• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <limits.h>
29 
30 #include "v8.h"
31 
32 #include "api.h"
33 #include "compilation-cache.h"
34 #include "execution.h"
35 #include "snapshot.h"
36 #include "platform.h"
37 #include "utils.h"
38 #include "cctest.h"
39 #include "parser.h"
40 #include "unicode-inl.h"
41 
42 static const bool kLogThreading = true;
43 
IsNaN(double x)44 static bool IsNaN(double x) {
45 #ifdef WIN32
46   return _isnan(x);
47 #else
48   return isnan(x);
49 #endif
50 }
51 
52 using ::v8::AccessorInfo;
53 using ::v8::Arguments;
54 using ::v8::Context;
55 using ::v8::Extension;
56 using ::v8::Function;
57 using ::v8::FunctionTemplate;
58 using ::v8::Handle;
59 using ::v8::HandleScope;
60 using ::v8::Local;
61 using ::v8::Message;
62 using ::v8::MessageCallback;
63 using ::v8::Object;
64 using ::v8::ObjectTemplate;
65 using ::v8::Persistent;
66 using ::v8::Script;
67 using ::v8::StackTrace;
68 using ::v8::String;
69 using ::v8::TryCatch;
70 using ::v8::Undefined;
71 using ::v8::V8;
72 using ::v8::Value;
73 
74 namespace i = ::i;
75 
76 
ExpectString(const char * code,const char * expected)77 static void ExpectString(const char* code, const char* expected) {
78   Local<Value> result = CompileRun(code);
79   CHECK(result->IsString());
80   String::AsciiValue ascii(result);
81   CHECK_EQ(expected, *ascii);
82 }
83 
84 
ExpectBoolean(const char * code,bool expected)85 static void ExpectBoolean(const char* code, bool expected) {
86   Local<Value> result = CompileRun(code);
87   CHECK(result->IsBoolean());
88   CHECK_EQ(expected, result->BooleanValue());
89 }
90 
91 
ExpectTrue(const char * code)92 static void ExpectTrue(const char* code) {
93   ExpectBoolean(code, true);
94 }
95 
96 
ExpectFalse(const char * code)97 static void ExpectFalse(const char* code) {
98   ExpectBoolean(code, false);
99 }
100 
101 
ExpectObject(const char * code,Local<Value> expected)102 static void ExpectObject(const char* code, Local<Value> expected) {
103   Local<Value> result = CompileRun(code);
104   CHECK(result->Equals(expected));
105 }
106 
107 
ExpectUndefined(const char * code)108 static void ExpectUndefined(const char* code) {
109   Local<Value> result = CompileRun(code);
110   CHECK(result->IsUndefined());
111 }
112 
113 
114 static int signature_callback_count;
IncrementingSignatureCallback(const v8::Arguments & args)115 static v8::Handle<Value> IncrementingSignatureCallback(
116     const v8::Arguments& args) {
117   ApiTestFuzzer::Fuzz();
118   signature_callback_count++;
119   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
120   for (int i = 0; i < args.Length(); i++)
121     result->Set(v8::Integer::New(i), args[i]);
122   return result;
123 }
124 
125 
SignatureCallback(const v8::Arguments & args)126 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
127   ApiTestFuzzer::Fuzz();
128   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
129   for (int i = 0; i < args.Length(); i++) {
130     result->Set(v8::Integer::New(i), args[i]);
131   }
132   return result;
133 }
134 
135 
THREADED_TEST(Handles)136 THREADED_TEST(Handles) {
137   v8::HandleScope scope;
138   Local<Context> local_env;
139   {
140     LocalContext env;
141     local_env = env.local();
142   }
143 
144   // Local context should still be live.
145   CHECK(!local_env.IsEmpty());
146   local_env->Enter();
147 
148   v8::Handle<v8::Primitive> undef = v8::Undefined();
149   CHECK(!undef.IsEmpty());
150   CHECK(undef->IsUndefined());
151 
152   const char* c_source = "1 + 2 + 3";
153   Local<String> source = String::New(c_source);
154   Local<Script> script = Script::Compile(source);
155   CHECK_EQ(6, script->Run()->Int32Value());
156 
157   local_env->Exit();
158 }
159 
160 
THREADED_TEST(ReceiverSignature)161 THREADED_TEST(ReceiverSignature) {
162   v8::HandleScope scope;
163   LocalContext env;
164   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
165   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
166   fun->PrototypeTemplate()->Set(
167       v8_str("m"),
168       v8::FunctionTemplate::New(IncrementingSignatureCallback,
169                                 v8::Handle<Value>(),
170                                 sig));
171   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
172   signature_callback_count = 0;
173   CompileRun(
174       "var o = new Fun();"
175       "o.m();");
176   CHECK_EQ(1, signature_callback_count);
177   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
178   sub_fun->Inherit(fun);
179   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
180   CompileRun(
181       "var o = new SubFun();"
182       "o.m();");
183   CHECK_EQ(2, signature_callback_count);
184 
185   v8::TryCatch try_catch;
186   CompileRun(
187       "var o = { };"
188       "o.m = Fun.prototype.m;"
189       "o.m();");
190   CHECK_EQ(2, signature_callback_count);
191   CHECK(try_catch.HasCaught());
192   try_catch.Reset();
193   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
194   sub_fun->Inherit(fun);
195   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
196   CompileRun(
197       "var o = new UnrelFun();"
198       "o.m = Fun.prototype.m;"
199       "o.m();");
200   CHECK_EQ(2, signature_callback_count);
201   CHECK(try_catch.HasCaught());
202 }
203 
204 
205 
206 
THREADED_TEST(ArgumentSignature)207 THREADED_TEST(ArgumentSignature) {
208   v8::HandleScope scope;
209   LocalContext env;
210   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
211   cons->SetClassName(v8_str("Cons"));
212   v8::Handle<v8::Signature> sig =
213       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
214   v8::Handle<v8::FunctionTemplate> fun =
215       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
216   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
217   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
218 
219   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
220   CHECK(value1->IsTrue());
221 
222   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
223   CHECK(value2->IsTrue());
224 
225   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
226   CHECK(value3->IsTrue());
227 
228   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
229   cons1->SetClassName(v8_str("Cons1"));
230   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
231   cons2->SetClassName(v8_str("Cons2"));
232   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
233   cons3->SetClassName(v8_str("Cons3"));
234 
235   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
236   v8::Handle<v8::Signature> wsig =
237       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
238   v8::Handle<v8::FunctionTemplate> fun2 =
239       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
240 
241   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
242   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
243   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
244   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
245   v8::Handle<Value> value4 = CompileRun(
246       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
247       "'[object Cons1],[object Cons2],[object Cons3]'");
248   CHECK(value4->IsTrue());
249 
250   v8::Handle<Value> value5 = CompileRun(
251       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
252   CHECK(value5->IsTrue());
253 
254   v8::Handle<Value> value6 = CompileRun(
255       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
256   CHECK(value6->IsTrue());
257 
258   v8::Handle<Value> value7 = CompileRun(
259       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
260       "'[object Cons1],[object Cons2],[object Cons3],d';");
261   CHECK(value7->IsTrue());
262 
263   v8::Handle<Value> value8 = CompileRun(
264       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
265   CHECK(value8->IsTrue());
266 }
267 
268 
THREADED_TEST(HulIgennem)269 THREADED_TEST(HulIgennem) {
270   v8::HandleScope scope;
271   LocalContext env;
272   v8::Handle<v8::Primitive> undef = v8::Undefined();
273   Local<String> undef_str = undef->ToString();
274   char* value = i::NewArray<char>(undef_str->Length() + 1);
275   undef_str->WriteAscii(value);
276   CHECK_EQ(0, strcmp(value, "undefined"));
277   i::DeleteArray(value);
278 }
279 
280 
THREADED_TEST(Access)281 THREADED_TEST(Access) {
282   v8::HandleScope scope;
283   LocalContext env;
284   Local<v8::Object> obj = v8::Object::New();
285   Local<Value> foo_before = obj->Get(v8_str("foo"));
286   CHECK(foo_before->IsUndefined());
287   Local<String> bar_str = v8_str("bar");
288   obj->Set(v8_str("foo"), bar_str);
289   Local<Value> foo_after = obj->Get(v8_str("foo"));
290   CHECK(!foo_after->IsUndefined());
291   CHECK(foo_after->IsString());
292   CHECK_EQ(bar_str, foo_after);
293 }
294 
295 
THREADED_TEST(AccessElement)296 THREADED_TEST(AccessElement) {
297   v8::HandleScope scope;
298   LocalContext env;
299   Local<v8::Object> obj = v8::Object::New();
300   Local<Value> before = obj->Get(1);
301   CHECK(before->IsUndefined());
302   Local<String> bar_str = v8_str("bar");
303   obj->Set(1, bar_str);
304   Local<Value> after = obj->Get(1);
305   CHECK(!after->IsUndefined());
306   CHECK(after->IsString());
307   CHECK_EQ(bar_str, after);
308 
309   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
310   CHECK_EQ(v8_str("a"), value->Get(0));
311   CHECK_EQ(v8_str("b"), value->Get(1));
312 }
313 
314 
THREADED_TEST(Script)315 THREADED_TEST(Script) {
316   v8::HandleScope scope;
317   LocalContext env;
318   const char* c_source = "1 + 2 + 3";
319   Local<String> source = String::New(c_source);
320   Local<Script> script = Script::Compile(source);
321   CHECK_EQ(6, script->Run()->Int32Value());
322 }
323 
324 
AsciiToTwoByteString(const char * source)325 static uint16_t* AsciiToTwoByteString(const char* source) {
326   int array_length = i::StrLength(source) + 1;
327   uint16_t* converted = i::NewArray<uint16_t>(array_length);
328   for (int i = 0; i < array_length; i++) converted[i] = source[i];
329   return converted;
330 }
331 
332 
333 class TestResource: public String::ExternalStringResource {
334  public:
335   static int dispose_count;
336 
TestResource(uint16_t * data)337   explicit TestResource(uint16_t* data)
338       : data_(data), length_(0) {
339     while (data[length_]) ++length_;
340   }
341 
~TestResource()342   ~TestResource() {
343     i::DeleteArray(data_);
344     ++dispose_count;
345   }
346 
data() const347   const uint16_t* data() const {
348     return data_;
349   }
350 
length() const351   size_t length() const {
352     return length_;
353   }
354  private:
355   uint16_t* data_;
356   size_t length_;
357 };
358 
359 
360 int TestResource::dispose_count = 0;
361 
362 
363 class TestAsciiResource: public String::ExternalAsciiStringResource {
364  public:
365   static int dispose_count;
366 
TestAsciiResource(const char * data)367   explicit TestAsciiResource(const char* data)
368       : data_(data),
369         length_(strlen(data)) { }
370 
~TestAsciiResource()371   ~TestAsciiResource() {
372     i::DeleteArray(data_);
373     ++dispose_count;
374   }
375 
data() const376   const char* data() const {
377     return data_;
378   }
379 
length() const380   size_t length() const {
381     return length_;
382   }
383  private:
384   const char* data_;
385   size_t length_;
386 };
387 
388 
389 int TestAsciiResource::dispose_count = 0;
390 
391 
THREADED_TEST(ScriptUsingStringResource)392 THREADED_TEST(ScriptUsingStringResource) {
393   TestResource::dispose_count = 0;
394   const char* c_source = "1 + 2 * 3";
395   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
396   {
397     v8::HandleScope scope;
398     LocalContext env;
399     TestResource* resource = new TestResource(two_byte_source);
400     Local<String> source = String::NewExternal(resource);
401     Local<Script> script = Script::Compile(source);
402     Local<Value> value = script->Run();
403     CHECK(value->IsNumber());
404     CHECK_EQ(7, value->Int32Value());
405     CHECK(source->IsExternal());
406     CHECK_EQ(resource,
407              static_cast<TestResource*>(source->GetExternalStringResource()));
408     HEAP->CollectAllGarbage(false);
409     CHECK_EQ(0, TestResource::dispose_count);
410   }
411   v8::internal::Isolate::Current()->compilation_cache()->Clear();
412   HEAP->CollectAllGarbage(false);
413   CHECK_EQ(1, TestResource::dispose_count);
414 }
415 
416 
THREADED_TEST(ScriptUsingAsciiStringResource)417 THREADED_TEST(ScriptUsingAsciiStringResource) {
418   TestAsciiResource::dispose_count = 0;
419   const char* c_source = "1 + 2 * 3";
420   {
421     v8::HandleScope scope;
422     LocalContext env;
423     Local<String> source =
424         String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
425     Local<Script> script = Script::Compile(source);
426     Local<Value> value = script->Run();
427     CHECK(value->IsNumber());
428     CHECK_EQ(7, value->Int32Value());
429     HEAP->CollectAllGarbage(false);
430     CHECK_EQ(0, TestAsciiResource::dispose_count);
431   }
432   i::Isolate::Current()->compilation_cache()->Clear();
433   HEAP->CollectAllGarbage(false);
434   CHECK_EQ(1, TestAsciiResource::dispose_count);
435 }
436 
437 
THREADED_TEST(ScriptMakingExternalString)438 THREADED_TEST(ScriptMakingExternalString) {
439   TestResource::dispose_count = 0;
440   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
441   {
442     v8::HandleScope scope;
443     LocalContext env;
444     Local<String> source = String::New(two_byte_source);
445     // Trigger GCs so that the newly allocated string moves to old gen.
446     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
447     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
448     bool success = source->MakeExternal(new TestResource(two_byte_source));
449     CHECK(success);
450     Local<Script> script = Script::Compile(source);
451     Local<Value> value = script->Run();
452     CHECK(value->IsNumber());
453     CHECK_EQ(7, value->Int32Value());
454     HEAP->CollectAllGarbage(false);
455     CHECK_EQ(0, TestResource::dispose_count);
456   }
457   i::Isolate::Current()->compilation_cache()->Clear();
458   HEAP->CollectAllGarbage(false);
459   CHECK_EQ(1, TestResource::dispose_count);
460 }
461 
462 
THREADED_TEST(ScriptMakingExternalAsciiString)463 THREADED_TEST(ScriptMakingExternalAsciiString) {
464   TestAsciiResource::dispose_count = 0;
465   const char* c_source = "1 + 2 * 3";
466   {
467     v8::HandleScope scope;
468     LocalContext env;
469     Local<String> source = v8_str(c_source);
470     // Trigger GCs so that the newly allocated string moves to old gen.
471     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
472     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
473     bool success = source->MakeExternal(
474         new TestAsciiResource(i::StrDup(c_source)));
475     CHECK(success);
476     Local<Script> script = Script::Compile(source);
477     Local<Value> value = script->Run();
478     CHECK(value->IsNumber());
479     CHECK_EQ(7, value->Int32Value());
480     HEAP->CollectAllGarbage(false);
481     CHECK_EQ(0, TestAsciiResource::dispose_count);
482   }
483   i::Isolate::Current()->compilation_cache()->Clear();
484   HEAP->CollectAllGarbage(false);
485   CHECK_EQ(1, TestAsciiResource::dispose_count);
486 }
487 
488 
TEST(MakingExternalStringConditions)489 TEST(MakingExternalStringConditions) {
490   v8::HandleScope scope;
491   LocalContext env;
492 
493   // Free some space in the new space so that we can check freshness.
494   HEAP->CollectGarbage(i::NEW_SPACE);
495   HEAP->CollectGarbage(i::NEW_SPACE);
496 
497   uint16_t* two_byte_string = AsciiToTwoByteString("small");
498   Local<String> small_string = String::New(two_byte_string);
499   i::DeleteArray(two_byte_string);
500 
501   // We should refuse to externalize newly created small string.
502   CHECK(!small_string->CanMakeExternal());
503   // Trigger GCs so that the newly allocated string moves to old gen.
504   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
505   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
506   // Old space strings should be accepted.
507   CHECK(small_string->CanMakeExternal());
508 
509   two_byte_string = AsciiToTwoByteString("small 2");
510   small_string = String::New(two_byte_string);
511   i::DeleteArray(two_byte_string);
512 
513   // We should refuse externalizing newly created small string.
514   CHECK(!small_string->CanMakeExternal());
515   for (int i = 0; i < 100; i++) {
516     String::Value value(small_string);
517   }
518   // Frequently used strings should be accepted.
519   CHECK(small_string->CanMakeExternal());
520 
521   const int buf_size = 10 * 1024;
522   char* buf = i::NewArray<char>(buf_size);
523   memset(buf, 'a', buf_size);
524   buf[buf_size - 1] = '\0';
525 
526   two_byte_string = AsciiToTwoByteString(buf);
527   Local<String> large_string = String::New(two_byte_string);
528   i::DeleteArray(buf);
529   i::DeleteArray(two_byte_string);
530   // Large strings should be immediately accepted.
531   CHECK(large_string->CanMakeExternal());
532 }
533 
534 
TEST(MakingExternalAsciiStringConditions)535 TEST(MakingExternalAsciiStringConditions) {
536   v8::HandleScope scope;
537   LocalContext env;
538 
539   // Free some space in the new space so that we can check freshness.
540   HEAP->CollectGarbage(i::NEW_SPACE);
541   HEAP->CollectGarbage(i::NEW_SPACE);
542 
543   Local<String> small_string = String::New("small");
544   // We should refuse to externalize newly created small string.
545   CHECK(!small_string->CanMakeExternal());
546   // Trigger GCs so that the newly allocated string moves to old gen.
547   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
548   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
549   // Old space strings should be accepted.
550   CHECK(small_string->CanMakeExternal());
551 
552   small_string = String::New("small 2");
553   // We should refuse externalizing newly created small string.
554   CHECK(!small_string->CanMakeExternal());
555   for (int i = 0; i < 100; i++) {
556     String::Value value(small_string);
557   }
558   // Frequently used strings should be accepted.
559   CHECK(small_string->CanMakeExternal());
560 
561   const int buf_size = 10 * 1024;
562   char* buf = i::NewArray<char>(buf_size);
563   memset(buf, 'a', buf_size);
564   buf[buf_size - 1] = '\0';
565   Local<String> large_string = String::New(buf);
566   i::DeleteArray(buf);
567   // Large strings should be immediately accepted.
568   CHECK(large_string->CanMakeExternal());
569 }
570 
571 
THREADED_TEST(UsingExternalString)572 THREADED_TEST(UsingExternalString) {
573   {
574     v8::HandleScope scope;
575     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
576     Local<String> string =
577         String::NewExternal(new TestResource(two_byte_string));
578     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
579     // Trigger GCs so that the newly allocated string moves to old gen.
580     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
581     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
582     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
583     CHECK(isymbol->IsSymbol());
584   }
585   HEAP->CollectAllGarbage(false);
586   HEAP->CollectAllGarbage(false);
587 }
588 
589 
THREADED_TEST(UsingExternalAsciiString)590 THREADED_TEST(UsingExternalAsciiString) {
591   {
592     v8::HandleScope scope;
593     const char* one_byte_string = "test string";
594     Local<String> string = String::NewExternal(
595         new TestAsciiResource(i::StrDup(one_byte_string)));
596     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
597     // Trigger GCs so that the newly allocated string moves to old gen.
598     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
599     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
600     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
601     CHECK(isymbol->IsSymbol());
602   }
603   HEAP->CollectAllGarbage(false);
604   HEAP->CollectAllGarbage(false);
605 }
606 
607 
THREADED_TEST(ScavengeExternalString)608 THREADED_TEST(ScavengeExternalString) {
609   TestResource::dispose_count = 0;
610   bool in_new_space = false;
611   {
612     v8::HandleScope scope;
613     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
614     Local<String> string =
615         String::NewExternal(new TestResource(two_byte_string));
616     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
617     HEAP->CollectGarbage(i::NEW_SPACE);
618     in_new_space = HEAP->InNewSpace(*istring);
619     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
620     CHECK_EQ(0, TestResource::dispose_count);
621   }
622   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
623   CHECK_EQ(1, TestResource::dispose_count);
624 }
625 
626 
THREADED_TEST(ScavengeExternalAsciiString)627 THREADED_TEST(ScavengeExternalAsciiString) {
628   TestAsciiResource::dispose_count = 0;
629   bool in_new_space = false;
630   {
631     v8::HandleScope scope;
632     const char* one_byte_string = "test string";
633     Local<String> string = String::NewExternal(
634         new TestAsciiResource(i::StrDup(one_byte_string)));
635     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
636     HEAP->CollectGarbage(i::NEW_SPACE);
637     in_new_space = HEAP->InNewSpace(*istring);
638     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
639     CHECK_EQ(0, TestAsciiResource::dispose_count);
640   }
641   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
642   CHECK_EQ(1, TestAsciiResource::dispose_count);
643 }
644 
645 
646 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
647  public:
648   static int dispose_calls;
649 
TestAsciiResourceWithDisposeControl(const char * data,bool dispose)650   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651       : TestAsciiResource(data),
652         dispose_(dispose) { }
653 
Dispose()654   void Dispose() {
655     ++dispose_calls;
656     if (dispose_) delete this;
657   }
658  private:
659   bool dispose_;
660 };
661 
662 
663 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
664 
665 
TEST(ExternalStringWithDisposeHandling)666 TEST(ExternalStringWithDisposeHandling) {
667   const char* c_source = "1 + 2 * 3";
668 
669   // Use a stack allocated external string resource allocated object.
670   TestAsciiResource::dispose_count = 0;
671   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
672   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
673   {
674     v8::HandleScope scope;
675     LocalContext env;
676     Local<String> source =  String::NewExternal(&res_stack);
677     Local<Script> script = Script::Compile(source);
678     Local<Value> value = script->Run();
679     CHECK(value->IsNumber());
680     CHECK_EQ(7, value->Int32Value());
681     HEAP->CollectAllGarbage(false);
682     CHECK_EQ(0, TestAsciiResource::dispose_count);
683   }
684   i::Isolate::Current()->compilation_cache()->Clear();
685   HEAP->CollectAllGarbage(false);
686   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
687   CHECK_EQ(0, TestAsciiResource::dispose_count);
688 
689   // Use a heap allocated external string resource allocated object.
690   TestAsciiResource::dispose_count = 0;
691   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
692   TestAsciiResource* res_heap =
693       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
694   {
695     v8::HandleScope scope;
696     LocalContext env;
697     Local<String> source =  String::NewExternal(res_heap);
698     Local<Script> script = Script::Compile(source);
699     Local<Value> value = script->Run();
700     CHECK(value->IsNumber());
701     CHECK_EQ(7, value->Int32Value());
702     HEAP->CollectAllGarbage(false);
703     CHECK_EQ(0, TestAsciiResource::dispose_count);
704   }
705   i::Isolate::Current()->compilation_cache()->Clear();
706   HEAP->CollectAllGarbage(false);
707   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
708   CHECK_EQ(1, TestAsciiResource::dispose_count);
709 }
710 
711 
THREADED_TEST(StringConcat)712 THREADED_TEST(StringConcat) {
713   {
714     v8::HandleScope scope;
715     LocalContext env;
716     const char* one_byte_string_1 = "function a_times_t";
717     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
718     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
719     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
720     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
723     Local<String> left = v8_str(one_byte_string_1);
724 
725     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
726     Local<String> right = String::New(two_byte_source);
727     i::DeleteArray(two_byte_source);
728 
729     Local<String> source = String::Concat(left, right);
730     right = String::NewExternal(
731         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
732     source = String::Concat(source, right);
733     right = String::NewExternal(
734         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
735     source = String::Concat(source, right);
736     right = v8_str(one_byte_string_2);
737     source = String::Concat(source, right);
738 
739     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
740     right = String::New(two_byte_source);
741     i::DeleteArray(two_byte_source);
742 
743     source = String::Concat(source, right);
744     right = String::NewExternal(
745         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
746     source = String::Concat(source, right);
747     Local<Script> script = Script::Compile(source);
748     Local<Value> value = script->Run();
749     CHECK(value->IsNumber());
750     CHECK_EQ(68, value->Int32Value());
751   }
752   i::Isolate::Current()->compilation_cache()->Clear();
753   HEAP->CollectAllGarbage(false);
754   HEAP->CollectAllGarbage(false);
755 }
756 
757 
THREADED_TEST(GlobalProperties)758 THREADED_TEST(GlobalProperties) {
759   v8::HandleScope scope;
760   LocalContext env;
761   v8::Handle<v8::Object> global = env->Global();
762   global->Set(v8_str("pi"), v8_num(3.1415926));
763   Local<Value> pi = global->Get(v8_str("pi"));
764   CHECK_EQ(3.1415926, pi->NumberValue());
765 }
766 
767 
handle_call(const v8::Arguments & args)768 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
769   ApiTestFuzzer::Fuzz();
770   return v8_num(102);
771 }
772 
773 
construct_call(const v8::Arguments & args)774 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
775   ApiTestFuzzer::Fuzz();
776   args.This()->Set(v8_str("x"), v8_num(1));
777   args.This()->Set(v8_str("y"), v8_num(2));
778   return args.This();
779 }
780 
Return239(Local<String> name,const AccessorInfo &)781 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
782   ApiTestFuzzer::Fuzz();
783   return v8_num(239);
784 }
785 
786 
THREADED_TEST(FunctionTemplate)787 THREADED_TEST(FunctionTemplate) {
788   v8::HandleScope scope;
789   LocalContext env;
790   {
791     Local<v8::FunctionTemplate> fun_templ =
792         v8::FunctionTemplate::New(handle_call);
793     Local<Function> fun = fun_templ->GetFunction();
794     env->Global()->Set(v8_str("obj"), fun);
795     Local<Script> script = v8_compile("obj()");
796     CHECK_EQ(102, script->Run()->Int32Value());
797   }
798   // Use SetCallHandler to initialize a function template, should work like the
799   // previous one.
800   {
801     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
802     fun_templ->SetCallHandler(handle_call);
803     Local<Function> fun = fun_templ->GetFunction();
804     env->Global()->Set(v8_str("obj"), fun);
805     Local<Script> script = v8_compile("obj()");
806     CHECK_EQ(102, script->Run()->Int32Value());
807   }
808   // Test constructor calls.
809   {
810     Local<v8::FunctionTemplate> fun_templ =
811         v8::FunctionTemplate::New(construct_call);
812     fun_templ->SetClassName(v8_str("funky"));
813     fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
814     Local<Function> fun = fun_templ->GetFunction();
815     env->Global()->Set(v8_str("obj"), fun);
816     Local<Script> script = v8_compile("var s = new obj(); s.x");
817     CHECK_EQ(1, script->Run()->Int32Value());
818 
819     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
820     CHECK_EQ(v8_str("[object funky]"), result);
821 
822     result = v8_compile("(new obj()).m")->Run();
823     CHECK_EQ(239, result->Int32Value());
824   }
825 }
826 
827 
828 static void* expected_ptr;
callback(const v8::Arguments & args)829 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
830   void* ptr = v8::External::Unwrap(args.Data());
831   CHECK_EQ(expected_ptr, ptr);
832   return v8::Boolean::New(true);
833 }
834 
835 
TestExternalPointerWrapping()836 static void TestExternalPointerWrapping() {
837   v8::HandleScope scope;
838   LocalContext env;
839 
840   v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
841 
842   v8::Handle<v8::Object> obj = v8::Object::New();
843   obj->Set(v8_str("func"),
844            v8::FunctionTemplate::New(callback, data)->GetFunction());
845   env->Global()->Set(v8_str("obj"), obj);
846 
847   CHECK(CompileRun(
848         "function foo() {\n"
849         "  for (var i = 0; i < 13; i++) obj.func();\n"
850         "}\n"
851         "foo(), true")->BooleanValue());
852 }
853 
854 
THREADED_TEST(ExternalWrap)855 THREADED_TEST(ExternalWrap) {
856   // Check heap allocated object.
857   int* ptr = new int;
858   expected_ptr = ptr;
859   TestExternalPointerWrapping();
860   delete ptr;
861 
862   // Check stack allocated object.
863   int foo;
864   expected_ptr = &foo;
865   TestExternalPointerWrapping();
866 
867   // Check not aligned addresses.
868   const int n = 100;
869   char* s = new char[n];
870   for (int i = 0; i < n; i++) {
871     expected_ptr = s + i;
872     TestExternalPointerWrapping();
873   }
874 
875   delete[] s;
876 
877   // Check several invalid addresses.
878   expected_ptr = reinterpret_cast<void*>(1);
879   TestExternalPointerWrapping();
880 
881   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
882   TestExternalPointerWrapping();
883 
884   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
885   TestExternalPointerWrapping();
886 
887 #if defined(V8_HOST_ARCH_X64)
888   // Check a value with a leading 1 bit in x64 Smi encoding.
889   expected_ptr = reinterpret_cast<void*>(0x400000000);
890   TestExternalPointerWrapping();
891 
892   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
893   TestExternalPointerWrapping();
894 
895   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
896   TestExternalPointerWrapping();
897 #endif
898 }
899 
900 
THREADED_TEST(FindInstanceInPrototypeChain)901 THREADED_TEST(FindInstanceInPrototypeChain) {
902   v8::HandleScope scope;
903   LocalContext env;
904 
905   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
906   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
907   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
908   derived->Inherit(base);
909 
910   Local<v8::Function> base_function = base->GetFunction();
911   Local<v8::Function> derived_function = derived->GetFunction();
912   Local<v8::Function> other_function = other->GetFunction();
913 
914   Local<v8::Object> base_instance = base_function->NewInstance();
915   Local<v8::Object> derived_instance = derived_function->NewInstance();
916   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
917   Local<v8::Object> other_instance = other_function->NewInstance();
918   derived_instance2->Set(v8_str("__proto__"), derived_instance);
919   other_instance->Set(v8_str("__proto__"), derived_instance2);
920 
921   // base_instance is only an instance of base.
922   CHECK_EQ(base_instance,
923            base_instance->FindInstanceInPrototypeChain(base));
924   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
925   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
926 
927   // derived_instance is an instance of base and derived.
928   CHECK_EQ(derived_instance,
929            derived_instance->FindInstanceInPrototypeChain(base));
930   CHECK_EQ(derived_instance,
931            derived_instance->FindInstanceInPrototypeChain(derived));
932   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
933 
934   // other_instance is an instance of other and its immediate
935   // prototype derived_instance2 is an instance of base and derived.
936   // Note, derived_instance is an instance of base and derived too,
937   // but it comes after derived_instance2 in the prototype chain of
938   // other_instance.
939   CHECK_EQ(derived_instance2,
940            other_instance->FindInstanceInPrototypeChain(base));
941   CHECK_EQ(derived_instance2,
942            other_instance->FindInstanceInPrototypeChain(derived));
943   CHECK_EQ(other_instance,
944            other_instance->FindInstanceInPrototypeChain(other));
945 }
946 
947 
THREADED_TEST(TinyInteger)948 THREADED_TEST(TinyInteger) {
949   v8::HandleScope scope;
950   LocalContext env;
951   int32_t value = 239;
952   Local<v8::Integer> value_obj = v8::Integer::New(value);
953   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
954 }
955 
956 
THREADED_TEST(BigSmiInteger)957 THREADED_TEST(BigSmiInteger) {
958   v8::HandleScope scope;
959   LocalContext env;
960   int32_t value = i::Smi::kMaxValue;
961   // We cannot add one to a Smi::kMaxValue without wrapping.
962   if (i::kSmiValueSize < 32) {
963     CHECK(i::Smi::IsValid(value));
964     CHECK(!i::Smi::IsValid(value + 1));
965     Local<v8::Integer> value_obj = v8::Integer::New(value);
966     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
967   }
968 }
969 
970 
THREADED_TEST(BigInteger)971 THREADED_TEST(BigInteger) {
972   v8::HandleScope scope;
973   LocalContext env;
974   // We cannot add one to a Smi::kMaxValue without wrapping.
975   if (i::kSmiValueSize < 32) {
976     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
977     // The code will not be run in that case, due to the "if" guard.
978     int32_t value =
979         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
980     CHECK(value > i::Smi::kMaxValue);
981     CHECK(!i::Smi::IsValid(value));
982     Local<v8::Integer> value_obj = v8::Integer::New(value);
983     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
984   }
985 }
986 
987 
THREADED_TEST(TinyUnsignedInteger)988 THREADED_TEST(TinyUnsignedInteger) {
989   v8::HandleScope scope;
990   LocalContext env;
991   uint32_t value = 239;
992   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
993   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
994 }
995 
996 
THREADED_TEST(BigUnsignedSmiInteger)997 THREADED_TEST(BigUnsignedSmiInteger) {
998   v8::HandleScope scope;
999   LocalContext env;
1000   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1001   CHECK(i::Smi::IsValid(value));
1002   CHECK(!i::Smi::IsValid(value + 1));
1003   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1004   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1005 }
1006 
1007 
THREADED_TEST(BigUnsignedInteger)1008 THREADED_TEST(BigUnsignedInteger) {
1009   v8::HandleScope scope;
1010   LocalContext env;
1011   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1012   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1013   CHECK(!i::Smi::IsValid(value));
1014   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1015   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1016 }
1017 
1018 
THREADED_TEST(OutOfSignedRangeUnsignedInteger)1019 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1020   v8::HandleScope scope;
1021   LocalContext env;
1022   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1023   uint32_t value = INT32_MAX_AS_UINT + 1;
1024   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1025   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1026   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1027 }
1028 
1029 
THREADED_TEST(Number)1030 THREADED_TEST(Number) {
1031   v8::HandleScope scope;
1032   LocalContext env;
1033   double PI = 3.1415926;
1034   Local<v8::Number> pi_obj = v8::Number::New(PI);
1035   CHECK_EQ(PI, pi_obj->NumberValue());
1036 }
1037 
1038 
THREADED_TEST(ToNumber)1039 THREADED_TEST(ToNumber) {
1040   v8::HandleScope scope;
1041   LocalContext env;
1042   Local<String> str = v8_str("3.1415926");
1043   CHECK_EQ(3.1415926, str->NumberValue());
1044   v8::Handle<v8::Boolean> t = v8::True();
1045   CHECK_EQ(1.0, t->NumberValue());
1046   v8::Handle<v8::Boolean> f = v8::False();
1047   CHECK_EQ(0.0, f->NumberValue());
1048 }
1049 
1050 
THREADED_TEST(Date)1051 THREADED_TEST(Date) {
1052   v8::HandleScope scope;
1053   LocalContext env;
1054   double PI = 3.1415926;
1055   Local<Value> date_obj = v8::Date::New(PI);
1056   CHECK_EQ(3.0, date_obj->NumberValue());
1057 }
1058 
1059 
THREADED_TEST(Boolean)1060 THREADED_TEST(Boolean) {
1061   v8::HandleScope scope;
1062   LocalContext env;
1063   v8::Handle<v8::Boolean> t = v8::True();
1064   CHECK(t->Value());
1065   v8::Handle<v8::Boolean> f = v8::False();
1066   CHECK(!f->Value());
1067   v8::Handle<v8::Primitive> u = v8::Undefined();
1068   CHECK(!u->BooleanValue());
1069   v8::Handle<v8::Primitive> n = v8::Null();
1070   CHECK(!n->BooleanValue());
1071   v8::Handle<String> str1 = v8_str("");
1072   CHECK(!str1->BooleanValue());
1073   v8::Handle<String> str2 = v8_str("x");
1074   CHECK(str2->BooleanValue());
1075   CHECK(!v8::Number::New(0)->BooleanValue());
1076   CHECK(v8::Number::New(-1)->BooleanValue());
1077   CHECK(v8::Number::New(1)->BooleanValue());
1078   CHECK(v8::Number::New(42)->BooleanValue());
1079   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1080 }
1081 
1082 
DummyCallHandler(const v8::Arguments & args)1083 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1084   ApiTestFuzzer::Fuzz();
1085   return v8_num(13.4);
1086 }
1087 
1088 
GetM(Local<String> name,const AccessorInfo &)1089 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1090   ApiTestFuzzer::Fuzz();
1091   return v8_num(876);
1092 }
1093 
1094 
THREADED_TEST(GlobalPrototype)1095 THREADED_TEST(GlobalPrototype) {
1096   v8::HandleScope scope;
1097   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1098   func_templ->PrototypeTemplate()->Set(
1099       "dummy",
1100       v8::FunctionTemplate::New(DummyCallHandler));
1101   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1102   templ->Set("x", v8_num(200));
1103   templ->SetAccessor(v8_str("m"), GetM);
1104   LocalContext env(0, templ);
1105   v8::Handle<v8::Object> obj = env->Global();
1106   v8::Handle<Script> script = v8_compile("dummy()");
1107   v8::Handle<Value> result = script->Run();
1108   CHECK_EQ(13.4, result->NumberValue());
1109   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1110   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1111 }
1112 
1113 
THREADED_TEST(ObjectTemplate)1114 THREADED_TEST(ObjectTemplate) {
1115   v8::HandleScope scope;
1116   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1117   templ1->Set("x", v8_num(10));
1118   templ1->Set("y", v8_num(13));
1119   LocalContext env;
1120   Local<v8::Object> instance1 = templ1->NewInstance();
1121   env->Global()->Set(v8_str("p"), instance1);
1122   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1123   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1124   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1125   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1126   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1127   templ2->Set("a", v8_num(12));
1128   templ2->Set("b", templ1);
1129   Local<v8::Object> instance2 = templ2->NewInstance();
1130   env->Global()->Set(v8_str("q"), instance2);
1131   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1132   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1133   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1134   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1135 }
1136 
1137 
GetFlabby(const v8::Arguments & args)1138 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1139   ApiTestFuzzer::Fuzz();
1140   return v8_num(17.2);
1141 }
1142 
1143 
GetKnurd(Local<String> property,const AccessorInfo &)1144 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1145   ApiTestFuzzer::Fuzz();
1146   return v8_num(15.2);
1147 }
1148 
1149 
THREADED_TEST(DescriptorInheritance)1150 THREADED_TEST(DescriptorInheritance) {
1151   v8::HandleScope scope;
1152   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1153   super->PrototypeTemplate()->Set("flabby",
1154                                   v8::FunctionTemplate::New(GetFlabby));
1155   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1156 
1157   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1158 
1159   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1160   base1->Inherit(super);
1161   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1162 
1163   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1164   base2->Inherit(super);
1165   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1166 
1167   LocalContext env;
1168 
1169   env->Global()->Set(v8_str("s"), super->GetFunction());
1170   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1171   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1172 
1173   // Checks right __proto__ chain.
1174   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1175   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1176 
1177   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1178 
1179   // Instance accessor should not be visible on function object or its prototype
1180   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1181   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1182   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1183 
1184   env->Global()->Set(v8_str("obj"),
1185                      base1->GetFunction()->NewInstance());
1186   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1187   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1188   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1189   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1190   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1191 
1192   env->Global()->Set(v8_str("obj2"),
1193                      base2->GetFunction()->NewInstance());
1194   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1195   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1196   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1197   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1198   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1199 
1200   // base1 and base2 cannot cross reference to each's prototype
1201   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1202   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1203 }
1204 
1205 
1206 int echo_named_call_count;
1207 
1208 
EchoNamedProperty(Local<String> name,const AccessorInfo & info)1209 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1210                                            const AccessorInfo& info) {
1211   ApiTestFuzzer::Fuzz();
1212   CHECK_EQ(v8_str("data"), info.Data());
1213   echo_named_call_count++;
1214   return name;
1215 }
1216 
1217 
THREADED_TEST(NamedPropertyHandlerGetter)1218 THREADED_TEST(NamedPropertyHandlerGetter) {
1219   echo_named_call_count = 0;
1220   v8::HandleScope scope;
1221   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1222   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1223                                                      0, 0, 0, 0,
1224                                                      v8_str("data"));
1225   LocalContext env;
1226   env->Global()->Set(v8_str("obj"),
1227                      templ->GetFunction()->NewInstance());
1228   CHECK_EQ(echo_named_call_count, 0);
1229   v8_compile("obj.x")->Run();
1230   CHECK_EQ(echo_named_call_count, 1);
1231   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1232   v8::Handle<Value> str = CompileRun(code);
1233   String::AsciiValue value(str);
1234   CHECK_EQ(*value, "oddlepoddle");
1235   // Check default behavior
1236   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1237   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1238   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1239 }
1240 
1241 
1242 int echo_indexed_call_count = 0;
1243 
1244 
EchoIndexedProperty(uint32_t index,const AccessorInfo & info)1245 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1246                                              const AccessorInfo& info) {
1247   ApiTestFuzzer::Fuzz();
1248   CHECK_EQ(v8_num(637), info.Data());
1249   echo_indexed_call_count++;
1250   return v8_num(index);
1251 }
1252 
1253 
THREADED_TEST(IndexedPropertyHandlerGetter)1254 THREADED_TEST(IndexedPropertyHandlerGetter) {
1255   v8::HandleScope scope;
1256   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1257   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1258                                                        0, 0, 0, 0,
1259                                                        v8_num(637));
1260   LocalContext env;
1261   env->Global()->Set(v8_str("obj"),
1262                      templ->GetFunction()->NewInstance());
1263   Local<Script> script = v8_compile("obj[900]");
1264   CHECK_EQ(script->Run()->Int32Value(), 900);
1265 }
1266 
1267 
1268 v8::Handle<v8::Object> bottom;
1269 
CheckThisIndexedPropertyHandler(uint32_t index,const AccessorInfo & info)1270 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1271     uint32_t index,
1272     const AccessorInfo& info) {
1273   ApiTestFuzzer::Fuzz();
1274   CHECK(info.This()->Equals(bottom));
1275   return v8::Handle<Value>();
1276 }
1277 
CheckThisNamedPropertyHandler(Local<String> name,const AccessorInfo & info)1278 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1279     Local<String> name,
1280     const AccessorInfo& info) {
1281   ApiTestFuzzer::Fuzz();
1282   CHECK(info.This()->Equals(bottom));
1283   return v8::Handle<Value>();
1284 }
1285 
1286 
CheckThisIndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)1287 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1288                                                  Local<Value> value,
1289                                                  const AccessorInfo& info) {
1290   ApiTestFuzzer::Fuzz();
1291   CHECK(info.This()->Equals(bottom));
1292   return v8::Handle<Value>();
1293 }
1294 
1295 
CheckThisNamedPropertySetter(Local<String> property,Local<Value> value,const AccessorInfo & info)1296 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1297                                                Local<Value> value,
1298                                                const AccessorInfo& info) {
1299   ApiTestFuzzer::Fuzz();
1300   CHECK(info.This()->Equals(bottom));
1301   return v8::Handle<Value>();
1302 }
1303 
CheckThisIndexedPropertyQuery(uint32_t index,const AccessorInfo & info)1304 v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1305     uint32_t index,
1306     const AccessorInfo& info) {
1307   ApiTestFuzzer::Fuzz();
1308   CHECK(info.This()->Equals(bottom));
1309   return v8::Handle<v8::Integer>();
1310 }
1311 
1312 
CheckThisNamedPropertyQuery(Local<String> property,const AccessorInfo & info)1313 v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1314                                                     const AccessorInfo& info) {
1315   ApiTestFuzzer::Fuzz();
1316   CHECK(info.This()->Equals(bottom));
1317   return v8::Handle<v8::Integer>();
1318 }
1319 
1320 
CheckThisIndexedPropertyDeleter(uint32_t index,const AccessorInfo & info)1321 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1322     uint32_t index,
1323     const AccessorInfo& info) {
1324   ApiTestFuzzer::Fuzz();
1325   CHECK(info.This()->Equals(bottom));
1326   return v8::Handle<v8::Boolean>();
1327 }
1328 
1329 
CheckThisNamedPropertyDeleter(Local<String> property,const AccessorInfo & info)1330 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1331     Local<String> property,
1332     const AccessorInfo& info) {
1333   ApiTestFuzzer::Fuzz();
1334   CHECK(info.This()->Equals(bottom));
1335   return v8::Handle<v8::Boolean>();
1336 }
1337 
1338 
CheckThisIndexedPropertyEnumerator(const AccessorInfo & info)1339 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1340     const AccessorInfo& info) {
1341   ApiTestFuzzer::Fuzz();
1342   CHECK(info.This()->Equals(bottom));
1343   return v8::Handle<v8::Array>();
1344 }
1345 
1346 
CheckThisNamedPropertyEnumerator(const AccessorInfo & info)1347 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1348     const AccessorInfo& info) {
1349   ApiTestFuzzer::Fuzz();
1350   CHECK(info.This()->Equals(bottom));
1351   return v8::Handle<v8::Array>();
1352 }
1353 
1354 
THREADED_TEST(PropertyHandlerInPrototype)1355 THREADED_TEST(PropertyHandlerInPrototype) {
1356   v8::HandleScope scope;
1357   LocalContext env;
1358 
1359   // Set up a prototype chain with three interceptors.
1360   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1361   templ->InstanceTemplate()->SetIndexedPropertyHandler(
1362       CheckThisIndexedPropertyHandler,
1363       CheckThisIndexedPropertySetter,
1364       CheckThisIndexedPropertyQuery,
1365       CheckThisIndexedPropertyDeleter,
1366       CheckThisIndexedPropertyEnumerator);
1367 
1368   templ->InstanceTemplate()->SetNamedPropertyHandler(
1369       CheckThisNamedPropertyHandler,
1370       CheckThisNamedPropertySetter,
1371       CheckThisNamedPropertyQuery,
1372       CheckThisNamedPropertyDeleter,
1373       CheckThisNamedPropertyEnumerator);
1374 
1375   bottom = templ->GetFunction()->NewInstance();
1376   Local<v8::Object> top = templ->GetFunction()->NewInstance();
1377   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1378 
1379   bottom->Set(v8_str("__proto__"), middle);
1380   middle->Set(v8_str("__proto__"), top);
1381   env->Global()->Set(v8_str("obj"), bottom);
1382 
1383   // Indexed and named get.
1384   Script::Compile(v8_str("obj[0]"))->Run();
1385   Script::Compile(v8_str("obj.x"))->Run();
1386 
1387   // Indexed and named set.
1388   Script::Compile(v8_str("obj[1] = 42"))->Run();
1389   Script::Compile(v8_str("obj.y = 42"))->Run();
1390 
1391   // Indexed and named query.
1392   Script::Compile(v8_str("0 in obj"))->Run();
1393   Script::Compile(v8_str("'x' in obj"))->Run();
1394 
1395   // Indexed and named deleter.
1396   Script::Compile(v8_str("delete obj[0]"))->Run();
1397   Script::Compile(v8_str("delete obj.x"))->Run();
1398 
1399   // Enumerators.
1400   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1401 }
1402 
1403 
PrePropertyHandlerGet(Local<String> key,const AccessorInfo & info)1404 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1405                                                const AccessorInfo& info) {
1406   ApiTestFuzzer::Fuzz();
1407   if (v8_str("pre")->Equals(key)) {
1408     return v8_str("PrePropertyHandler: pre");
1409   }
1410   return v8::Handle<String>();
1411 }
1412 
1413 
PrePropertyHandlerQuery(Local<String> key,const AccessorInfo &)1414 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1415                                                        const AccessorInfo&) {
1416   if (v8_str("pre")->Equals(key)) {
1417     return v8::Integer::New(v8::None);
1418   }
1419 
1420   return v8::Handle<v8::Integer>();  // do not intercept the call
1421 }
1422 
1423 
THREADED_TEST(PrePropertyHandler)1424 THREADED_TEST(PrePropertyHandler) {
1425   v8::HandleScope scope;
1426   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1427   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1428                                                     0,
1429                                                     PrePropertyHandlerQuery);
1430   LocalContext env(NULL, desc->InstanceTemplate());
1431   Script::Compile(v8_str(
1432       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1433   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1434   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1435   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1436   CHECK_EQ(v8_str("Object: on"), result_on);
1437   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1438   CHECK(result_post.IsEmpty());
1439 }
1440 
1441 
THREADED_TEST(UndefinedIsNotEnumerable)1442 THREADED_TEST(UndefinedIsNotEnumerable) {
1443   v8::HandleScope scope;
1444   LocalContext env;
1445   v8::Handle<Value> result = Script::Compile(v8_str(
1446       "this.propertyIsEnumerable(undefined)"))->Run();
1447   CHECK(result->IsFalse());
1448 }
1449 
1450 
1451 v8::Handle<Script> call_recursively_script;
1452 static const int kTargetRecursionDepth = 200;  // near maximum
1453 
1454 
CallScriptRecursivelyCall(const v8::Arguments & args)1455 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1456   ApiTestFuzzer::Fuzz();
1457   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1458   if (depth == kTargetRecursionDepth) return v8::Undefined();
1459   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1460   return call_recursively_script->Run();
1461 }
1462 
1463 
CallFunctionRecursivelyCall(const v8::Arguments & args)1464 static v8::Handle<Value> CallFunctionRecursivelyCall(
1465     const v8::Arguments& args) {
1466   ApiTestFuzzer::Fuzz();
1467   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1468   if (depth == kTargetRecursionDepth) {
1469     printf("[depth = %d]\n", depth);
1470     return v8::Undefined();
1471   }
1472   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1473   v8::Handle<Value> function =
1474       args.This()->Get(v8_str("callFunctionRecursively"));
1475   return function.As<Function>()->Call(args.This(), 0, NULL);
1476 }
1477 
1478 
THREADED_TEST(DeepCrossLanguageRecursion)1479 THREADED_TEST(DeepCrossLanguageRecursion) {
1480   v8::HandleScope scope;
1481   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1482   global->Set(v8_str("callScriptRecursively"),
1483               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1484   global->Set(v8_str("callFunctionRecursively"),
1485               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1486   LocalContext env(NULL, global);
1487 
1488   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1489   call_recursively_script = v8_compile("callScriptRecursively()");
1490   v8::Handle<Value> result = call_recursively_script->Run();
1491   call_recursively_script = v8::Handle<Script>();
1492 
1493   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1494   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1495 }
1496 
1497 
1498 static v8::Handle<Value>
ThrowingPropertyHandlerGet(Local<String> key,const AccessorInfo &)1499     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1500   ApiTestFuzzer::Fuzz();
1501   return v8::ThrowException(key);
1502 }
1503 
1504 
ThrowingPropertyHandlerSet(Local<String> key,Local<Value>,const AccessorInfo &)1505 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1506                                                     Local<Value>,
1507                                                     const AccessorInfo&) {
1508   v8::ThrowException(key);
1509   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1510 }
1511 
1512 
THREADED_TEST(CallbackExceptionRegression)1513 THREADED_TEST(CallbackExceptionRegression) {
1514   v8::HandleScope scope;
1515   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1516   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1517                                ThrowingPropertyHandlerSet);
1518   LocalContext env;
1519   env->Global()->Set(v8_str("obj"), obj->NewInstance());
1520   v8::Handle<Value> otto = Script::Compile(v8_str(
1521       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1522   CHECK_EQ(v8_str("otto"), otto);
1523   v8::Handle<Value> netto = Script::Compile(v8_str(
1524       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1525   CHECK_EQ(v8_str("netto"), netto);
1526 }
1527 
1528 
THREADED_TEST(FunctionPrototype)1529 THREADED_TEST(FunctionPrototype) {
1530   v8::HandleScope scope;
1531   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1532   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1533   LocalContext env;
1534   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1535   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1536   CHECK_EQ(script->Run()->Int32Value(), 321);
1537 }
1538 
1539 
THREADED_TEST(InternalFields)1540 THREADED_TEST(InternalFields) {
1541   v8::HandleScope scope;
1542   LocalContext env;
1543 
1544   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1545   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1546   instance_templ->SetInternalFieldCount(1);
1547   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1548   CHECK_EQ(1, obj->InternalFieldCount());
1549   CHECK(obj->GetInternalField(0)->IsUndefined());
1550   obj->SetInternalField(0, v8_num(17));
1551   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1552 }
1553 
1554 
THREADED_TEST(GlobalObjectInternalFields)1555 THREADED_TEST(GlobalObjectInternalFields) {
1556   v8::HandleScope scope;
1557   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1558   global_template->SetInternalFieldCount(1);
1559   LocalContext env(NULL, global_template);
1560   v8::Handle<v8::Object> global_proxy = env->Global();
1561   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1562   CHECK_EQ(1, global->InternalFieldCount());
1563   CHECK(global->GetInternalField(0)->IsUndefined());
1564   global->SetInternalField(0, v8_num(17));
1565   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1566 }
1567 
1568 
THREADED_TEST(InternalFieldsNativePointers)1569 THREADED_TEST(InternalFieldsNativePointers) {
1570   v8::HandleScope scope;
1571   LocalContext env;
1572 
1573   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1574   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1575   instance_templ->SetInternalFieldCount(1);
1576   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1577   CHECK_EQ(1, obj->InternalFieldCount());
1578   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1579 
1580   char* data = new char[100];
1581 
1582   void* aligned = data;
1583   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1584   void* unaligned = data + 1;
1585   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1586 
1587   // Check reading and writing aligned pointers.
1588   obj->SetPointerInInternalField(0, aligned);
1589   HEAP->CollectAllGarbage(false);
1590   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1591 
1592   // Check reading and writing unaligned pointers.
1593   obj->SetPointerInInternalField(0, unaligned);
1594   HEAP->CollectAllGarbage(false);
1595   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1596 
1597   delete[] data;
1598 }
1599 
1600 
THREADED_TEST(InternalFieldsNativePointersAndExternal)1601 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1602   v8::HandleScope scope;
1603   LocalContext env;
1604 
1605   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1606   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1607   instance_templ->SetInternalFieldCount(1);
1608   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1609   CHECK_EQ(1, obj->InternalFieldCount());
1610   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1611 
1612   char* data = new char[100];
1613 
1614   void* aligned = data;
1615   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1616   void* unaligned = data + 1;
1617   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1618 
1619   obj->SetPointerInInternalField(0, aligned);
1620   HEAP->CollectAllGarbage(false);
1621   CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1622 
1623   obj->SetPointerInInternalField(0, unaligned);
1624   HEAP->CollectAllGarbage(false);
1625   CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1626 
1627   obj->SetInternalField(0, v8::External::Wrap(aligned));
1628   HEAP->CollectAllGarbage(false);
1629   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1630 
1631   obj->SetInternalField(0, v8::External::Wrap(unaligned));
1632   HEAP->CollectAllGarbage(false);
1633   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1634 
1635   delete[] data;
1636 }
1637 
1638 
THREADED_TEST(IdentityHash)1639 THREADED_TEST(IdentityHash) {
1640   v8::HandleScope scope;
1641   LocalContext env;
1642 
1643   // Ensure that the test starts with an fresh heap to test whether the hash
1644   // code is based on the address.
1645   HEAP->CollectAllGarbage(false);
1646   Local<v8::Object> obj = v8::Object::New();
1647   int hash = obj->GetIdentityHash();
1648   int hash1 = obj->GetIdentityHash();
1649   CHECK_EQ(hash, hash1);
1650   int hash2 = v8::Object::New()->GetIdentityHash();
1651   // Since the identity hash is essentially a random number two consecutive
1652   // objects should not be assigned the same hash code. If the test below fails
1653   // the random number generator should be evaluated.
1654   CHECK_NE(hash, hash2);
1655   HEAP->CollectAllGarbage(false);
1656   int hash3 = v8::Object::New()->GetIdentityHash();
1657   // Make sure that the identity hash is not based on the initial address of
1658   // the object alone. If the test below fails the random number generator
1659   // should be evaluated.
1660   CHECK_NE(hash, hash3);
1661   int hash4 = obj->GetIdentityHash();
1662   CHECK_EQ(hash, hash4);
1663 
1664   // Check identity hashes behaviour in the presence of JS accessors.
1665   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1666   {
1667     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1668     Local<v8::Object> o1 = v8::Object::New();
1669     Local<v8::Object> o2 = v8::Object::New();
1670     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1671   }
1672   {
1673     CompileRun(
1674         "function cnst() { return 42; };\n"
1675         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1676     Local<v8::Object> o1 = v8::Object::New();
1677     Local<v8::Object> o2 = v8::Object::New();
1678     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1679   }
1680 }
1681 
1682 
THREADED_TEST(HiddenProperties)1683 THREADED_TEST(HiddenProperties) {
1684   v8::HandleScope scope;
1685   LocalContext env;
1686 
1687   v8::Local<v8::Object> obj = v8::Object::New();
1688   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1689   v8::Local<v8::String> empty = v8_str("");
1690   v8::Local<v8::String> prop_name = v8_str("prop_name");
1691 
1692   HEAP->CollectAllGarbage(false);
1693 
1694   // Make sure delete of a non-existent hidden value works
1695   CHECK(obj->DeleteHiddenValue(key));
1696 
1697   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1698   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1699   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1700   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1701 
1702   HEAP->CollectAllGarbage(false);
1703 
1704   // Make sure we do not find the hidden property.
1705   CHECK(!obj->Has(empty));
1706   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1707   CHECK(obj->Get(empty)->IsUndefined());
1708   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1709   CHECK(obj->Set(empty, v8::Integer::New(2003)));
1710   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1711   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1712 
1713   HEAP->CollectAllGarbage(false);
1714 
1715   // Add another property and delete it afterwards to force the object in
1716   // slow case.
1717   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1718   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1719   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1720   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1721   CHECK(obj->Delete(prop_name));
1722   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1723 
1724   HEAP->CollectAllGarbage(false);
1725 
1726   CHECK(obj->DeleteHiddenValue(key));
1727   CHECK(obj->GetHiddenValue(key).IsEmpty());
1728 }
1729 
1730 
1731 static bool interceptor_for_hidden_properties_called;
InterceptorForHiddenProperties(Local<String> name,const AccessorInfo & info)1732 static v8::Handle<Value> InterceptorForHiddenProperties(
1733     Local<String> name, const AccessorInfo& info) {
1734   interceptor_for_hidden_properties_called = true;
1735   return v8::Handle<Value>();
1736 }
1737 
1738 
THREADED_TEST(HiddenPropertiesWithInterceptors)1739 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1740   v8::HandleScope scope;
1741   LocalContext context;
1742 
1743   interceptor_for_hidden_properties_called = false;
1744 
1745   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1746 
1747   // Associate an interceptor with an object and start setting hidden values.
1748   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1749   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1750   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1751   Local<v8::Function> function = fun_templ->GetFunction();
1752   Local<v8::Object> obj = function->NewInstance();
1753   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1754   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1755   CHECK(!interceptor_for_hidden_properties_called);
1756 }
1757 
1758 
THREADED_TEST(External)1759 THREADED_TEST(External) {
1760   v8::HandleScope scope;
1761   int x = 3;
1762   Local<v8::External> ext = v8::External::New(&x);
1763   LocalContext env;
1764   env->Global()->Set(v8_str("ext"), ext);
1765   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1766   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1767   int* ptr = static_cast<int*>(reext->Value());
1768   CHECK_EQ(x, 3);
1769   *ptr = 10;
1770   CHECK_EQ(x, 10);
1771 
1772   // Make sure unaligned pointers are wrapped properly.
1773   char* data = i::StrDup("0123456789");
1774   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1775   Local<v8::Value> one = v8::External::Wrap(&data[1]);
1776   Local<v8::Value> two = v8::External::Wrap(&data[2]);
1777   Local<v8::Value> three = v8::External::Wrap(&data[3]);
1778 
1779   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1780   CHECK_EQ('0', *char_ptr);
1781   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1782   CHECK_EQ('1', *char_ptr);
1783   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1784   CHECK_EQ('2', *char_ptr);
1785   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1786   CHECK_EQ('3', *char_ptr);
1787   i::DeleteArray(data);
1788 }
1789 
1790 
THREADED_TEST(GlobalHandle)1791 THREADED_TEST(GlobalHandle) {
1792   v8::Persistent<String> global;
1793   {
1794     v8::HandleScope scope;
1795     Local<String> str = v8_str("str");
1796     global = v8::Persistent<String>::New(str);
1797   }
1798   CHECK_EQ(global->Length(), 3);
1799   global.Dispose();
1800 }
1801 
1802 
1803 static int NumberOfWeakCalls = 0;
WeakPointerCallback(Persistent<Value> handle,void * id)1804 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1805   CHECK_EQ(reinterpret_cast<void*>(1234), id);
1806   NumberOfWeakCalls++;
1807   handle.Dispose();
1808 }
1809 
THREADED_TEST(ApiObjectGroups)1810 THREADED_TEST(ApiObjectGroups) {
1811   HandleScope scope;
1812   LocalContext env;
1813 
1814   NumberOfWeakCalls = 0;
1815 
1816   Persistent<Object> g1s1;
1817   Persistent<Object> g1s2;
1818   Persistent<Object> g1c1;
1819   Persistent<Object> g2s1;
1820   Persistent<Object> g2s2;
1821   Persistent<Object> g2c1;
1822 
1823   {
1824     HandleScope scope;
1825     g1s1 = Persistent<Object>::New(Object::New());
1826     g1s2 = Persistent<Object>::New(Object::New());
1827     g1c1 = Persistent<Object>::New(Object::New());
1828     g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1829     g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1830     g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1831 
1832     g2s1 = Persistent<Object>::New(Object::New());
1833     g2s2 = Persistent<Object>::New(Object::New());
1834     g2c1 = Persistent<Object>::New(Object::New());
1835     g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1836     g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1837     g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1838   }
1839 
1840   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
1841 
1842   // Connect group 1 and 2, make a cycle.
1843   CHECK(g1s2->Set(0, g2s2));
1844   CHECK(g2s1->Set(0, g1s1));
1845 
1846   {
1847     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1848     Persistent<Value> g1_children[] = { g1c1 };
1849     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1850     Persistent<Value> g2_children[] = { g2c1 };
1851     V8::AddObjectGroup(g1_objects, 2);
1852     V8::AddImplicitReferences(g1s1, g1_children, 1);
1853     V8::AddObjectGroup(g2_objects, 2);
1854     V8::AddImplicitReferences(g2s2, g2_children, 1);
1855   }
1856   // Do a full GC
1857   HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1858 
1859   // All object should be alive.
1860   CHECK_EQ(0, NumberOfWeakCalls);
1861 
1862   // Weaken the root.
1863   root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1864   // But make children strong roots---all the objects (except for children)
1865   // should be collectable now.
1866   g1c1.ClearWeak();
1867   g2c1.ClearWeak();
1868 
1869   // Groups are deleted, rebuild groups.
1870   {
1871     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1872     Persistent<Value> g1_children[] = { g1c1 };
1873     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1874     Persistent<Value> g2_children[] = { g2c1 };
1875     V8::AddObjectGroup(g1_objects, 2);
1876     V8::AddImplicitReferences(g1s1, g1_children, 1);
1877     V8::AddObjectGroup(g2_objects, 2);
1878     V8::AddImplicitReferences(g2s2, g2_children, 1);
1879   }
1880 
1881   HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1882 
1883   // All objects should be gone. 5 global handles in total.
1884   CHECK_EQ(5, NumberOfWeakCalls);
1885 
1886   // And now make children weak again and collect them.
1887   g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1888   g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1889 
1890   HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1891   CHECK_EQ(7, NumberOfWeakCalls);
1892 }
1893 
1894 
THREADED_TEST(ApiObjectGroupsCycle)1895 THREADED_TEST(ApiObjectGroupsCycle) {
1896   HandleScope scope;
1897   LocalContext env;
1898 
1899   NumberOfWeakCalls = 0;
1900 
1901   Persistent<Object> g1s1;
1902   Persistent<Object> g1s2;
1903   Persistent<Object> g2s1;
1904   Persistent<Object> g2s2;
1905   Persistent<Object> g3s1;
1906   Persistent<Object> g3s2;
1907 
1908   {
1909     HandleScope scope;
1910     g1s1 = Persistent<Object>::New(Object::New());
1911     g1s2 = Persistent<Object>::New(Object::New());
1912     g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1913     g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914 
1915     g2s1 = Persistent<Object>::New(Object::New());
1916     g2s2 = Persistent<Object>::New(Object::New());
1917     g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1918     g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1919 
1920     g3s1 = Persistent<Object>::New(Object::New());
1921     g3s2 = Persistent<Object>::New(Object::New());
1922     g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1923     g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1924   }
1925 
1926   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
1927 
1928   // Connect groups.  We're building the following cycle:
1929   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
1930   // groups.
1931   {
1932     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1933     Persistent<Value> g1_children[] = { g2s1 };
1934     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1935     Persistent<Value> g2_children[] = { g3s1 };
1936     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1937     Persistent<Value> g3_children[] = { g1s1 };
1938     V8::AddObjectGroup(g1_objects, 2);
1939     V8::AddImplicitReferences(g1s1, g1_children, 1);
1940     V8::AddObjectGroup(g2_objects, 2);
1941     V8::AddImplicitReferences(g2s1, g2_children, 1);
1942     V8::AddObjectGroup(g3_objects, 2);
1943     V8::AddImplicitReferences(g3s1, g3_children, 1);
1944   }
1945   // Do a full GC
1946   HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1947 
1948   // All object should be alive.
1949   CHECK_EQ(0, NumberOfWeakCalls);
1950 
1951   // Weaken the root.
1952   root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1953 
1954   // Groups are deleted, rebuild groups.
1955   {
1956     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1957     Persistent<Value> g1_children[] = { g2s1 };
1958     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1959     Persistent<Value> g2_children[] = { g3s1 };
1960     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1961     Persistent<Value> g3_children[] = { g1s1 };
1962     V8::AddObjectGroup(g1_objects, 2);
1963     V8::AddImplicitReferences(g1s1, g1_children, 1);
1964     V8::AddObjectGroup(g2_objects, 2);
1965     V8::AddImplicitReferences(g2s1, g2_children, 1);
1966     V8::AddObjectGroup(g3_objects, 2);
1967     V8::AddImplicitReferences(g3s1, g3_children, 1);
1968   }
1969 
1970   HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1971 
1972   // All objects should be gone. 7 global handles in total.
1973   CHECK_EQ(7, NumberOfWeakCalls);
1974 }
1975 
1976 
THREADED_TEST(ScriptException)1977 THREADED_TEST(ScriptException) {
1978   v8::HandleScope scope;
1979   LocalContext env;
1980   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1981   v8::TryCatch try_catch;
1982   Local<Value> result = script->Run();
1983   CHECK(result.IsEmpty());
1984   CHECK(try_catch.HasCaught());
1985   String::AsciiValue exception_value(try_catch.Exception());
1986   CHECK_EQ(*exception_value, "panama!");
1987 }
1988 
1989 
1990 bool message_received;
1991 
1992 
check_message(v8::Handle<v8::Message> message,v8::Handle<Value> data)1993 static void check_message(v8::Handle<v8::Message> message,
1994                           v8::Handle<Value> data) {
1995   CHECK_EQ(5.76, data->NumberValue());
1996   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1997   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1998   message_received = true;
1999 }
2000 
2001 
THREADED_TEST(MessageHandlerData)2002 THREADED_TEST(MessageHandlerData) {
2003   message_received = false;
2004   v8::HandleScope scope;
2005   CHECK(!message_received);
2006   v8::V8::AddMessageListener(check_message, v8_num(5.76));
2007   LocalContext context;
2008   v8::ScriptOrigin origin =
2009       v8::ScriptOrigin(v8_str("6.75"));
2010   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2011                                                   &origin);
2012   script->SetData(v8_str("7.56"));
2013   script->Run();
2014   CHECK(message_received);
2015   // clear out the message listener
2016   v8::V8::RemoveMessageListeners(check_message);
2017 }
2018 
2019 
THREADED_TEST(GetSetProperty)2020 THREADED_TEST(GetSetProperty) {
2021   v8::HandleScope scope;
2022   LocalContext context;
2023   context->Global()->Set(v8_str("foo"), v8_num(14));
2024   context->Global()->Set(v8_str("12"), v8_num(92));
2025   context->Global()->Set(v8::Integer::New(16), v8_num(32));
2026   context->Global()->Set(v8_num(13), v8_num(56));
2027   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2028   CHECK_EQ(14, foo->Int32Value());
2029   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2030   CHECK_EQ(92, twelve->Int32Value());
2031   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2032   CHECK_EQ(32, sixteen->Int32Value());
2033   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2034   CHECK_EQ(56, thirteen->Int32Value());
2035   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2036   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2037   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2038   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2039   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2040   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2041   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2042   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2043   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2044 }
2045 
2046 
THREADED_TEST(PropertyAttributes)2047 THREADED_TEST(PropertyAttributes) {
2048   v8::HandleScope scope;
2049   LocalContext context;
2050   // read-only
2051   Local<String> prop = v8_str("read_only");
2052   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2053   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2054   Script::Compile(v8_str("read_only = 9"))->Run();
2055   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2056   context->Global()->Set(prop, v8_num(10));
2057   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2058   // dont-delete
2059   prop = v8_str("dont_delete");
2060   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2061   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2062   Script::Compile(v8_str("delete dont_delete"))->Run();
2063   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2064 }
2065 
2066 
THREADED_TEST(Array)2067 THREADED_TEST(Array) {
2068   v8::HandleScope scope;
2069   LocalContext context;
2070   Local<v8::Array> array = v8::Array::New();
2071   CHECK_EQ(0, array->Length());
2072   CHECK(array->Get(0)->IsUndefined());
2073   CHECK(!array->Has(0));
2074   CHECK(array->Get(100)->IsUndefined());
2075   CHECK(!array->Has(100));
2076   array->Set(2, v8_num(7));
2077   CHECK_EQ(3, array->Length());
2078   CHECK(!array->Has(0));
2079   CHECK(!array->Has(1));
2080   CHECK(array->Has(2));
2081   CHECK_EQ(7, array->Get(2)->Int32Value());
2082   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2083   Local<v8::Array> arr = obj.As<v8::Array>();
2084   CHECK_EQ(3, arr->Length());
2085   CHECK_EQ(1, arr->Get(0)->Int32Value());
2086   CHECK_EQ(2, arr->Get(1)->Int32Value());
2087   CHECK_EQ(3, arr->Get(2)->Int32Value());
2088   array = v8::Array::New(27);
2089   CHECK_EQ(27, array->Length());
2090   array = v8::Array::New(-27);
2091   CHECK_EQ(0, array->Length());
2092 }
2093 
2094 
HandleF(const v8::Arguments & args)2095 v8::Handle<Value> HandleF(const v8::Arguments& args) {
2096   v8::HandleScope scope;
2097   ApiTestFuzzer::Fuzz();
2098   Local<v8::Array> result = v8::Array::New(args.Length());
2099   for (int i = 0; i < args.Length(); i++)
2100     result->Set(i, args[i]);
2101   return scope.Close(result);
2102 }
2103 
2104 
THREADED_TEST(Vector)2105 THREADED_TEST(Vector) {
2106   v8::HandleScope scope;
2107   Local<ObjectTemplate> global = ObjectTemplate::New();
2108   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2109   LocalContext context(0, global);
2110 
2111   const char* fun = "f()";
2112   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2113   CHECK_EQ(0, a0->Length());
2114 
2115   const char* fun2 = "f(11)";
2116   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2117   CHECK_EQ(1, a1->Length());
2118   CHECK_EQ(11, a1->Get(0)->Int32Value());
2119 
2120   const char* fun3 = "f(12, 13)";
2121   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2122   CHECK_EQ(2, a2->Length());
2123   CHECK_EQ(12, a2->Get(0)->Int32Value());
2124   CHECK_EQ(13, a2->Get(1)->Int32Value());
2125 
2126   const char* fun4 = "f(14, 15, 16)";
2127   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2128   CHECK_EQ(3, a3->Length());
2129   CHECK_EQ(14, a3->Get(0)->Int32Value());
2130   CHECK_EQ(15, a3->Get(1)->Int32Value());
2131   CHECK_EQ(16, a3->Get(2)->Int32Value());
2132 
2133   const char* fun5 = "f(17, 18, 19, 20)";
2134   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2135   CHECK_EQ(4, a4->Length());
2136   CHECK_EQ(17, a4->Get(0)->Int32Value());
2137   CHECK_EQ(18, a4->Get(1)->Int32Value());
2138   CHECK_EQ(19, a4->Get(2)->Int32Value());
2139   CHECK_EQ(20, a4->Get(3)->Int32Value());
2140 }
2141 
2142 
THREADED_TEST(FunctionCall)2143 THREADED_TEST(FunctionCall) {
2144   v8::HandleScope scope;
2145   LocalContext context;
2146   CompileRun(
2147     "function Foo() {"
2148     "  var result = [];"
2149     "  for (var i = 0; i < arguments.length; i++) {"
2150     "    result.push(arguments[i]);"
2151     "  }"
2152     "  return result;"
2153     "}");
2154   Local<Function> Foo =
2155       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2156 
2157   v8::Handle<Value>* args0 = NULL;
2158   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2159   CHECK_EQ(0, a0->Length());
2160 
2161   v8::Handle<Value> args1[] = { v8_num(1.1) };
2162   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2163   CHECK_EQ(1, a1->Length());
2164   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2165 
2166   v8::Handle<Value> args2[] = { v8_num(2.2),
2167                                 v8_num(3.3) };
2168   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2169   CHECK_EQ(2, a2->Length());
2170   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2171   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2172 
2173   v8::Handle<Value> args3[] = { v8_num(4.4),
2174                                 v8_num(5.5),
2175                                 v8_num(6.6) };
2176   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2177   CHECK_EQ(3, a3->Length());
2178   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2179   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2180   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2181 
2182   v8::Handle<Value> args4[] = { v8_num(7.7),
2183                                 v8_num(8.8),
2184                                 v8_num(9.9),
2185                                 v8_num(10.11) };
2186   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2187   CHECK_EQ(4, a4->Length());
2188   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2189   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2190   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2191   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2192 }
2193 
2194 
2195 static const char* js_code_causing_out_of_memory =
2196     "var a = new Array(); while(true) a.push(a);";
2197 
2198 
2199 // These tests run for a long time and prevent us from running tests
2200 // that come after them so they cannot run in parallel.
TEST(OutOfMemory)2201 TEST(OutOfMemory) {
2202   // It's not possible to read a snapshot into a heap with different dimensions.
2203   if (i::Snapshot::IsEnabled()) return;
2204   // Set heap limits.
2205   static const int K = 1024;
2206   v8::ResourceConstraints constraints;
2207   constraints.set_max_young_space_size(256 * K);
2208   constraints.set_max_old_space_size(4 * K * K);
2209   v8::SetResourceConstraints(&constraints);
2210 
2211   // Execute a script that causes out of memory.
2212   v8::HandleScope scope;
2213   LocalContext context;
2214   v8::V8::IgnoreOutOfMemoryException();
2215   Local<Script> script =
2216       Script::Compile(String::New(js_code_causing_out_of_memory));
2217   Local<Value> result = script->Run();
2218 
2219   // Check for out of memory state.
2220   CHECK(result.IsEmpty());
2221   CHECK(context->HasOutOfMemoryException());
2222 }
2223 
2224 
ProvokeOutOfMemory(const v8::Arguments & args)2225 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2226   ApiTestFuzzer::Fuzz();
2227 
2228   v8::HandleScope scope;
2229   LocalContext context;
2230   Local<Script> script =
2231       Script::Compile(String::New(js_code_causing_out_of_memory));
2232   Local<Value> result = script->Run();
2233 
2234   // Check for out of memory state.
2235   CHECK(result.IsEmpty());
2236   CHECK(context->HasOutOfMemoryException());
2237 
2238   return result;
2239 }
2240 
2241 
TEST(OutOfMemoryNested)2242 TEST(OutOfMemoryNested) {
2243   // It's not possible to read a snapshot into a heap with different dimensions.
2244   if (i::Snapshot::IsEnabled()) return;
2245   // Set heap limits.
2246   static const int K = 1024;
2247   v8::ResourceConstraints constraints;
2248   constraints.set_max_young_space_size(256 * K);
2249   constraints.set_max_old_space_size(4 * K * K);
2250   v8::SetResourceConstraints(&constraints);
2251 
2252   v8::HandleScope scope;
2253   Local<ObjectTemplate> templ = ObjectTemplate::New();
2254   templ->Set(v8_str("ProvokeOutOfMemory"),
2255              v8::FunctionTemplate::New(ProvokeOutOfMemory));
2256   LocalContext context(0, templ);
2257   v8::V8::IgnoreOutOfMemoryException();
2258   Local<Value> result = CompileRun(
2259     "var thrown = false;"
2260     "try {"
2261     "  ProvokeOutOfMemory();"
2262     "} catch (e) {"
2263     "  thrown = true;"
2264     "}");
2265   // Check for out of memory state.
2266   CHECK(result.IsEmpty());
2267   CHECK(context->HasOutOfMemoryException());
2268 }
2269 
2270 
TEST(HugeConsStringOutOfMemory)2271 TEST(HugeConsStringOutOfMemory) {
2272   // It's not possible to read a snapshot into a heap with different dimensions.
2273   if (i::Snapshot::IsEnabled()) return;
2274   // Set heap limits.
2275   static const int K = 1024;
2276   v8::ResourceConstraints constraints;
2277   constraints.set_max_young_space_size(256 * K);
2278   constraints.set_max_old_space_size(2 * K * K);
2279   v8::SetResourceConstraints(&constraints);
2280 
2281   // Execute a script that causes out of memory.
2282   v8::V8::IgnoreOutOfMemoryException();
2283 
2284   v8::HandleScope scope;
2285   LocalContext context;
2286 
2287   // Build huge string. This should fail with out of memory exception.
2288   Local<Value> result = CompileRun(
2289     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2290     "for (var i = 0; i < 22; i++) { str = str + str; }");
2291 
2292   // Check for out of memory state.
2293   CHECK(result.IsEmpty());
2294   CHECK(context->HasOutOfMemoryException());
2295 }
2296 
2297 
THREADED_TEST(ConstructCall)2298 THREADED_TEST(ConstructCall) {
2299   v8::HandleScope scope;
2300   LocalContext context;
2301   CompileRun(
2302     "function Foo() {"
2303     "  var result = [];"
2304     "  for (var i = 0; i < arguments.length; i++) {"
2305     "    result.push(arguments[i]);"
2306     "  }"
2307     "  return result;"
2308     "}");
2309   Local<Function> Foo =
2310       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2311 
2312   v8::Handle<Value>* args0 = NULL;
2313   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2314   CHECK_EQ(0, a0->Length());
2315 
2316   v8::Handle<Value> args1[] = { v8_num(1.1) };
2317   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2318   CHECK_EQ(1, a1->Length());
2319   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2320 
2321   v8::Handle<Value> args2[] = { v8_num(2.2),
2322                                 v8_num(3.3) };
2323   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2324   CHECK_EQ(2, a2->Length());
2325   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2326   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2327 
2328   v8::Handle<Value> args3[] = { v8_num(4.4),
2329                                 v8_num(5.5),
2330                                 v8_num(6.6) };
2331   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2332   CHECK_EQ(3, a3->Length());
2333   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2334   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2335   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2336 
2337   v8::Handle<Value> args4[] = { v8_num(7.7),
2338                                 v8_num(8.8),
2339                                 v8_num(9.9),
2340                                 v8_num(10.11) };
2341   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2342   CHECK_EQ(4, a4->Length());
2343   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2344   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2345   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2346   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2347 }
2348 
2349 
CheckUncle(v8::TryCatch * try_catch)2350 static void CheckUncle(v8::TryCatch* try_catch) {
2351   CHECK(try_catch->HasCaught());
2352   String::AsciiValue str_value(try_catch->Exception());
2353   CHECK_EQ(*str_value, "uncle?");
2354   try_catch->Reset();
2355 }
2356 
2357 
THREADED_TEST(ConversionNumber)2358 THREADED_TEST(ConversionNumber) {
2359   v8::HandleScope scope;
2360   LocalContext env;
2361   // Very large number.
2362   CompileRun("var obj = Math.pow(2,32) * 1237;");
2363   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2364   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2365   CHECK_EQ(0, obj->ToInt32()->Value());
2366   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2367   // Large number.
2368   CompileRun("var obj = -1234567890123;");
2369   obj = env->Global()->Get(v8_str("obj"));
2370   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2371   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2372   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2373   // Small positive integer.
2374   CompileRun("var obj = 42;");
2375   obj = env->Global()->Get(v8_str("obj"));
2376   CHECK_EQ(42.0, obj->ToNumber()->Value());
2377   CHECK_EQ(42, obj->ToInt32()->Value());
2378   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2379   // Negative integer.
2380   CompileRun("var obj = -37;");
2381   obj = env->Global()->Get(v8_str("obj"));
2382   CHECK_EQ(-37.0, obj->ToNumber()->Value());
2383   CHECK_EQ(-37, obj->ToInt32()->Value());
2384   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2385   // Positive non-int32 integer.
2386   CompileRun("var obj = 0x81234567;");
2387   obj = env->Global()->Get(v8_str("obj"));
2388   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2389   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2390   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2391   // Fraction.
2392   CompileRun("var obj = 42.3;");
2393   obj = env->Global()->Get(v8_str("obj"));
2394   CHECK_EQ(42.3, obj->ToNumber()->Value());
2395   CHECK_EQ(42, obj->ToInt32()->Value());
2396   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2397   // Large negative fraction.
2398   CompileRun("var obj = -5726623061.75;");
2399   obj = env->Global()->Get(v8_str("obj"));
2400   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2401   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2402   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2403 }
2404 
2405 
THREADED_TEST(isNumberType)2406 THREADED_TEST(isNumberType) {
2407   v8::HandleScope scope;
2408   LocalContext env;
2409   // Very large number.
2410   CompileRun("var obj = Math.pow(2,32) * 1237;");
2411   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2412   CHECK(!obj->IsInt32());
2413   CHECK(!obj->IsUint32());
2414   // Large negative number.
2415   CompileRun("var obj = -1234567890123;");
2416   obj = env->Global()->Get(v8_str("obj"));
2417   CHECK(!obj->IsInt32());
2418   CHECK(!obj->IsUint32());
2419   // Small positive integer.
2420   CompileRun("var obj = 42;");
2421   obj = env->Global()->Get(v8_str("obj"));
2422   CHECK(obj->IsInt32());
2423   CHECK(obj->IsUint32());
2424   // Negative integer.
2425   CompileRun("var obj = -37;");
2426   obj = env->Global()->Get(v8_str("obj"));
2427   CHECK(obj->IsInt32());
2428   CHECK(!obj->IsUint32());
2429   // Positive non-int32 integer.
2430   CompileRun("var obj = 0x81234567;");
2431   obj = env->Global()->Get(v8_str("obj"));
2432   CHECK(!obj->IsInt32());
2433   CHECK(obj->IsUint32());
2434   // Fraction.
2435   CompileRun("var obj = 42.3;");
2436   obj = env->Global()->Get(v8_str("obj"));
2437   CHECK(!obj->IsInt32());
2438   CHECK(!obj->IsUint32());
2439   // Large negative fraction.
2440   CompileRun("var obj = -5726623061.75;");
2441   obj = env->Global()->Get(v8_str("obj"));
2442   CHECK(!obj->IsInt32());
2443   CHECK(!obj->IsUint32());
2444 }
2445 
2446 
THREADED_TEST(ConversionException)2447 THREADED_TEST(ConversionException) {
2448   v8::HandleScope scope;
2449   LocalContext env;
2450   CompileRun(
2451     "function TestClass() { };"
2452     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2453     "var obj = new TestClass();");
2454   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2455 
2456   v8::TryCatch try_catch;
2457 
2458   Local<Value> to_string_result = obj->ToString();
2459   CHECK(to_string_result.IsEmpty());
2460   CheckUncle(&try_catch);
2461 
2462   Local<Value> to_number_result = obj->ToNumber();
2463   CHECK(to_number_result.IsEmpty());
2464   CheckUncle(&try_catch);
2465 
2466   Local<Value> to_integer_result = obj->ToInteger();
2467   CHECK(to_integer_result.IsEmpty());
2468   CheckUncle(&try_catch);
2469 
2470   Local<Value> to_uint32_result = obj->ToUint32();
2471   CHECK(to_uint32_result.IsEmpty());
2472   CheckUncle(&try_catch);
2473 
2474   Local<Value> to_int32_result = obj->ToInt32();
2475   CHECK(to_int32_result.IsEmpty());
2476   CheckUncle(&try_catch);
2477 
2478   Local<Value> to_object_result = v8::Undefined()->ToObject();
2479   CHECK(to_object_result.IsEmpty());
2480   CHECK(try_catch.HasCaught());
2481   try_catch.Reset();
2482 
2483   int32_t int32_value = obj->Int32Value();
2484   CHECK_EQ(0, int32_value);
2485   CheckUncle(&try_catch);
2486 
2487   uint32_t uint32_value = obj->Uint32Value();
2488   CHECK_EQ(0, uint32_value);
2489   CheckUncle(&try_catch);
2490 
2491   double number_value = obj->NumberValue();
2492   CHECK_NE(0, IsNaN(number_value));
2493   CheckUncle(&try_catch);
2494 
2495   int64_t integer_value = obj->IntegerValue();
2496   CHECK_EQ(0.0, static_cast<double>(integer_value));
2497   CheckUncle(&try_catch);
2498 }
2499 
2500 
ThrowFromC(const v8::Arguments & args)2501 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2502   ApiTestFuzzer::Fuzz();
2503   return v8::ThrowException(v8_str("konto"));
2504 }
2505 
2506 
CCatcher(const v8::Arguments & args)2507 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2508   if (args.Length() < 1) return v8::Boolean::New(false);
2509   v8::HandleScope scope;
2510   v8::TryCatch try_catch;
2511   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2512   CHECK(!try_catch.HasCaught() || result.IsEmpty());
2513   return v8::Boolean::New(try_catch.HasCaught());
2514 }
2515 
2516 
THREADED_TEST(APICatch)2517 THREADED_TEST(APICatch) {
2518   v8::HandleScope scope;
2519   Local<ObjectTemplate> templ = ObjectTemplate::New();
2520   templ->Set(v8_str("ThrowFromC"),
2521              v8::FunctionTemplate::New(ThrowFromC));
2522   LocalContext context(0, templ);
2523   CompileRun(
2524     "var thrown = false;"
2525     "try {"
2526     "  ThrowFromC();"
2527     "} catch (e) {"
2528     "  thrown = true;"
2529     "}");
2530   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2531   CHECK(thrown->BooleanValue());
2532 }
2533 
2534 
THREADED_TEST(APIThrowTryCatch)2535 THREADED_TEST(APIThrowTryCatch) {
2536   v8::HandleScope scope;
2537   Local<ObjectTemplate> templ = ObjectTemplate::New();
2538   templ->Set(v8_str("ThrowFromC"),
2539              v8::FunctionTemplate::New(ThrowFromC));
2540   LocalContext context(0, templ);
2541   v8::TryCatch try_catch;
2542   CompileRun("ThrowFromC();");
2543   CHECK(try_catch.HasCaught());
2544 }
2545 
2546 
2547 // Test that a try-finally block doesn't shadow a try-catch block
2548 // when setting up an external handler.
2549 //
2550 // BUG(271): Some of the exception propagation does not work on the
2551 // ARM simulator because the simulator separates the C++ stack and the
2552 // JS stack.  This test therefore fails on the simulator.  The test is
2553 // not threaded to allow the threading tests to run on the simulator.
TEST(TryCatchInTryFinally)2554 TEST(TryCatchInTryFinally) {
2555   v8::HandleScope scope;
2556   Local<ObjectTemplate> templ = ObjectTemplate::New();
2557   templ->Set(v8_str("CCatcher"),
2558              v8::FunctionTemplate::New(CCatcher));
2559   LocalContext context(0, templ);
2560   Local<Value> result = CompileRun("try {"
2561                                    "  try {"
2562                                    "    CCatcher('throw 7;');"
2563                                    "  } finally {"
2564                                    "  }"
2565                                    "} catch (e) {"
2566                                    "}");
2567   CHECK(result->IsTrue());
2568 }
2569 
2570 
check_reference_error_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)2571 static void check_reference_error_message(
2572     v8::Handle<v8::Message> message,
2573     v8::Handle<v8::Value> data) {
2574   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2575   CHECK(message->Get()->Equals(v8_str(reference_error)));
2576 }
2577 
2578 
Fail(const v8::Arguments & args)2579 static v8::Handle<Value> Fail(const v8::Arguments& args) {
2580   ApiTestFuzzer::Fuzz();
2581   CHECK(false);
2582   return v8::Undefined();
2583 }
2584 
2585 
2586 // Test that overwritten methods are not invoked on uncaught exception
2587 // formatting. However, they are invoked when performing normal error
2588 // string conversions.
TEST(APIThrowMessageOverwrittenToString)2589 TEST(APIThrowMessageOverwrittenToString) {
2590   v8::HandleScope scope;
2591   v8::V8::AddMessageListener(check_reference_error_message);
2592   Local<ObjectTemplate> templ = ObjectTemplate::New();
2593   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2594   LocalContext context(NULL, templ);
2595   CompileRun("asdf;");
2596   CompileRun("var limit = {};"
2597              "limit.valueOf = fail;"
2598              "Error.stackTraceLimit = limit;");
2599   CompileRun("asdf");
2600   CompileRun("Array.prototype.pop = fail;");
2601   CompileRun("Object.prototype.hasOwnProperty = fail;");
2602   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2603   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2604   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2605   CompileRun("ReferenceError.prototype.toString ="
2606              "  function() { return 'Whoops' }");
2607   CompileRun("asdf;");
2608   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2609   CompileRun("asdf;");
2610   CompileRun("ReferenceError.prototype.constructor = void 0;");
2611   CompileRun("asdf;");
2612   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2613   CompileRun("asdf;");
2614   CompileRun("ReferenceError.prototype = new Object();");
2615   CompileRun("asdf;");
2616   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2617   CHECK(string->Equals(v8_str("Whoops")));
2618   CompileRun("ReferenceError.prototype.constructor = new Object();"
2619              "ReferenceError.prototype.constructor.name = 1;"
2620              "Number.prototype.toString = function() { return 'Whoops'; };"
2621              "ReferenceError.prototype.toString = Object.prototype.toString;");
2622   CompileRun("asdf;");
2623   v8::V8::RemoveMessageListeners(check_message);
2624 }
2625 
2626 
receive_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)2627 static void receive_message(v8::Handle<v8::Message> message,
2628                             v8::Handle<v8::Value> data) {
2629   message->Get();
2630   message_received = true;
2631 }
2632 
2633 
TEST(APIThrowMessage)2634 TEST(APIThrowMessage) {
2635   message_received = false;
2636   v8::HandleScope scope;
2637   v8::V8::AddMessageListener(receive_message);
2638   Local<ObjectTemplate> templ = ObjectTemplate::New();
2639   templ->Set(v8_str("ThrowFromC"),
2640              v8::FunctionTemplate::New(ThrowFromC));
2641   LocalContext context(0, templ);
2642   CompileRun("ThrowFromC();");
2643   CHECK(message_received);
2644   v8::V8::RemoveMessageListeners(check_message);
2645 }
2646 
2647 
TEST(APIThrowMessageAndVerboseTryCatch)2648 TEST(APIThrowMessageAndVerboseTryCatch) {
2649   message_received = false;
2650   v8::HandleScope scope;
2651   v8::V8::AddMessageListener(receive_message);
2652   Local<ObjectTemplate> templ = ObjectTemplate::New();
2653   templ->Set(v8_str("ThrowFromC"),
2654              v8::FunctionTemplate::New(ThrowFromC));
2655   LocalContext context(0, templ);
2656   v8::TryCatch try_catch;
2657   try_catch.SetVerbose(true);
2658   Local<Value> result = CompileRun("ThrowFromC();");
2659   CHECK(try_catch.HasCaught());
2660   CHECK(result.IsEmpty());
2661   CHECK(message_received);
2662   v8::V8::RemoveMessageListeners(check_message);
2663 }
2664 
2665 
TEST(APIStackOverflowAndVerboseTryCatch)2666 TEST(APIStackOverflowAndVerboseTryCatch) {
2667   message_received = false;
2668   v8::HandleScope scope;
2669   v8::V8::AddMessageListener(receive_message);
2670   LocalContext context;
2671   v8::TryCatch try_catch;
2672   try_catch.SetVerbose(true);
2673   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2674   CHECK(try_catch.HasCaught());
2675   CHECK(result.IsEmpty());
2676   CHECK(message_received);
2677   v8::V8::RemoveMessageListeners(receive_message);
2678 }
2679 
2680 
THREADED_TEST(ExternalScriptException)2681 THREADED_TEST(ExternalScriptException) {
2682   v8::HandleScope scope;
2683   Local<ObjectTemplate> templ = ObjectTemplate::New();
2684   templ->Set(v8_str("ThrowFromC"),
2685              v8::FunctionTemplate::New(ThrowFromC));
2686   LocalContext context(0, templ);
2687 
2688   v8::TryCatch try_catch;
2689   Local<Script> script
2690       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2691   Local<Value> result = script->Run();
2692   CHECK(result.IsEmpty());
2693   CHECK(try_catch.HasCaught());
2694   String::AsciiValue exception_value(try_catch.Exception());
2695   CHECK_EQ("konto", *exception_value);
2696 }
2697 
2698 
2699 
CThrowCountDown(const v8::Arguments & args)2700 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2701   ApiTestFuzzer::Fuzz();
2702   CHECK_EQ(4, args.Length());
2703   int count = args[0]->Int32Value();
2704   int cInterval = args[2]->Int32Value();
2705   if (count == 0) {
2706     return v8::ThrowException(v8_str("FromC"));
2707   } else {
2708     Local<v8::Object> global = Context::GetCurrent()->Global();
2709     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2710     v8::Handle<Value> argv[] = { v8_num(count - 1),
2711                                  args[1],
2712                                  args[2],
2713                                  args[3] };
2714     if (count % cInterval == 0) {
2715       v8::TryCatch try_catch;
2716       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2717       int expected = args[3]->Int32Value();
2718       if (try_catch.HasCaught()) {
2719         CHECK_EQ(expected, count);
2720         CHECK(result.IsEmpty());
2721         CHECK(!i::Isolate::Current()->has_scheduled_exception());
2722       } else {
2723         CHECK_NE(expected, count);
2724       }
2725       return result;
2726     } else {
2727       return fun.As<Function>()->Call(global, 4, argv);
2728     }
2729   }
2730 }
2731 
2732 
JSCheck(const v8::Arguments & args)2733 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2734   ApiTestFuzzer::Fuzz();
2735   CHECK_EQ(3, args.Length());
2736   bool equality = args[0]->BooleanValue();
2737   int count = args[1]->Int32Value();
2738   int expected = args[2]->Int32Value();
2739   if (equality) {
2740     CHECK_EQ(count, expected);
2741   } else {
2742     CHECK_NE(count, expected);
2743   }
2744   return v8::Undefined();
2745 }
2746 
2747 
THREADED_TEST(EvalInTryFinally)2748 THREADED_TEST(EvalInTryFinally) {
2749   v8::HandleScope scope;
2750   LocalContext context;
2751   v8::TryCatch try_catch;
2752   CompileRun("(function() {"
2753              "  try {"
2754              "    eval('asldkf (*&^&*^');"
2755              "  } finally {"
2756              "    return;"
2757              "  }"
2758              "})()");
2759   CHECK(!try_catch.HasCaught());
2760 }
2761 
2762 
2763 // This test works by making a stack of alternating JavaScript and C
2764 // activations.  These activations set up exception handlers with regular
2765 // intervals, one interval for C activations and another for JavaScript
2766 // activations.  When enough activations have been created an exception is
2767 // thrown and we check that the right activation catches the exception and that
2768 // no other activations do.  The right activation is always the topmost one with
2769 // a handler, regardless of whether it is in JavaScript or C.
2770 //
2771 // The notation used to describe a test case looks like this:
2772 //
2773 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
2774 //
2775 // Each entry is an activation, either JS or C.  The index is the count at that
2776 // level.  Stars identify activations with exception handlers, the @ identifies
2777 // the exception handler that should catch the exception.
2778 //
2779 // BUG(271): Some of the exception propagation does not work on the
2780 // ARM simulator because the simulator separates the C++ stack and the
2781 // JS stack.  This test therefore fails on the simulator.  The test is
2782 // not threaded to allow the threading tests to run on the simulator.
TEST(ExceptionOrder)2783 TEST(ExceptionOrder) {
2784   v8::HandleScope scope;
2785   Local<ObjectTemplate> templ = ObjectTemplate::New();
2786   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2787   templ->Set(v8_str("CThrowCountDown"),
2788              v8::FunctionTemplate::New(CThrowCountDown));
2789   LocalContext context(0, templ);
2790   CompileRun(
2791     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2792     "  if (count == 0) throw 'FromJS';"
2793     "  if (count % jsInterval == 0) {"
2794     "    try {"
2795     "      var value = CThrowCountDown(count - 1,"
2796     "                                  jsInterval,"
2797     "                                  cInterval,"
2798     "                                  expected);"
2799     "      check(false, count, expected);"
2800     "      return value;"
2801     "    } catch (e) {"
2802     "      check(true, count, expected);"
2803     "    }"
2804     "  } else {"
2805     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2806     "  }"
2807     "}");
2808   Local<Function> fun =
2809       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2810 
2811   const int argc = 4;
2812   //                             count      jsInterval cInterval  expected
2813 
2814   // *JS[4] *C[3] @JS[2] C[1] JS[0]
2815   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2816   fun->Call(fun, argc, a0);
2817 
2818   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2819   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2820   fun->Call(fun, argc, a1);
2821 
2822   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2823   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2824   fun->Call(fun, argc, a2);
2825 
2826   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2827   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2828   fun->Call(fun, argc, a3);
2829 
2830   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2831   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2832   fun->Call(fun, argc, a4);
2833 
2834   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2835   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2836   fun->Call(fun, argc, a5);
2837 }
2838 
2839 
ThrowValue(const v8::Arguments & args)2840 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2841   ApiTestFuzzer::Fuzz();
2842   CHECK_EQ(1, args.Length());
2843   return v8::ThrowException(args[0]);
2844 }
2845 
2846 
THREADED_TEST(ThrowValues)2847 THREADED_TEST(ThrowValues) {
2848   v8::HandleScope scope;
2849   Local<ObjectTemplate> templ = ObjectTemplate::New();
2850   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2851   LocalContext context(0, templ);
2852   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2853     "function Run(obj) {"
2854     "  try {"
2855     "    Throw(obj);"
2856     "  } catch (e) {"
2857     "    return e;"
2858     "  }"
2859     "  return 'no exception';"
2860     "}"
2861     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2862   CHECK_EQ(5, result->Length());
2863   CHECK(result->Get(v8::Integer::New(0))->IsString());
2864   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2865   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2866   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2867   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2868   CHECK(result->Get(v8::Integer::New(3))->IsNull());
2869   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2870 }
2871 
2872 
THREADED_TEST(CatchZero)2873 THREADED_TEST(CatchZero) {
2874   v8::HandleScope scope;
2875   LocalContext context;
2876   v8::TryCatch try_catch;
2877   CHECK(!try_catch.HasCaught());
2878   Script::Compile(v8_str("throw 10"))->Run();
2879   CHECK(try_catch.HasCaught());
2880   CHECK_EQ(10, try_catch.Exception()->Int32Value());
2881   try_catch.Reset();
2882   CHECK(!try_catch.HasCaught());
2883   Script::Compile(v8_str("throw 0"))->Run();
2884   CHECK(try_catch.HasCaught());
2885   CHECK_EQ(0, try_catch.Exception()->Int32Value());
2886 }
2887 
2888 
THREADED_TEST(CatchExceptionFromWith)2889 THREADED_TEST(CatchExceptionFromWith) {
2890   v8::HandleScope scope;
2891   LocalContext context;
2892   v8::TryCatch try_catch;
2893   CHECK(!try_catch.HasCaught());
2894   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2895   CHECK(try_catch.HasCaught());
2896 }
2897 
2898 
THREADED_TEST(TryCatchAndFinallyHidingException)2899 THREADED_TEST(TryCatchAndFinallyHidingException) {
2900   v8::HandleScope scope;
2901   LocalContext context;
2902   v8::TryCatch try_catch;
2903   CHECK(!try_catch.HasCaught());
2904   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
2905   CompileRun("f({toString: function() { throw 42; }});");
2906   CHECK(!try_catch.HasCaught());
2907 }
2908 
2909 
WithTryCatch(const v8::Arguments & args)2910 v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
2911   v8::TryCatch try_catch;
2912   return v8::Undefined();
2913 }
2914 
2915 
THREADED_TEST(TryCatchAndFinally)2916 THREADED_TEST(TryCatchAndFinally) {
2917   v8::HandleScope scope;
2918   LocalContext context;
2919   context->Global()->Set(
2920       v8_str("native_with_try_catch"),
2921       v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
2922   v8::TryCatch try_catch;
2923   CHECK(!try_catch.HasCaught());
2924   CompileRun(
2925       "try {\n"
2926       "  throw new Error('a');\n"
2927       "} finally {\n"
2928       "  native_with_try_catch();\n"
2929       "}\n");
2930   CHECK(try_catch.HasCaught());
2931 }
2932 
2933 
THREADED_TEST(Equality)2934 THREADED_TEST(Equality) {
2935   v8::HandleScope scope;
2936   LocalContext context;
2937   // Check that equality works at all before relying on CHECK_EQ
2938   CHECK(v8_str("a")->Equals(v8_str("a")));
2939   CHECK(!v8_str("a")->Equals(v8_str("b")));
2940 
2941   CHECK_EQ(v8_str("a"), v8_str("a"));
2942   CHECK_NE(v8_str("a"), v8_str("b"));
2943   CHECK_EQ(v8_num(1), v8_num(1));
2944   CHECK_EQ(v8_num(1.00), v8_num(1));
2945   CHECK_NE(v8_num(1), v8_num(2));
2946 
2947   // Assume String is not symbol.
2948   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2949   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2950   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2951   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2952   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2953   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2954   Local<Value> not_a_number = v8_num(i::OS::nan_value());
2955   CHECK(!not_a_number->StrictEquals(not_a_number));
2956   CHECK(v8::False()->StrictEquals(v8::False()));
2957   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2958 
2959   v8::Handle<v8::Object> obj = v8::Object::New();
2960   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2961   CHECK(alias->StrictEquals(obj));
2962   alias.Dispose();
2963 }
2964 
2965 
THREADED_TEST(MultiRun)2966 THREADED_TEST(MultiRun) {
2967   v8::HandleScope scope;
2968   LocalContext context;
2969   Local<Script> script = Script::Compile(v8_str("x"));
2970   for (int i = 0; i < 10; i++)
2971     script->Run();
2972 }
2973 
2974 
GetXValue(Local<String> name,const AccessorInfo & info)2975 static v8::Handle<Value> GetXValue(Local<String> name,
2976                                    const AccessorInfo& info) {
2977   ApiTestFuzzer::Fuzz();
2978   CHECK_EQ(info.Data(), v8_str("donut"));
2979   CHECK_EQ(name, v8_str("x"));
2980   return name;
2981 }
2982 
2983 
THREADED_TEST(SimplePropertyRead)2984 THREADED_TEST(SimplePropertyRead) {
2985   v8::HandleScope scope;
2986   Local<ObjectTemplate> templ = ObjectTemplate::New();
2987   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2988   LocalContext context;
2989   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2990   Local<Script> script = Script::Compile(v8_str("obj.x"));
2991   for (int i = 0; i < 10; i++) {
2992     Local<Value> result = script->Run();
2993     CHECK_EQ(result, v8_str("x"));
2994   }
2995 }
2996 
THREADED_TEST(DefinePropertyOnAPIAccessor)2997 THREADED_TEST(DefinePropertyOnAPIAccessor) {
2998   v8::HandleScope scope;
2999   Local<ObjectTemplate> templ = ObjectTemplate::New();
3000   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3001   LocalContext context;
3002   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3003 
3004   // Uses getOwnPropertyDescriptor to check the configurable status
3005   Local<Script> script_desc
3006     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3007                              "obj, 'x');"
3008                              "prop.configurable;"));
3009   Local<Value> result = script_desc->Run();
3010   CHECK_EQ(result->BooleanValue(), true);
3011 
3012   // Redefine get - but still configurable
3013   Local<Script> script_define
3014     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3015                              "            configurable: true };"
3016                              "Object.defineProperty(obj, 'x', desc);"
3017                              "obj.x"));
3018   result = script_define->Run();
3019   CHECK_EQ(result, v8_num(42));
3020 
3021   // Check that the accessor is still configurable
3022   result = script_desc->Run();
3023   CHECK_EQ(result->BooleanValue(), true);
3024 
3025   // Redefine to a non-configurable
3026   script_define
3027     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3028                              "             configurable: false };"
3029                              "Object.defineProperty(obj, 'x', desc);"
3030                              "obj.x"));
3031   result = script_define->Run();
3032   CHECK_EQ(result, v8_num(43));
3033   result = script_desc->Run();
3034   CHECK_EQ(result->BooleanValue(), false);
3035 
3036   // Make sure that it is not possible to redefine again
3037   v8::TryCatch try_catch;
3038   result = script_define->Run();
3039   CHECK(try_catch.HasCaught());
3040   String::AsciiValue exception_value(try_catch.Exception());
3041   CHECK_EQ(*exception_value,
3042            "TypeError: Cannot redefine property: defineProperty");
3043 }
3044 
THREADED_TEST(DefinePropertyOnDefineGetterSetter)3045 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3046   v8::HandleScope scope;
3047   Local<ObjectTemplate> templ = ObjectTemplate::New();
3048   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3049   LocalContext context;
3050   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3051 
3052   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3053                                     "Object.getOwnPropertyDescriptor( "
3054                                     "obj, 'x');"
3055                                     "prop.configurable;"));
3056   Local<Value> result = script_desc->Run();
3057   CHECK_EQ(result->BooleanValue(), true);
3058 
3059   Local<Script> script_define =
3060     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3061                            "            configurable: true };"
3062                            "Object.defineProperty(obj, 'x', desc);"
3063                            "obj.x"));
3064   result = script_define->Run();
3065   CHECK_EQ(result, v8_num(42));
3066 
3067 
3068   result = script_desc->Run();
3069   CHECK_EQ(result->BooleanValue(), true);
3070 
3071 
3072   script_define =
3073     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3074                            "            configurable: false };"
3075                            "Object.defineProperty(obj, 'x', desc);"
3076                            "obj.x"));
3077   result = script_define->Run();
3078   CHECK_EQ(result, v8_num(43));
3079   result = script_desc->Run();
3080 
3081   CHECK_EQ(result->BooleanValue(), false);
3082 
3083   v8::TryCatch try_catch;
3084   result = script_define->Run();
3085   CHECK(try_catch.HasCaught());
3086   String::AsciiValue exception_value(try_catch.Exception());
3087   CHECK_EQ(*exception_value,
3088            "TypeError: Cannot redefine property: defineProperty");
3089 }
3090 
3091 
GetGlobalProperty(LocalContext * context,char const * name)3092 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3093                                                 char const* name) {
3094   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3095 }
3096 
3097 
THREADED_TEST(DefineAPIAccessorOnObject)3098 THREADED_TEST(DefineAPIAccessorOnObject) {
3099   v8::HandleScope scope;
3100   Local<ObjectTemplate> templ = ObjectTemplate::New();
3101   LocalContext context;
3102 
3103   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3104   CompileRun("var obj2 = {};");
3105 
3106   CHECK(CompileRun("obj1.x")->IsUndefined());
3107   CHECK(CompileRun("obj2.x")->IsUndefined());
3108 
3109   CHECK(GetGlobalProperty(&context, "obj1")->
3110       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3111 
3112   ExpectString("obj1.x", "x");
3113   CHECK(CompileRun("obj2.x")->IsUndefined());
3114 
3115   CHECK(GetGlobalProperty(&context, "obj2")->
3116       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3117 
3118   ExpectString("obj1.x", "x");
3119   ExpectString("obj2.x", "x");
3120 
3121   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3122   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3123 
3124   CompileRun("Object.defineProperty(obj1, 'x',"
3125              "{ get: function() { return 'y'; }, configurable: true })");
3126 
3127   ExpectString("obj1.x", "y");
3128   ExpectString("obj2.x", "x");
3129 
3130   CompileRun("Object.defineProperty(obj2, 'x',"
3131              "{ get: function() { return 'y'; }, configurable: true })");
3132 
3133   ExpectString("obj1.x", "y");
3134   ExpectString("obj2.x", "y");
3135 
3136   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3137   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3138 
3139   CHECK(GetGlobalProperty(&context, "obj1")->
3140       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3141   CHECK(GetGlobalProperty(&context, "obj2")->
3142       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3143 
3144   ExpectString("obj1.x", "x");
3145   ExpectString("obj2.x", "x");
3146 
3147   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3148   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3149 
3150   // Define getters/setters, but now make them not configurable.
3151   CompileRun("Object.defineProperty(obj1, 'x',"
3152              "{ get: function() { return 'z'; }, configurable: false })");
3153   CompileRun("Object.defineProperty(obj2, 'x',"
3154              "{ get: function() { return 'z'; }, configurable: false })");
3155 
3156   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3157   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3158 
3159   ExpectString("obj1.x", "z");
3160   ExpectString("obj2.x", "z");
3161 
3162   CHECK(!GetGlobalProperty(&context, "obj1")->
3163       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3164   CHECK(!GetGlobalProperty(&context, "obj2")->
3165       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3166 
3167   ExpectString("obj1.x", "z");
3168   ExpectString("obj2.x", "z");
3169 }
3170 
3171 
THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden)3172 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3173   v8::HandleScope scope;
3174   Local<ObjectTemplate> templ = ObjectTemplate::New();
3175   LocalContext context;
3176 
3177   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3178   CompileRun("var obj2 = {};");
3179 
3180   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3181         v8_str("x"),
3182         GetXValue, NULL,
3183         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3184   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3185         v8_str("x"),
3186         GetXValue, NULL,
3187         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3188 
3189   ExpectString("obj1.x", "x");
3190   ExpectString("obj2.x", "x");
3191 
3192   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3193   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3194 
3195   CHECK(!GetGlobalProperty(&context, "obj1")->
3196       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3197   CHECK(!GetGlobalProperty(&context, "obj2")->
3198       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3199 
3200   {
3201     v8::TryCatch try_catch;
3202     CompileRun("Object.defineProperty(obj1, 'x',"
3203         "{get: function() { return 'func'; }})");
3204     CHECK(try_catch.HasCaught());
3205     String::AsciiValue exception_value(try_catch.Exception());
3206     CHECK_EQ(*exception_value,
3207             "TypeError: Cannot redefine property: defineProperty");
3208   }
3209   {
3210     v8::TryCatch try_catch;
3211     CompileRun("Object.defineProperty(obj2, 'x',"
3212         "{get: function() { return 'func'; }})");
3213     CHECK(try_catch.HasCaught());
3214     String::AsciiValue exception_value(try_catch.Exception());
3215     CHECK_EQ(*exception_value,
3216             "TypeError: Cannot redefine property: defineProperty");
3217   }
3218 }
3219 
3220 
Get239Value(Local<String> name,const AccessorInfo & info)3221 static v8::Handle<Value> Get239Value(Local<String> name,
3222                                      const AccessorInfo& info) {
3223   ApiTestFuzzer::Fuzz();
3224   CHECK_EQ(info.Data(), v8_str("donut"));
3225   CHECK_EQ(name, v8_str("239"));
3226   return name;
3227 }
3228 
3229 
THREADED_TEST(ElementAPIAccessor)3230 THREADED_TEST(ElementAPIAccessor) {
3231   v8::HandleScope scope;
3232   Local<ObjectTemplate> templ = ObjectTemplate::New();
3233   LocalContext context;
3234 
3235   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3236   CompileRun("var obj2 = {};");
3237 
3238   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3239         v8_str("239"),
3240         Get239Value, NULL,
3241         v8_str("donut")));
3242   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3243         v8_str("239"),
3244         Get239Value, NULL,
3245         v8_str("donut")));
3246 
3247   ExpectString("obj1[239]", "239");
3248   ExpectString("obj2[239]", "239");
3249   ExpectString("obj1['239']", "239");
3250   ExpectString("obj2['239']", "239");
3251 }
3252 
3253 
3254 v8::Persistent<Value> xValue;
3255 
3256 
SetXValue(Local<String> name,Local<Value> value,const AccessorInfo & info)3257 static void SetXValue(Local<String> name,
3258                       Local<Value> value,
3259                       const AccessorInfo& info) {
3260   CHECK_EQ(value, v8_num(4));
3261   CHECK_EQ(info.Data(), v8_str("donut"));
3262   CHECK_EQ(name, v8_str("x"));
3263   CHECK(xValue.IsEmpty());
3264   xValue = v8::Persistent<Value>::New(value);
3265 }
3266 
3267 
THREADED_TEST(SimplePropertyWrite)3268 THREADED_TEST(SimplePropertyWrite) {
3269   v8::HandleScope scope;
3270   Local<ObjectTemplate> templ = ObjectTemplate::New();
3271   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3272   LocalContext context;
3273   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3274   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3275   for (int i = 0; i < 10; i++) {
3276     CHECK(xValue.IsEmpty());
3277     script->Run();
3278     CHECK_EQ(v8_num(4), xValue);
3279     xValue.Dispose();
3280     xValue = v8::Persistent<Value>();
3281   }
3282 }
3283 
3284 
XPropertyGetter(Local<String> property,const AccessorInfo & info)3285 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3286                                          const AccessorInfo& info) {
3287   ApiTestFuzzer::Fuzz();
3288   CHECK(info.Data()->IsUndefined());
3289   return property;
3290 }
3291 
3292 
THREADED_TEST(NamedInterceptorPropertyRead)3293 THREADED_TEST(NamedInterceptorPropertyRead) {
3294   v8::HandleScope scope;
3295   Local<ObjectTemplate> templ = ObjectTemplate::New();
3296   templ->SetNamedPropertyHandler(XPropertyGetter);
3297   LocalContext context;
3298   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3299   Local<Script> script = Script::Compile(v8_str("obj.x"));
3300   for (int i = 0; i < 10; i++) {
3301     Local<Value> result = script->Run();
3302     CHECK_EQ(result, v8_str("x"));
3303   }
3304 }
3305 
3306 
THREADED_TEST(NamedInterceptorDictionaryIC)3307 THREADED_TEST(NamedInterceptorDictionaryIC) {
3308   v8::HandleScope scope;
3309   Local<ObjectTemplate> templ = ObjectTemplate::New();
3310   templ->SetNamedPropertyHandler(XPropertyGetter);
3311   LocalContext context;
3312   // Create an object with a named interceptor.
3313   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3314   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3315   for (int i = 0; i < 10; i++) {
3316     Local<Value> result = script->Run();
3317     CHECK_EQ(result, v8_str("x"));
3318   }
3319   // Create a slow case object and a function accessing a property in
3320   // that slow case object (with dictionary probing in generated
3321   // code). Then force object with a named interceptor into slow-case,
3322   // pass it to the function, and check that the interceptor is called
3323   // instead of accessing the local property.
3324   Local<Value> result =
3325       CompileRun("function get_x(o) { return o.x; };"
3326                  "var obj = { x : 42, y : 0 };"
3327                  "delete obj.y;"
3328                  "for (var i = 0; i < 10; i++) get_x(obj);"
3329                  "interceptor_obj.x = 42;"
3330                  "interceptor_obj.y = 10;"
3331                  "delete interceptor_obj.y;"
3332                  "get_x(interceptor_obj)");
3333   CHECK_EQ(result, v8_str("x"));
3334 }
3335 
3336 
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext)3337 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3338   v8::HandleScope scope;
3339 
3340   v8::Persistent<Context> context1 = Context::New();
3341 
3342   context1->Enter();
3343   Local<ObjectTemplate> templ = ObjectTemplate::New();
3344   templ->SetNamedPropertyHandler(XPropertyGetter);
3345   // Create an object with a named interceptor.
3346   v8::Local<v8::Object> object = templ->NewInstance();
3347   context1->Global()->Set(v8_str("interceptor_obj"), object);
3348 
3349   // Force the object into the slow case.
3350   CompileRun("interceptor_obj.y = 0;"
3351              "delete interceptor_obj.y;");
3352   context1->Exit();
3353 
3354   {
3355     // Introduce the object into a different context.
3356     // Repeat named loads to exercise ICs.
3357     LocalContext context2;
3358     context2->Global()->Set(v8_str("interceptor_obj"), object);
3359     Local<Value> result =
3360       CompileRun("function get_x(o) { return o.x; }"
3361                  "interceptor_obj.x = 42;"
3362                  "for (var i=0; i != 10; i++) {"
3363                  "  get_x(interceptor_obj);"
3364                  "}"
3365                  "get_x(interceptor_obj)");
3366     // Check that the interceptor was actually invoked.
3367     CHECK_EQ(result, v8_str("x"));
3368   }
3369 
3370   // Return to the original context and force some object to the slow case
3371   // to cause the NormalizedMapCache to verify.
3372   context1->Enter();
3373   CompileRun("var obj = { x : 0 }; delete obj.x;");
3374   context1->Exit();
3375 
3376   context1.Dispose();
3377 }
3378 
3379 
SetXOnPrototypeGetter(Local<String> property,const AccessorInfo & info)3380 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3381                                                const AccessorInfo& info) {
3382   // Set x on the prototype object and do not handle the get request.
3383   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3384   proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3385   return v8::Handle<Value>();
3386 }
3387 
3388 
3389 // This is a regression test for http://crbug.com/20104. Map
3390 // transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead)3391 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3392   v8::HandleScope scope;
3393   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3394   Local<v8::ObjectTemplate> instance_template
3395       = function_template->InstanceTemplate();
3396   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3397   LocalContext context;
3398   context->Global()->Set(v8_str("F"), function_template->GetFunction());
3399   // Create an instance of F and introduce a map transition for x.
3400   CompileRun("var o = new F(); o.x = 23;");
3401   // Create an instance of F and invoke the getter. The result should be 23.
3402   Local<Value> result = CompileRun("o = new F(); o.x");
3403   CHECK_EQ(result->Int32Value(), 23);
3404 }
3405 
3406 
IndexedPropertyGetter(uint32_t index,const AccessorInfo & info)3407 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3408                                                const AccessorInfo& info) {
3409   ApiTestFuzzer::Fuzz();
3410   if (index == 37) {
3411     return v8::Handle<Value>(v8_num(625));
3412   }
3413   return v8::Handle<Value>();
3414 }
3415 
3416 
IndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)3417 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3418                                                Local<Value> value,
3419                                                const AccessorInfo& info) {
3420   ApiTestFuzzer::Fuzz();
3421   if (index == 39) {
3422     return value;
3423   }
3424   return v8::Handle<Value>();
3425 }
3426 
3427 
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)3428 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3429   v8::HandleScope scope;
3430   Local<ObjectTemplate> templ = ObjectTemplate::New();
3431   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3432                                    IndexedPropertySetter);
3433   LocalContext context;
3434   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3435   Local<Script> getter_script = Script::Compile(v8_str(
3436       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3437   Local<Script> setter_script = Script::Compile(v8_str(
3438       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3439       "obj[17] = 23;"
3440       "obj.foo;"));
3441   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3442       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3443       "obj[39] = 47;"
3444       "obj.foo;"));  // This setter should not run, due to the interceptor.
3445   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3446       "obj[37];"));
3447   Local<Value> result = getter_script->Run();
3448   CHECK_EQ(v8_num(5), result);
3449   result = setter_script->Run();
3450   CHECK_EQ(v8_num(23), result);
3451   result = interceptor_setter_script->Run();
3452   CHECK_EQ(v8_num(23), result);
3453   result = interceptor_getter_script->Run();
3454   CHECK_EQ(v8_num(625), result);
3455 }
3456 
3457 
IdentityIndexedPropertyGetter(uint32_t index,const AccessorInfo & info)3458 static v8::Handle<Value> IdentityIndexedPropertyGetter(
3459     uint32_t index,
3460     const AccessorInfo& info) {
3461   return v8::Integer::NewFromUnsigned(index);
3462 }
3463 
3464 
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor)3465 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3466   v8::HandleScope scope;
3467   Local<ObjectTemplate> templ = ObjectTemplate::New();
3468   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3469 
3470   LocalContext context;
3471   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3472 
3473   // Check fast object case.
3474   const char* fast_case_code =
3475       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3476   ExpectString(fast_case_code, "0");
3477 
3478   // Check slow case.
3479   const char* slow_case_code =
3480       "obj.x = 1; delete obj.x;"
3481       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3482   ExpectString(slow_case_code, "1");
3483 }
3484 
3485 
THREADED_TEST(IndexedInterceptorWithNoSetter)3486 THREADED_TEST(IndexedInterceptorWithNoSetter) {
3487   v8::HandleScope scope;
3488   Local<ObjectTemplate> templ = ObjectTemplate::New();
3489   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3490 
3491   LocalContext context;
3492   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3493 
3494   const char* code =
3495       "try {"
3496       "  obj[0] = 239;"
3497       "  for (var i = 0; i < 100; i++) {"
3498       "    var v = obj[0];"
3499       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3500       "  }"
3501       "  'PASSED'"
3502       "} catch(e) {"
3503       "  e"
3504       "}";
3505   ExpectString(code, "PASSED");
3506 }
3507 
3508 
THREADED_TEST(IndexedInterceptorWithAccessorCheck)3509 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3510   v8::HandleScope scope;
3511   Local<ObjectTemplate> templ = ObjectTemplate::New();
3512   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3513 
3514   LocalContext context;
3515   Local<v8::Object> obj = templ->NewInstance();
3516   obj->TurnOnAccessCheck();
3517   context->Global()->Set(v8_str("obj"), obj);
3518 
3519   const char* code =
3520       "try {"
3521       "  for (var i = 0; i < 100; i++) {"
3522       "    var v = obj[0];"
3523       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3524       "  }"
3525       "  'PASSED'"
3526       "} catch(e) {"
3527       "  e"
3528       "}";
3529   ExpectString(code, "PASSED");
3530 }
3531 
3532 
THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn)3533 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3534   i::FLAG_allow_natives_syntax = true;
3535   v8::HandleScope scope;
3536   Local<ObjectTemplate> templ = ObjectTemplate::New();
3537   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3538 
3539   LocalContext context;
3540   Local<v8::Object> obj = templ->NewInstance();
3541   context->Global()->Set(v8_str("obj"), obj);
3542 
3543   const char* code =
3544       "try {"
3545       "  for (var i = 0; i < 100; i++) {"
3546       "    var expected = i;"
3547       "    if (i == 5) {"
3548       "      %EnableAccessChecks(obj);"
3549       "      expected = undefined;"
3550       "    }"
3551       "    var v = obj[i];"
3552       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3553       "    if (i == 5) %DisableAccessChecks(obj);"
3554       "  }"
3555       "  'PASSED'"
3556       "} catch(e) {"
3557       "  e"
3558       "}";
3559   ExpectString(code, "PASSED");
3560 }
3561 
3562 
THREADED_TEST(IndexedInterceptorWithDifferentIndices)3563 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3564   v8::HandleScope scope;
3565   Local<ObjectTemplate> templ = ObjectTemplate::New();
3566   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3567 
3568   LocalContext context;
3569   Local<v8::Object> obj = templ->NewInstance();
3570   context->Global()->Set(v8_str("obj"), obj);
3571 
3572   const char* code =
3573       "try {"
3574       "  for (var i = 0; i < 100; i++) {"
3575       "    var v = obj[i];"
3576       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3577       "  }"
3578       "  'PASSED'"
3579       "} catch(e) {"
3580       "  e"
3581       "}";
3582   ExpectString(code, "PASSED");
3583 }
3584 
3585 
THREADED_TEST(IndexedInterceptorWithNegativeIndices)3586 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3587   v8::HandleScope scope;
3588   Local<ObjectTemplate> templ = ObjectTemplate::New();
3589   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3590 
3591   LocalContext context;
3592   Local<v8::Object> obj = templ->NewInstance();
3593   context->Global()->Set(v8_str("obj"), obj);
3594 
3595   const char* code =
3596       "try {"
3597       "  for (var i = 0; i < 100; i++) {"
3598       "    var expected = i;"
3599       "    var key = i;"
3600       "    if (i == 25) {"
3601       "       key = -1;"
3602       "       expected = undefined;"
3603       "    }"
3604       "    if (i == 50) {"
3605       "       /* probe minimal Smi number on 32-bit platforms */"
3606       "       key = -(1 << 30);"
3607       "       expected = undefined;"
3608       "    }"
3609       "    if (i == 75) {"
3610       "       /* probe minimal Smi number on 64-bit platforms */"
3611       "       key = 1 << 31;"
3612       "       expected = undefined;"
3613       "    }"
3614       "    var v = obj[key];"
3615       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3616       "  }"
3617       "  'PASSED'"
3618       "} catch(e) {"
3619       "  e"
3620       "}";
3621   ExpectString(code, "PASSED");
3622 }
3623 
3624 
THREADED_TEST(IndexedInterceptorWithNotSmiLookup)3625 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3626   v8::HandleScope scope;
3627   Local<ObjectTemplate> templ = ObjectTemplate::New();
3628   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3629 
3630   LocalContext context;
3631   Local<v8::Object> obj = templ->NewInstance();
3632   context->Global()->Set(v8_str("obj"), obj);
3633 
3634   const char* code =
3635       "try {"
3636       "  for (var i = 0; i < 100; i++) {"
3637       "    var expected = i;"
3638       "    var key = i;"
3639       "    if (i == 50) {"
3640       "       key = 'foobar';"
3641       "       expected = undefined;"
3642       "    }"
3643       "    var v = obj[key];"
3644       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3645       "  }"
3646       "  'PASSED'"
3647       "} catch(e) {"
3648       "  e"
3649       "}";
3650   ExpectString(code, "PASSED");
3651 }
3652 
3653 
THREADED_TEST(IndexedInterceptorGoingMegamorphic)3654 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3655   v8::HandleScope scope;
3656   Local<ObjectTemplate> templ = ObjectTemplate::New();
3657   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3658 
3659   LocalContext context;
3660   Local<v8::Object> obj = templ->NewInstance();
3661   context->Global()->Set(v8_str("obj"), obj);
3662 
3663   const char* code =
3664       "var original = obj;"
3665       "try {"
3666       "  for (var i = 0; i < 100; i++) {"
3667       "    var expected = i;"
3668       "    if (i == 50) {"
3669       "       obj = {50: 'foobar'};"
3670       "       expected = 'foobar';"
3671       "    }"
3672       "    var v = obj[i];"
3673       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3674       "    if (i == 50) obj = original;"
3675       "  }"
3676       "  'PASSED'"
3677       "} catch(e) {"
3678       "  e"
3679       "}";
3680   ExpectString(code, "PASSED");
3681 }
3682 
3683 
THREADED_TEST(IndexedInterceptorReceiverTurningSmi)3684 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3685   v8::HandleScope scope;
3686   Local<ObjectTemplate> templ = ObjectTemplate::New();
3687   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3688 
3689   LocalContext context;
3690   Local<v8::Object> obj = templ->NewInstance();
3691   context->Global()->Set(v8_str("obj"), obj);
3692 
3693   const char* code =
3694       "var original = obj;"
3695       "try {"
3696       "  for (var i = 0; i < 100; i++) {"
3697       "    var expected = i;"
3698       "    if (i == 5) {"
3699       "       obj = 239;"
3700       "       expected = undefined;"
3701       "    }"
3702       "    var v = obj[i];"
3703       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3704       "    if (i == 5) obj = original;"
3705       "  }"
3706       "  'PASSED'"
3707       "} catch(e) {"
3708       "  e"
3709       "}";
3710   ExpectString(code, "PASSED");
3711 }
3712 
3713 
THREADED_TEST(IndexedInterceptorOnProto)3714 THREADED_TEST(IndexedInterceptorOnProto) {
3715   v8::HandleScope scope;
3716   Local<ObjectTemplate> templ = ObjectTemplate::New();
3717   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3718 
3719   LocalContext context;
3720   Local<v8::Object> obj = templ->NewInstance();
3721   context->Global()->Set(v8_str("obj"), obj);
3722 
3723   const char* code =
3724       "var o = {__proto__: obj};"
3725       "try {"
3726       "  for (var i = 0; i < 100; i++) {"
3727       "    var v = o[i];"
3728       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3729       "  }"
3730       "  'PASSED'"
3731       "} catch(e) {"
3732       "  e"
3733       "}";
3734   ExpectString(code, "PASSED");
3735 }
3736 
3737 
THREADED_TEST(MultiContexts)3738 THREADED_TEST(MultiContexts) {
3739   v8::HandleScope scope;
3740   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3741   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3742 
3743   Local<String> password = v8_str("Password");
3744 
3745   // Create an environment
3746   LocalContext context0(0, templ);
3747   context0->SetSecurityToken(password);
3748   v8::Handle<v8::Object> global0 = context0->Global();
3749   global0->Set(v8_str("custom"), v8_num(1234));
3750   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3751 
3752   // Create an independent environment
3753   LocalContext context1(0, templ);
3754   context1->SetSecurityToken(password);
3755   v8::Handle<v8::Object> global1 = context1->Global();
3756   global1->Set(v8_str("custom"), v8_num(1234));
3757   CHECK_NE(global0, global1);
3758   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3759   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3760 
3761   // Now create a new context with the old global
3762   LocalContext context2(0, templ, global1);
3763   context2->SetSecurityToken(password);
3764   v8::Handle<v8::Object> global2 = context2->Global();
3765   CHECK_EQ(global1, global2);
3766   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3767   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3768 }
3769 
3770 
THREADED_TEST(FunctionPrototypeAcrossContexts)3771 THREADED_TEST(FunctionPrototypeAcrossContexts) {
3772   // Make sure that functions created by cloning boilerplates cannot
3773   // communicate through their __proto__ field.
3774 
3775   v8::HandleScope scope;
3776 
3777   LocalContext env0;
3778   v8::Handle<v8::Object> global0 =
3779       env0->Global();
3780   v8::Handle<v8::Object> object0 =
3781       global0->Get(v8_str("Object")).As<v8::Object>();
3782   v8::Handle<v8::Object> tostring0 =
3783       object0->Get(v8_str("toString")).As<v8::Object>();
3784   v8::Handle<v8::Object> proto0 =
3785       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3786   proto0->Set(v8_str("custom"), v8_num(1234));
3787 
3788   LocalContext env1;
3789   v8::Handle<v8::Object> global1 =
3790       env1->Global();
3791   v8::Handle<v8::Object> object1 =
3792       global1->Get(v8_str("Object")).As<v8::Object>();
3793   v8::Handle<v8::Object> tostring1 =
3794       object1->Get(v8_str("toString")).As<v8::Object>();
3795   v8::Handle<v8::Object> proto1 =
3796       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3797   CHECK(!proto1->Has(v8_str("custom")));
3798 }
3799 
3800 
THREADED_TEST(Regress892105)3801 THREADED_TEST(Regress892105) {
3802   // Make sure that object and array literals created by cloning
3803   // boilerplates cannot communicate through their __proto__
3804   // field. This is rather difficult to check, but we try to add stuff
3805   // to Object.prototype and Array.prototype and create a new
3806   // environment. This should succeed.
3807 
3808   v8::HandleScope scope;
3809 
3810   Local<String> source = v8_str("Object.prototype.obj = 1234;"
3811                                 "Array.prototype.arr = 4567;"
3812                                 "8901");
3813 
3814   LocalContext env0;
3815   Local<Script> script0 = Script::Compile(source);
3816   CHECK_EQ(8901.0, script0->Run()->NumberValue());
3817 
3818   LocalContext env1;
3819   Local<Script> script1 = Script::Compile(source);
3820   CHECK_EQ(8901.0, script1->Run()->NumberValue());
3821 }
3822 
3823 
THREADED_TEST(UndetectableObject)3824 THREADED_TEST(UndetectableObject) {
3825   v8::HandleScope scope;
3826   LocalContext env;
3827 
3828   Local<v8::FunctionTemplate> desc =
3829       v8::FunctionTemplate::New(0, v8::Handle<Value>());
3830   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3831 
3832   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3833   env->Global()->Set(v8_str("undetectable"), obj);
3834 
3835   ExpectString("undetectable.toString()", "[object Object]");
3836   ExpectString("typeof undetectable", "undefined");
3837   ExpectString("typeof(undetectable)", "undefined");
3838   ExpectBoolean("typeof undetectable == 'undefined'", true);
3839   ExpectBoolean("typeof undetectable == 'object'", false);
3840   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3841   ExpectBoolean("!undetectable", true);
3842 
3843   ExpectObject("true&&undetectable", obj);
3844   ExpectBoolean("false&&undetectable", false);
3845   ExpectBoolean("true||undetectable", true);
3846   ExpectObject("false||undetectable", obj);
3847 
3848   ExpectObject("undetectable&&true", obj);
3849   ExpectObject("undetectable&&false", obj);
3850   ExpectBoolean("undetectable||true", true);
3851   ExpectBoolean("undetectable||false", false);
3852 
3853   ExpectBoolean("undetectable==null", true);
3854   ExpectBoolean("null==undetectable", true);
3855   ExpectBoolean("undetectable==undefined", true);
3856   ExpectBoolean("undefined==undetectable", true);
3857   ExpectBoolean("undetectable==undetectable", true);
3858 
3859 
3860   ExpectBoolean("undetectable===null", false);
3861   ExpectBoolean("null===undetectable", false);
3862   ExpectBoolean("undetectable===undefined", false);
3863   ExpectBoolean("undefined===undetectable", false);
3864   ExpectBoolean("undetectable===undetectable", true);
3865 }
3866 
3867 
3868 
THREADED_TEST(ExtensibleOnUndetectable)3869 THREADED_TEST(ExtensibleOnUndetectable) {
3870   v8::HandleScope scope;
3871   LocalContext env;
3872 
3873   Local<v8::FunctionTemplate> desc =
3874       v8::FunctionTemplate::New(0, v8::Handle<Value>());
3875   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3876 
3877   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3878   env->Global()->Set(v8_str("undetectable"), obj);
3879 
3880   Local<String> source = v8_str("undetectable.x = 42;"
3881                                 "undetectable.x");
3882 
3883   Local<Script> script = Script::Compile(source);
3884 
3885   CHECK_EQ(v8::Integer::New(42), script->Run());
3886 
3887   ExpectBoolean("Object.isExtensible(undetectable)", true);
3888 
3889   source = v8_str("Object.preventExtensions(undetectable);");
3890   script = Script::Compile(source);
3891   script->Run();
3892   ExpectBoolean("Object.isExtensible(undetectable)", false);
3893 
3894   source = v8_str("undetectable.y = 2000;");
3895   script = Script::Compile(source);
3896   Local<Value> result = script->Run();
3897   ExpectBoolean("undetectable.y == undefined", true);
3898 }
3899 
3900 
3901 
THREADED_TEST(UndetectableString)3902 THREADED_TEST(UndetectableString) {
3903   v8::HandleScope scope;
3904   LocalContext env;
3905 
3906   Local<String> obj = String::NewUndetectable("foo");
3907   env->Global()->Set(v8_str("undetectable"), obj);
3908 
3909   ExpectString("undetectable", "foo");
3910   ExpectString("typeof undetectable", "undefined");
3911   ExpectString("typeof(undetectable)", "undefined");
3912   ExpectBoolean("typeof undetectable == 'undefined'", true);
3913   ExpectBoolean("typeof undetectable == 'string'", false);
3914   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3915   ExpectBoolean("!undetectable", true);
3916 
3917   ExpectObject("true&&undetectable", obj);
3918   ExpectBoolean("false&&undetectable", false);
3919   ExpectBoolean("true||undetectable", true);
3920   ExpectObject("false||undetectable", obj);
3921 
3922   ExpectObject("undetectable&&true", obj);
3923   ExpectObject("undetectable&&false", obj);
3924   ExpectBoolean("undetectable||true", true);
3925   ExpectBoolean("undetectable||false", false);
3926 
3927   ExpectBoolean("undetectable==null", true);
3928   ExpectBoolean("null==undetectable", true);
3929   ExpectBoolean("undetectable==undefined", true);
3930   ExpectBoolean("undefined==undetectable", true);
3931   ExpectBoolean("undetectable==undetectable", true);
3932 
3933 
3934   ExpectBoolean("undetectable===null", false);
3935   ExpectBoolean("null===undetectable", false);
3936   ExpectBoolean("undetectable===undefined", false);
3937   ExpectBoolean("undefined===undetectable", false);
3938   ExpectBoolean("undetectable===undetectable", true);
3939 }
3940 
3941 
USE(T)3942 template <typename T> static void USE(T) { }
3943 
3944 
3945 // This test is not intended to be run, just type checked.
PersistentHandles()3946 static void PersistentHandles() {
3947   USE(PersistentHandles);
3948   Local<String> str = v8_str("foo");
3949   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3950   USE(p_str);
3951   Local<Script> scr = Script::Compile(v8_str(""));
3952   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3953   USE(p_scr);
3954   Local<ObjectTemplate> templ = ObjectTemplate::New();
3955   v8::Persistent<ObjectTemplate> p_templ =
3956     v8::Persistent<ObjectTemplate>::New(templ);
3957   USE(p_templ);
3958 }
3959 
3960 
HandleLogDelegator(const v8::Arguments & args)3961 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3962   ApiTestFuzzer::Fuzz();
3963   return v8::Undefined();
3964 }
3965 
3966 
THREADED_TEST(GlobalObjectTemplate)3967 THREADED_TEST(GlobalObjectTemplate) {
3968   v8::HandleScope handle_scope;
3969   Local<ObjectTemplate> global_template = ObjectTemplate::New();
3970   global_template->Set(v8_str("JSNI_Log"),
3971                        v8::FunctionTemplate::New(HandleLogDelegator));
3972   v8::Persistent<Context> context = Context::New(0, global_template);
3973   Context::Scope context_scope(context);
3974   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3975   context.Dispose();
3976 }
3977 
3978 
3979 static const char* kSimpleExtensionSource =
3980   "function Foo() {"
3981   "  return 4;"
3982   "}";
3983 
3984 
THREADED_TEST(SimpleExtensions)3985 THREADED_TEST(SimpleExtensions) {
3986   v8::HandleScope handle_scope;
3987   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3988   const char* extension_names[] = { "simpletest" };
3989   v8::ExtensionConfiguration extensions(1, extension_names);
3990   v8::Handle<Context> context = Context::New(&extensions);
3991   Context::Scope lock(context);
3992   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3993   CHECK_EQ(result, v8::Integer::New(4));
3994 }
3995 
3996 
3997 static const char* kEvalExtensionSource1 =
3998   "function UseEval1() {"
3999   "  var x = 42;"
4000   "  return eval('x');"
4001   "}";
4002 
4003 
4004 static const char* kEvalExtensionSource2 =
4005   "(function() {"
4006   "  var x = 42;"
4007   "  function e() {"
4008   "    return eval('x');"
4009   "  }"
4010   "  this.UseEval2 = e;"
4011   "})()";
4012 
4013 
THREADED_TEST(UseEvalFromExtension)4014 THREADED_TEST(UseEvalFromExtension) {
4015   v8::HandleScope handle_scope;
4016   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4017   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4018   const char* extension_names[] = { "evaltest1", "evaltest2" };
4019   v8::ExtensionConfiguration extensions(2, extension_names);
4020   v8::Handle<Context> context = Context::New(&extensions);
4021   Context::Scope lock(context);
4022   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4023   CHECK_EQ(result, v8::Integer::New(42));
4024   result = Script::Compile(v8_str("UseEval2()"))->Run();
4025   CHECK_EQ(result, v8::Integer::New(42));
4026 }
4027 
4028 
4029 static const char* kWithExtensionSource1 =
4030   "function UseWith1() {"
4031   "  var x = 42;"
4032   "  with({x:87}) { return x; }"
4033   "}";
4034 
4035 
4036 
4037 static const char* kWithExtensionSource2 =
4038   "(function() {"
4039   "  var x = 42;"
4040   "  function e() {"
4041   "    with ({x:87}) { return x; }"
4042   "  }"
4043   "  this.UseWith2 = e;"
4044   "})()";
4045 
4046 
THREADED_TEST(UseWithFromExtension)4047 THREADED_TEST(UseWithFromExtension) {
4048   v8::HandleScope handle_scope;
4049   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4050   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4051   const char* extension_names[] = { "withtest1", "withtest2" };
4052   v8::ExtensionConfiguration extensions(2, extension_names);
4053   v8::Handle<Context> context = Context::New(&extensions);
4054   Context::Scope lock(context);
4055   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4056   CHECK_EQ(result, v8::Integer::New(87));
4057   result = Script::Compile(v8_str("UseWith2()"))->Run();
4058   CHECK_EQ(result, v8::Integer::New(87));
4059 }
4060 
4061 
THREADED_TEST(AutoExtensions)4062 THREADED_TEST(AutoExtensions) {
4063   v8::HandleScope handle_scope;
4064   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4065   extension->set_auto_enable(true);
4066   v8::RegisterExtension(extension);
4067   v8::Handle<Context> context = Context::New();
4068   Context::Scope lock(context);
4069   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4070   CHECK_EQ(result, v8::Integer::New(4));
4071 }
4072 
4073 
4074 static const char* kSyntaxErrorInExtensionSource =
4075     "[";
4076 
4077 
4078 // Test that a syntax error in an extension does not cause a fatal
4079 // error but results in an empty context.
THREADED_TEST(SyntaxErrorExtensions)4080 THREADED_TEST(SyntaxErrorExtensions) {
4081   v8::HandleScope handle_scope;
4082   v8::RegisterExtension(new Extension("syntaxerror",
4083                                       kSyntaxErrorInExtensionSource));
4084   const char* extension_names[] = { "syntaxerror" };
4085   v8::ExtensionConfiguration extensions(1, extension_names);
4086   v8::Handle<Context> context = Context::New(&extensions);
4087   CHECK(context.IsEmpty());
4088 }
4089 
4090 
4091 static const char* kExceptionInExtensionSource =
4092     "throw 42";
4093 
4094 
4095 // Test that an exception when installing an extension does not cause
4096 // a fatal error but results in an empty context.
THREADED_TEST(ExceptionExtensions)4097 THREADED_TEST(ExceptionExtensions) {
4098   v8::HandleScope handle_scope;
4099   v8::RegisterExtension(new Extension("exception",
4100                                       kExceptionInExtensionSource));
4101   const char* extension_names[] = { "exception" };
4102   v8::ExtensionConfiguration extensions(1, extension_names);
4103   v8::Handle<Context> context = Context::New(&extensions);
4104   CHECK(context.IsEmpty());
4105 }
4106 
4107 
4108 static const char* kNativeCallInExtensionSource =
4109     "function call_runtime_last_index_of(x) {"
4110     "  return %StringLastIndexOf(x, 'bob', 10);"
4111     "}";
4112 
4113 
4114 static const char* kNativeCallTest =
4115     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4116 
4117 // Test that a native runtime calls are supported in extensions.
THREADED_TEST(NativeCallInExtensions)4118 THREADED_TEST(NativeCallInExtensions) {
4119   v8::HandleScope handle_scope;
4120   v8::RegisterExtension(new Extension("nativecall",
4121                                       kNativeCallInExtensionSource));
4122   const char* extension_names[] = { "nativecall" };
4123   v8::ExtensionConfiguration extensions(1, extension_names);
4124   v8::Handle<Context> context = Context::New(&extensions);
4125   Context::Scope lock(context);
4126   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4127   CHECK_EQ(result, v8::Integer::New(3));
4128 }
4129 
4130 
CheckDependencies(const char * name,const char * expected)4131 static void CheckDependencies(const char* name, const char* expected) {
4132   v8::HandleScope handle_scope;
4133   v8::ExtensionConfiguration config(1, &name);
4134   LocalContext context(&config);
4135   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4136 }
4137 
4138 
4139 /*
4140  * Configuration:
4141  *
4142  *     /-- B <--\
4143  * A <-          -- D <-- E
4144  *     \-- C <--/
4145  */
THREADED_TEST(ExtensionDependency)4146 THREADED_TEST(ExtensionDependency) {
4147   static const char* kEDeps[] = { "D" };
4148   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4149   static const char* kDDeps[] = { "B", "C" };
4150   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4151   static const char* kBCDeps[] = { "A" };
4152   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4153   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4154   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4155   CheckDependencies("A", "undefinedA");
4156   CheckDependencies("B", "undefinedAB");
4157   CheckDependencies("C", "undefinedAC");
4158   CheckDependencies("D", "undefinedABCD");
4159   CheckDependencies("E", "undefinedABCDE");
4160   v8::HandleScope handle_scope;
4161   static const char* exts[2] = { "C", "E" };
4162   v8::ExtensionConfiguration config(2, exts);
4163   LocalContext context(&config);
4164   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4165 }
4166 
4167 
4168 static const char* kExtensionTestScript =
4169   "native function A();"
4170   "native function B();"
4171   "native function C();"
4172   "function Foo(i) {"
4173   "  if (i == 0) return A();"
4174   "  if (i == 1) return B();"
4175   "  if (i == 2) return C();"
4176   "}";
4177 
4178 
CallFun(const v8::Arguments & args)4179 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4180   ApiTestFuzzer::Fuzz();
4181   if (args.IsConstructCall()) {
4182     args.This()->Set(v8_str("data"), args.Data());
4183     return v8::Null();
4184   }
4185   return args.Data();
4186 }
4187 
4188 
4189 class FunctionExtension : public Extension {
4190  public:
FunctionExtension()4191   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4192   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4193       v8::Handle<String> name);
4194 };
4195 
4196 
4197 static int lookup_count = 0;
GetNativeFunction(v8::Handle<String> name)4198 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4199       v8::Handle<String> name) {
4200   lookup_count++;
4201   if (name->Equals(v8_str("A"))) {
4202     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4203   } else if (name->Equals(v8_str("B"))) {
4204     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4205   } else if (name->Equals(v8_str("C"))) {
4206     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4207   } else {
4208     return v8::Handle<v8::FunctionTemplate>();
4209   }
4210 }
4211 
4212 
THREADED_TEST(FunctionLookup)4213 THREADED_TEST(FunctionLookup) {
4214   v8::RegisterExtension(new FunctionExtension());
4215   v8::HandleScope handle_scope;
4216   static const char* exts[1] = { "functiontest" };
4217   v8::ExtensionConfiguration config(1, exts);
4218   LocalContext context(&config);
4219   CHECK_EQ(3, lookup_count);
4220   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4221   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4222   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4223 }
4224 
4225 
THREADED_TEST(NativeFunctionConstructCall)4226 THREADED_TEST(NativeFunctionConstructCall) {
4227   v8::RegisterExtension(new FunctionExtension());
4228   v8::HandleScope handle_scope;
4229   static const char* exts[1] = { "functiontest" };
4230   v8::ExtensionConfiguration config(1, exts);
4231   LocalContext context(&config);
4232   for (int i = 0; i < 10; i++) {
4233     // Run a few times to ensure that allocation of objects doesn't
4234     // change behavior of a constructor function.
4235     CHECK_EQ(v8::Integer::New(8),
4236              Script::Compile(v8_str("(new A()).data"))->Run());
4237     CHECK_EQ(v8::Integer::New(7),
4238              Script::Compile(v8_str("(new B()).data"))->Run());
4239     CHECK_EQ(v8::Integer::New(6),
4240              Script::Compile(v8_str("(new C()).data"))->Run());
4241   }
4242 }
4243 
4244 
4245 static const char* last_location;
4246 static const char* last_message;
StoringErrorCallback(const char * location,const char * message)4247 void StoringErrorCallback(const char* location, const char* message) {
4248   if (last_location == NULL) {
4249     last_location = location;
4250     last_message = message;
4251   }
4252 }
4253 
4254 
4255 // ErrorReporting creates a circular extensions configuration and
4256 // tests that the fatal error handler gets called.  This renders V8
4257 // unusable and therefore this test cannot be run in parallel.
TEST(ErrorReporting)4258 TEST(ErrorReporting) {
4259   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4260   static const char* aDeps[] = { "B" };
4261   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4262   static const char* bDeps[] = { "A" };
4263   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4264   last_location = NULL;
4265   v8::ExtensionConfiguration config(1, bDeps);
4266   v8::Handle<Context> context = Context::New(&config);
4267   CHECK(context.IsEmpty());
4268   CHECK_NE(last_location, NULL);
4269 }
4270 
4271 
4272 static const char* js_code_causing_huge_string_flattening =
4273     "var str = 'X';"
4274     "for (var i = 0; i < 30; i++) {"
4275     "  str = str + str;"
4276     "}"
4277     "str.match(/X/);";
4278 
4279 
OOMCallback(const char * location,const char * message)4280 void OOMCallback(const char* location, const char* message) {
4281   exit(0);
4282 }
4283 
4284 
TEST(RegexpOutOfMemory)4285 TEST(RegexpOutOfMemory) {
4286   // Execute a script that causes out of memory when flattening a string.
4287   v8::HandleScope scope;
4288   v8::V8::SetFatalErrorHandler(OOMCallback);
4289   LocalContext context;
4290   Local<Script> script =
4291       Script::Compile(String::New(js_code_causing_huge_string_flattening));
4292   last_location = NULL;
4293   Local<Value> result = script->Run();
4294 
4295   CHECK(false);  // Should not return.
4296 }
4297 
4298 
MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,v8::Handle<Value> data)4299 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4300                                              v8::Handle<Value> data) {
4301   CHECK_EQ(v8::Undefined(), data);
4302   CHECK(message->GetScriptResourceName()->IsUndefined());
4303   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4304   message->GetLineNumber();
4305   message->GetSourceLine();
4306 }
4307 
4308 
THREADED_TEST(ErrorWithMissingScriptInfo)4309 THREADED_TEST(ErrorWithMissingScriptInfo) {
4310   v8::HandleScope scope;
4311   LocalContext context;
4312   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4313   Script::Compile(v8_str("throw Error()"))->Run();
4314   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4315 }
4316 
4317 
4318 int global_index = 0;
4319 
4320 class Snorkel {
4321  public:
Snorkel()4322   Snorkel() { index_ = global_index++; }
4323   int index_;
4324 };
4325 
4326 class Whammy {
4327  public:
Whammy()4328   Whammy() {
4329     cursor_ = 0;
4330   }
~Whammy()4331   ~Whammy() {
4332     script_.Dispose();
4333   }
getScript()4334   v8::Handle<Script> getScript() {
4335     if (script_.IsEmpty())
4336       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4337     return Local<Script>(*script_);
4338   }
4339 
4340  public:
4341   static const int kObjectCount = 256;
4342   int cursor_;
4343   v8::Persistent<v8::Object> objects_[kObjectCount];
4344   v8::Persistent<Script> script_;
4345 };
4346 
HandleWeakReference(v8::Persistent<v8::Value> obj,void * data)4347 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4348   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4349   delete snorkel;
4350   obj.ClearWeak();
4351 }
4352 
WhammyPropertyGetter(Local<String> name,const AccessorInfo & info)4353 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4354                                        const AccessorInfo& info) {
4355   Whammy* whammy =
4356     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4357 
4358   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4359 
4360   v8::Handle<v8::Object> obj = v8::Object::New();
4361   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4362   if (!prev.IsEmpty()) {
4363     prev->Set(v8_str("next"), obj);
4364     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4365     whammy->objects_[whammy->cursor_].Clear();
4366   }
4367   whammy->objects_[whammy->cursor_] = global;
4368   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4369   return whammy->getScript()->Run();
4370 }
4371 
THREADED_TEST(WeakReference)4372 THREADED_TEST(WeakReference) {
4373   v8::HandleScope handle_scope;
4374   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
4375   Whammy* whammy = new Whammy();
4376   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4377                                  0, 0, 0, 0,
4378                                  v8::External::New(whammy));
4379   const char* extension_list[] = { "v8/gc" };
4380   v8::ExtensionConfiguration extensions(1, extension_list);
4381   v8::Persistent<Context> context = Context::New(&extensions);
4382   Context::Scope context_scope(context);
4383 
4384   v8::Handle<v8::Object> interceptor = templ->NewInstance();
4385   context->Global()->Set(v8_str("whammy"), interceptor);
4386   const char* code =
4387       "var last;"
4388       "for (var i = 0; i < 10000; i++) {"
4389       "  var obj = whammy.length;"
4390       "  if (last) last.next = obj;"
4391       "  last = obj;"
4392       "}"
4393       "gc();"
4394       "4";
4395   v8::Handle<Value> result = CompileRun(code);
4396   CHECK_EQ(4.0, result->NumberValue());
4397   delete whammy;
4398   context.Dispose();
4399 }
4400 
4401 
4402 static bool in_scavenge = false;
4403 static int last = -1;
4404 
ForceScavenge(v8::Persistent<v8::Value> obj,void * data)4405 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4406   CHECK_EQ(-1, last);
4407   last = 0;
4408   obj.Dispose();
4409   obj.Clear();
4410   in_scavenge = true;
4411   HEAP->PerformScavenge();
4412   in_scavenge = false;
4413   *(reinterpret_cast<bool*>(data)) = true;
4414 }
4415 
CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,void * data)4416 static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4417                                         void* data) {
4418   CHECK_EQ(0, last);
4419   last = 1;
4420   *(reinterpret_cast<bool*>(data)) = in_scavenge;
4421   obj.Dispose();
4422   obj.Clear();
4423 }
4424 
THREADED_TEST(NoWeakRefCallbacksInScavenge)4425 THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4426   // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4427   // Calling callbacks from scavenges is unsafe as objects held by those
4428   // handlers might have become strongly reachable, but scavenge doesn't
4429   // check that.
4430   v8::Persistent<Context> context = Context::New();
4431   Context::Scope context_scope(context);
4432 
4433   v8::Persistent<v8::Object> object_a;
4434   v8::Persistent<v8::Object> object_b;
4435 
4436   {
4437     v8::HandleScope handle_scope;
4438     object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4439     object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4440   }
4441 
4442   bool object_a_disposed = false;
4443   object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4444   bool released_in_scavenge = false;
4445   object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4446 
4447   while (!object_a_disposed) {
4448     HEAP->CollectAllGarbage(false);
4449   }
4450   CHECK(!released_in_scavenge);
4451 }
4452 
4453 
4454 v8::Handle<Function> args_fun;
4455 
4456 
ArgumentsTestCallback(const v8::Arguments & args)4457 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4458   ApiTestFuzzer::Fuzz();
4459   CHECK_EQ(args_fun, args.Callee());
4460   CHECK_EQ(3, args.Length());
4461   CHECK_EQ(v8::Integer::New(1), args[0]);
4462   CHECK_EQ(v8::Integer::New(2), args[1]);
4463   CHECK_EQ(v8::Integer::New(3), args[2]);
4464   CHECK_EQ(v8::Undefined(), args[3]);
4465   v8::HandleScope scope;
4466   HEAP->CollectAllGarbage(false);
4467   return v8::Undefined();
4468 }
4469 
4470 
THREADED_TEST(Arguments)4471 THREADED_TEST(Arguments) {
4472   v8::HandleScope scope;
4473   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4474   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4475   LocalContext context(NULL, global);
4476   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
4477   v8_compile("f(1, 2, 3)")->Run();
4478 }
4479 
4480 
NoBlockGetterX(Local<String> name,const AccessorInfo &)4481 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4482                                         const AccessorInfo&) {
4483   return v8::Handle<Value>();
4484 }
4485 
4486 
NoBlockGetterI(uint32_t index,const AccessorInfo &)4487 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4488                                         const AccessorInfo&) {
4489   return v8::Handle<Value>();
4490 }
4491 
4492 
PDeleter(Local<String> name,const AccessorInfo &)4493 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4494                                         const AccessorInfo&) {
4495   if (!name->Equals(v8_str("foo"))) {
4496     return v8::Handle<v8::Boolean>();  // not intercepted
4497   }
4498 
4499   return v8::False();  // intercepted, and don't delete the property
4500 }
4501 
4502 
IDeleter(uint32_t index,const AccessorInfo &)4503 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4504   if (index != 2) {
4505     return v8::Handle<v8::Boolean>();  // not intercepted
4506   }
4507 
4508   return v8::False();  // intercepted, and don't delete the property
4509 }
4510 
4511 
THREADED_TEST(Deleter)4512 THREADED_TEST(Deleter) {
4513   v8::HandleScope scope;
4514   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4515   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4516   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4517   LocalContext context;
4518   context->Global()->Set(v8_str("k"), obj->NewInstance());
4519   CompileRun(
4520     "k.foo = 'foo';"
4521     "k.bar = 'bar';"
4522     "k[2] = 2;"
4523     "k[4] = 4;");
4524   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4525   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4526 
4527   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4528   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4529 
4530   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4531   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4532 
4533   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4534   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4535 }
4536 
4537 
GetK(Local<String> name,const AccessorInfo &)4538 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4539   ApiTestFuzzer::Fuzz();
4540   if (name->Equals(v8_str("foo")) ||
4541       name->Equals(v8_str("bar")) ||
4542       name->Equals(v8_str("baz"))) {
4543     return v8::Undefined();
4544   }
4545   return v8::Handle<Value>();
4546 }
4547 
4548 
IndexedGetK(uint32_t index,const AccessorInfo &)4549 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4550   ApiTestFuzzer::Fuzz();
4551   if (index == 0 || index == 1) return v8::Undefined();
4552   return v8::Handle<Value>();
4553 }
4554 
4555 
NamedEnum(const AccessorInfo &)4556 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4557   ApiTestFuzzer::Fuzz();
4558   v8::Handle<v8::Array> result = v8::Array::New(3);
4559   result->Set(v8::Integer::New(0), v8_str("foo"));
4560   result->Set(v8::Integer::New(1), v8_str("bar"));
4561   result->Set(v8::Integer::New(2), v8_str("baz"));
4562   return result;
4563 }
4564 
4565 
IndexedEnum(const AccessorInfo &)4566 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4567   ApiTestFuzzer::Fuzz();
4568   v8::Handle<v8::Array> result = v8::Array::New(2);
4569   result->Set(v8::Integer::New(0), v8_str("0"));
4570   result->Set(v8::Integer::New(1), v8_str("1"));
4571   return result;
4572 }
4573 
4574 
THREADED_TEST(Enumerators)4575 THREADED_TEST(Enumerators) {
4576   v8::HandleScope scope;
4577   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4578   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4579   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4580   LocalContext context;
4581   context->Global()->Set(v8_str("k"), obj->NewInstance());
4582   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4583     "k[10] = 0;"
4584     "k.a = 0;"
4585     "k[5] = 0;"
4586     "k.b = 0;"
4587     "k[4294967295] = 0;"
4588     "k.c = 0;"
4589     "k[4294967296] = 0;"
4590     "k.d = 0;"
4591     "k[140000] = 0;"
4592     "k.e = 0;"
4593     "k[30000000000] = 0;"
4594     "k.f = 0;"
4595     "var result = [];"
4596     "for (var prop in k) {"
4597     "  result.push(prop);"
4598     "}"
4599     "result"));
4600   // Check that we get all the property names returned including the
4601   // ones from the enumerators in the right order: indexed properties
4602   // in numerical order, indexed interceptor properties, named
4603   // properties in insertion order, named interceptor properties.
4604   // This order is not mandated by the spec, so this test is just
4605   // documenting our behavior.
4606   CHECK_EQ(17, result->Length());
4607   // Indexed properties in numerical order.
4608   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4609   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4610   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4611   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4612   // Indexed interceptor properties in the order they are returned
4613   // from the enumerator interceptor.
4614   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4615   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4616   // Named properties in insertion order.
4617   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4618   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4619   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4620   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4621   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4622   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4623   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4624   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4625   // Named interceptor properties.
4626   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4627   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4628   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4629 }
4630 
4631 
4632 int p_getter_count;
4633 int p_getter_count2;
4634 
4635 
PGetter(Local<String> name,const AccessorInfo & info)4636 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4637   ApiTestFuzzer::Fuzz();
4638   p_getter_count++;
4639   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4640   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4641   if (name->Equals(v8_str("p1"))) {
4642     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4643   } else if (name->Equals(v8_str("p2"))) {
4644     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4645   } else if (name->Equals(v8_str("p3"))) {
4646     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4647   } else if (name->Equals(v8_str("p4"))) {
4648     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4649   }
4650   return v8::Undefined();
4651 }
4652 
4653 
RunHolderTest(v8::Handle<v8::ObjectTemplate> obj)4654 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4655   ApiTestFuzzer::Fuzz();
4656   LocalContext context;
4657   context->Global()->Set(v8_str("o1"), obj->NewInstance());
4658   CompileRun(
4659     "o1.__proto__ = { };"
4660     "var o2 = { __proto__: o1 };"
4661     "var o3 = { __proto__: o2 };"
4662     "var o4 = { __proto__: o3 };"
4663     "for (var i = 0; i < 10; i++) o4.p4;"
4664     "for (var i = 0; i < 10; i++) o3.p3;"
4665     "for (var i = 0; i < 10; i++) o2.p2;"
4666     "for (var i = 0; i < 10; i++) o1.p1;");
4667 }
4668 
4669 
PGetter2(Local<String> name,const AccessorInfo & info)4670 static v8::Handle<Value> PGetter2(Local<String> name,
4671                                   const AccessorInfo& info) {
4672   ApiTestFuzzer::Fuzz();
4673   p_getter_count2++;
4674   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4675   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4676   if (name->Equals(v8_str("p1"))) {
4677     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4678   } else if (name->Equals(v8_str("p2"))) {
4679     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4680   } else if (name->Equals(v8_str("p3"))) {
4681     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4682   } else if (name->Equals(v8_str("p4"))) {
4683     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4684   }
4685   return v8::Undefined();
4686 }
4687 
4688 
THREADED_TEST(GetterHolders)4689 THREADED_TEST(GetterHolders) {
4690   v8::HandleScope scope;
4691   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4692   obj->SetAccessor(v8_str("p1"), PGetter);
4693   obj->SetAccessor(v8_str("p2"), PGetter);
4694   obj->SetAccessor(v8_str("p3"), PGetter);
4695   obj->SetAccessor(v8_str("p4"), PGetter);
4696   p_getter_count = 0;
4697   RunHolderTest(obj);
4698   CHECK_EQ(40, p_getter_count);
4699 }
4700 
4701 
THREADED_TEST(PreInterceptorHolders)4702 THREADED_TEST(PreInterceptorHolders) {
4703   v8::HandleScope scope;
4704   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4705   obj->SetNamedPropertyHandler(PGetter2);
4706   p_getter_count2 = 0;
4707   RunHolderTest(obj);
4708   CHECK_EQ(40, p_getter_count2);
4709 }
4710 
4711 
THREADED_TEST(ObjectInstantiation)4712 THREADED_TEST(ObjectInstantiation) {
4713   v8::HandleScope scope;
4714   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4715   templ->SetAccessor(v8_str("t"), PGetter2);
4716   LocalContext context;
4717   context->Global()->Set(v8_str("o"), templ->NewInstance());
4718   for (int i = 0; i < 100; i++) {
4719     v8::HandleScope inner_scope;
4720     v8::Handle<v8::Object> obj = templ->NewInstance();
4721     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4722     context->Global()->Set(v8_str("o2"), obj);
4723     v8::Handle<Value> value =
4724         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4725     CHECK_EQ(v8::True(), value);
4726     context->Global()->Set(v8_str("o"), obj);
4727   }
4728 }
4729 
4730 
StrCmp16(uint16_t * a,uint16_t * b)4731 static int StrCmp16(uint16_t* a, uint16_t* b) {
4732   while (true) {
4733     if (*a == 0 && *b == 0) return 0;
4734     if (*a != *b) return 0 + *a - *b;
4735     a++;
4736     b++;
4737   }
4738 }
4739 
4740 
StrNCmp16(uint16_t * a,uint16_t * b,int n)4741 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4742   while (true) {
4743     if (n-- == 0) return 0;
4744     if (*a == 0 && *b == 0) return 0;
4745     if (*a != *b) return 0 + *a - *b;
4746     a++;
4747     b++;
4748   }
4749 }
4750 
4751 
THREADED_TEST(StringWrite)4752 THREADED_TEST(StringWrite) {
4753   v8::HandleScope scope;
4754   v8::Handle<String> str = v8_str("abcde");
4755   // abc<Icelandic eth><Unicode snowman>.
4756   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4757 
4758   CHECK_EQ(5, str2->Length());
4759 
4760   char buf[100];
4761   char utf8buf[100];
4762   uint16_t wbuf[100];
4763   int len;
4764   int charlen;
4765 
4766   memset(utf8buf, 0x1, sizeof(utf8buf));
4767   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4768   CHECK_EQ(9, len);
4769   CHECK_EQ(5, charlen);
4770   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
4771 
4772   memset(utf8buf, 0x1, sizeof(utf8buf));
4773   len = str2->WriteUtf8(utf8buf, 8, &charlen);
4774   CHECK_EQ(8, len);
4775   CHECK_EQ(5, charlen);
4776   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
4777 
4778   memset(utf8buf, 0x1, sizeof(utf8buf));
4779   len = str2->WriteUtf8(utf8buf, 7, &charlen);
4780   CHECK_EQ(5, len);
4781   CHECK_EQ(4, charlen);
4782   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4783 
4784   memset(utf8buf, 0x1, sizeof(utf8buf));
4785   len = str2->WriteUtf8(utf8buf, 6, &charlen);
4786   CHECK_EQ(5, len);
4787   CHECK_EQ(4, charlen);
4788   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4789 
4790   memset(utf8buf, 0x1, sizeof(utf8buf));
4791   len = str2->WriteUtf8(utf8buf, 5, &charlen);
4792   CHECK_EQ(5, len);
4793   CHECK_EQ(4, charlen);
4794   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
4795 
4796   memset(utf8buf, 0x1, sizeof(utf8buf));
4797   len = str2->WriteUtf8(utf8buf, 4, &charlen);
4798   CHECK_EQ(3, len);
4799   CHECK_EQ(3, charlen);
4800   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
4801 
4802   memset(utf8buf, 0x1, sizeof(utf8buf));
4803   len = str2->WriteUtf8(utf8buf, 3, &charlen);
4804   CHECK_EQ(3, len);
4805   CHECK_EQ(3, charlen);
4806   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
4807 
4808   memset(utf8buf, 0x1, sizeof(utf8buf));
4809   len = str2->WriteUtf8(utf8buf, 2, &charlen);
4810   CHECK_EQ(2, len);
4811   CHECK_EQ(2, charlen);
4812   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
4813 
4814   memset(buf, 0x1, sizeof(buf));
4815   memset(wbuf, 0x1, sizeof(wbuf));
4816   len = str->WriteAscii(buf);
4817   CHECK_EQ(5, len);
4818   len = str->Write(wbuf);
4819   CHECK_EQ(5, len);
4820   CHECK_EQ(0, strcmp("abcde", buf));
4821   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4822   CHECK_EQ(0, StrCmp16(answer1, wbuf));
4823 
4824   memset(buf, 0x1, sizeof(buf));
4825   memset(wbuf, 0x1, sizeof(wbuf));
4826   len = str->WriteAscii(buf, 0, 4);
4827   CHECK_EQ(4, len);
4828   len = str->Write(wbuf, 0, 4);
4829   CHECK_EQ(4, len);
4830   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
4831   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4832   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
4833 
4834   memset(buf, 0x1, sizeof(buf));
4835   memset(wbuf, 0x1, sizeof(wbuf));
4836   len = str->WriteAscii(buf, 0, 5);
4837   CHECK_EQ(5, len);
4838   len = str->Write(wbuf, 0, 5);
4839   CHECK_EQ(5, len);
4840   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
4841   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4842   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
4843 
4844   memset(buf, 0x1, sizeof(buf));
4845   memset(wbuf, 0x1, sizeof(wbuf));
4846   len = str->WriteAscii(buf, 0, 6);
4847   CHECK_EQ(5, len);
4848   len = str->Write(wbuf, 0, 6);
4849   CHECK_EQ(5, len);
4850   CHECK_EQ(0, strcmp("abcde", buf));
4851   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4852   CHECK_EQ(0, StrCmp16(answer4, wbuf));
4853 
4854   memset(buf, 0x1, sizeof(buf));
4855   memset(wbuf, 0x1, sizeof(wbuf));
4856   len = str->WriteAscii(buf, 4, -1);
4857   CHECK_EQ(1, len);
4858   len = str->Write(wbuf, 4, -1);
4859   CHECK_EQ(1, len);
4860   CHECK_EQ(0, strcmp("e", buf));
4861   uint16_t answer5[] = {'e', '\0'};
4862   CHECK_EQ(0, StrCmp16(answer5, wbuf));
4863 
4864   memset(buf, 0x1, sizeof(buf));
4865   memset(wbuf, 0x1, sizeof(wbuf));
4866   len = str->WriteAscii(buf, 4, 6);
4867   CHECK_EQ(1, len);
4868   len = str->Write(wbuf, 4, 6);
4869   CHECK_EQ(1, len);
4870   CHECK_EQ(0, strcmp("e", buf));
4871   CHECK_EQ(0, StrCmp16(answer5, wbuf));
4872 
4873   memset(buf, 0x1, sizeof(buf));
4874   memset(wbuf, 0x1, sizeof(wbuf));
4875   len = str->WriteAscii(buf, 4, 1);
4876   CHECK_EQ(1, len);
4877   len = str->Write(wbuf, 4, 1);
4878   CHECK_EQ(1, len);
4879   CHECK_EQ(0, strncmp("e\1", buf, 2));
4880   uint16_t answer6[] = {'e', 0x101};
4881   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
4882 
4883   memset(buf, 0x1, sizeof(buf));
4884   memset(wbuf, 0x1, sizeof(wbuf));
4885   len = str->WriteAscii(buf, 3, 1);
4886   CHECK_EQ(1, len);
4887   len = str->Write(wbuf, 3, 1);
4888   CHECK_EQ(1, len);
4889   CHECK_EQ(0, strncmp("d\1", buf, 2));
4890   uint16_t answer7[] = {'d', 0x101};
4891   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
4892 }
4893 
4894 
THREADED_TEST(ToArrayIndex)4895 THREADED_TEST(ToArrayIndex) {
4896   v8::HandleScope scope;
4897   LocalContext context;
4898 
4899   v8::Handle<String> str = v8_str("42");
4900   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4901   CHECK(!index.IsEmpty());
4902   CHECK_EQ(42.0, index->Uint32Value());
4903   str = v8_str("42asdf");
4904   index = str->ToArrayIndex();
4905   CHECK(index.IsEmpty());
4906   str = v8_str("-42");
4907   index = str->ToArrayIndex();
4908   CHECK(index.IsEmpty());
4909   str = v8_str("4294967295");
4910   index = str->ToArrayIndex();
4911   CHECK(!index.IsEmpty());
4912   CHECK_EQ(4294967295.0, index->Uint32Value());
4913   v8::Handle<v8::Number> num = v8::Number::New(1);
4914   index = num->ToArrayIndex();
4915   CHECK(!index.IsEmpty());
4916   CHECK_EQ(1.0, index->Uint32Value());
4917   num = v8::Number::New(-1);
4918   index = num->ToArrayIndex();
4919   CHECK(index.IsEmpty());
4920   v8::Handle<v8::Object> obj = v8::Object::New();
4921   index = obj->ToArrayIndex();
4922   CHECK(index.IsEmpty());
4923 }
4924 
4925 
THREADED_TEST(ErrorConstruction)4926 THREADED_TEST(ErrorConstruction) {
4927   v8::HandleScope scope;
4928   LocalContext context;
4929 
4930   v8::Handle<String> foo = v8_str("foo");
4931   v8::Handle<String> message = v8_str("message");
4932   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4933   CHECK(range_error->IsObject());
4934   v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4935   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4936   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4937   CHECK(reference_error->IsObject());
4938   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4939   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4940   CHECK(syntax_error->IsObject());
4941   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4942   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4943   CHECK(type_error->IsObject());
4944   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4945   v8::Handle<Value> error = v8::Exception::Error(foo);
4946   CHECK(error->IsObject());
4947   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4948 }
4949 
4950 
YGetter(Local<String> name,const AccessorInfo & info)4951 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4952   ApiTestFuzzer::Fuzz();
4953   return v8_num(10);
4954 }
4955 
4956 
YSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)4957 static void YSetter(Local<String> name,
4958                     Local<Value> value,
4959                     const AccessorInfo& info) {
4960   if (info.This()->Has(name)) {
4961     info.This()->Delete(name);
4962   }
4963   info.This()->Set(name, value);
4964 }
4965 
4966 
THREADED_TEST(DeleteAccessor)4967 THREADED_TEST(DeleteAccessor) {
4968   v8::HandleScope scope;
4969   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4970   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4971   LocalContext context;
4972   v8::Handle<v8::Object> holder = obj->NewInstance();
4973   context->Global()->Set(v8_str("holder"), holder);
4974   v8::Handle<Value> result = CompileRun(
4975       "holder.y = 11; holder.y = 12; holder.y");
4976   CHECK_EQ(12, result->Uint32Value());
4977 }
4978 
4979 
THREADED_TEST(TypeSwitch)4980 THREADED_TEST(TypeSwitch) {
4981   v8::HandleScope scope;
4982   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4983   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4984   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4985   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4986   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4987   LocalContext context;
4988   v8::Handle<v8::Object> obj0 = v8::Object::New();
4989   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4990   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4991   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4992   for (int i = 0; i < 10; i++) {
4993     CHECK_EQ(0, type_switch->match(obj0));
4994     CHECK_EQ(1, type_switch->match(obj1));
4995     CHECK_EQ(2, type_switch->match(obj2));
4996     CHECK_EQ(3, type_switch->match(obj3));
4997     CHECK_EQ(3, type_switch->match(obj3));
4998     CHECK_EQ(2, type_switch->match(obj2));
4999     CHECK_EQ(1, type_switch->match(obj1));
5000     CHECK_EQ(0, type_switch->match(obj0));
5001   }
5002 }
5003 
5004 
5005 // For use within the TestSecurityHandler() test.
5006 static bool g_security_callback_result = false;
NamedSecurityTestCallback(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)5007 static bool NamedSecurityTestCallback(Local<v8::Object> global,
5008                                       Local<Value> name,
5009                                       v8::AccessType type,
5010                                       Local<Value> data) {
5011   // Always allow read access.
5012   if (type == v8::ACCESS_GET)
5013     return true;
5014 
5015   // Sometimes allow other access.
5016   return g_security_callback_result;
5017 }
5018 
5019 
IndexedSecurityTestCallback(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)5020 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5021                                         uint32_t key,
5022                                         v8::AccessType type,
5023                                         Local<Value> data) {
5024   // Always allow read access.
5025   if (type == v8::ACCESS_GET)
5026     return true;
5027 
5028   // Sometimes allow other access.
5029   return g_security_callback_result;
5030 }
5031 
5032 
5033 static int trouble_nesting = 0;
TroubleCallback(const v8::Arguments & args)5034 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5035   ApiTestFuzzer::Fuzz();
5036   trouble_nesting++;
5037 
5038   // Call a JS function that throws an uncaught exception.
5039   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5040   Local<Value> trouble_callee = (trouble_nesting == 3) ?
5041     arg_this->Get(v8_str("trouble_callee")) :
5042     arg_this->Get(v8_str("trouble_caller"));
5043   CHECK(trouble_callee->IsFunction());
5044   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5045 }
5046 
5047 
5048 static int report_count = 0;
ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,v8::Handle<Value>)5049 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5050                                              v8::Handle<Value>) {
5051   report_count++;
5052 }
5053 
5054 
5055 // Counts uncaught exceptions, but other tests running in parallel
5056 // also have uncaught exceptions.
TEST(ApiUncaughtException)5057 TEST(ApiUncaughtException) {
5058   report_count = 0;
5059   v8::HandleScope scope;
5060   LocalContext env;
5061   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5062 
5063   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5064   v8::Local<v8::Object> global = env->Global();
5065   global->Set(v8_str("trouble"), fun->GetFunction());
5066 
5067   Script::Compile(v8_str("function trouble_callee() {"
5068                          "  var x = null;"
5069                          "  return x.foo;"
5070                          "};"
5071                          "function trouble_caller() {"
5072                          "  trouble();"
5073                          "};"))->Run();
5074   Local<Value> trouble = global->Get(v8_str("trouble"));
5075   CHECK(trouble->IsFunction());
5076   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5077   CHECK(trouble_callee->IsFunction());
5078   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5079   CHECK(trouble_caller->IsFunction());
5080   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5081   CHECK_EQ(1, report_count);
5082   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5083 }
5084 
5085 static const char* script_resource_name = "ExceptionInNativeScript.js";
ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,v8::Handle<Value>)5086 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5087                                                 v8::Handle<Value>) {
5088   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5089   CHECK(!name_val.IsEmpty() && name_val->IsString());
5090   v8::String::AsciiValue name(message->GetScriptResourceName());
5091   CHECK_EQ(script_resource_name, *name);
5092   CHECK_EQ(3, message->GetLineNumber());
5093   v8::String::AsciiValue source_line(message->GetSourceLine());
5094   CHECK_EQ("  new o.foo();", *source_line);
5095 }
5096 
TEST(ExceptionInNativeScript)5097 TEST(ExceptionInNativeScript) {
5098   v8::HandleScope scope;
5099   LocalContext env;
5100   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5101 
5102   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5103   v8::Local<v8::Object> global = env->Global();
5104   global->Set(v8_str("trouble"), fun->GetFunction());
5105 
5106   Script::Compile(v8_str("function trouble() {\n"
5107                          "  var o = {};\n"
5108                          "  new o.foo();\n"
5109                          "};"), v8::String::New(script_resource_name))->Run();
5110   Local<Value> trouble = global->Get(v8_str("trouble"));
5111   CHECK(trouble->IsFunction());
5112   Function::Cast(*trouble)->Call(global, 0, NULL);
5113   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5114 }
5115 
5116 
TEST(CompilationErrorUsingTryCatchHandler)5117 TEST(CompilationErrorUsingTryCatchHandler) {
5118   v8::HandleScope scope;
5119   LocalContext env;
5120   v8::TryCatch try_catch;
5121   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5122   CHECK_NE(NULL, *try_catch.Exception());
5123   CHECK(try_catch.HasCaught());
5124 }
5125 
5126 
TEST(TryCatchFinallyUsingTryCatchHandler)5127 TEST(TryCatchFinallyUsingTryCatchHandler) {
5128   v8::HandleScope scope;
5129   LocalContext env;
5130   v8::TryCatch try_catch;
5131   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5132   CHECK(!try_catch.HasCaught());
5133   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5134   CHECK(try_catch.HasCaught());
5135   try_catch.Reset();
5136   Script::Compile(v8_str("(function() {"
5137                          "try { throw ''; } finally { return; }"
5138                          "})()"))->Run();
5139   CHECK(!try_catch.HasCaught());
5140   Script::Compile(v8_str("(function()"
5141                          "  { try { throw ''; } finally { throw 0; }"
5142                          "})()"))->Run();
5143   CHECK(try_catch.HasCaught());
5144 }
5145 
5146 
5147 // SecurityHandler can't be run twice
TEST(SecurityHandler)5148 TEST(SecurityHandler) {
5149   v8::HandleScope scope0;
5150   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5151   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5152                                            IndexedSecurityTestCallback);
5153   // Create an environment
5154   v8::Persistent<Context> context0 =
5155     Context::New(NULL, global_template);
5156   context0->Enter();
5157 
5158   v8::Handle<v8::Object> global0 = context0->Global();
5159   v8::Handle<Script> script0 = v8_compile("foo = 111");
5160   script0->Run();
5161   global0->Set(v8_str("0"), v8_num(999));
5162   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5163   CHECK_EQ(111, foo0->Int32Value());
5164   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5165   CHECK_EQ(999, z0->Int32Value());
5166 
5167   // Create another environment, should fail security checks.
5168   v8::HandleScope scope1;
5169 
5170   v8::Persistent<Context> context1 =
5171     Context::New(NULL, global_template);
5172   context1->Enter();
5173 
5174   v8::Handle<v8::Object> global1 = context1->Global();
5175   global1->Set(v8_str("othercontext"), global0);
5176   // This set will fail the security check.
5177   v8::Handle<Script> script1 =
5178     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5179   script1->Run();
5180   // This read will pass the security check.
5181   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5182   CHECK_EQ(111, foo1->Int32Value());
5183   // This read will pass the security check.
5184   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5185   CHECK_EQ(999, z1->Int32Value());
5186 
5187   // Create another environment, should pass security checks.
5188   { g_security_callback_result = true;  // allow security handler to pass.
5189     v8::HandleScope scope2;
5190     LocalContext context2;
5191     v8::Handle<v8::Object> global2 = context2->Global();
5192     global2->Set(v8_str("othercontext"), global0);
5193     v8::Handle<Script> script2 =
5194         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5195     script2->Run();
5196     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5197     CHECK_EQ(333, foo2->Int32Value());
5198     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5199     CHECK_EQ(888, z2->Int32Value());
5200   }
5201 
5202   context1->Exit();
5203   context1.Dispose();
5204 
5205   context0->Exit();
5206   context0.Dispose();
5207 }
5208 
5209 
THREADED_TEST(SecurityChecks)5210 THREADED_TEST(SecurityChecks) {
5211   v8::HandleScope handle_scope;
5212   LocalContext env1;
5213   v8::Persistent<Context> env2 = Context::New();
5214 
5215   Local<Value> foo = v8_str("foo");
5216   Local<Value> bar = v8_str("bar");
5217 
5218   // Set to the same domain.
5219   env1->SetSecurityToken(foo);
5220 
5221   // Create a function in env1.
5222   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5223   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5224   CHECK(spy->IsFunction());
5225 
5226   // Create another function accessing global objects.
5227   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5228   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5229   CHECK(spy2->IsFunction());
5230 
5231   // Switch to env2 in the same domain and invoke spy on env2.
5232   {
5233     env2->SetSecurityToken(foo);
5234     // Enter env2
5235     Context::Scope scope_env2(env2);
5236     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5237     CHECK(result->IsFunction());
5238   }
5239 
5240   {
5241     env2->SetSecurityToken(bar);
5242     Context::Scope scope_env2(env2);
5243 
5244     // Call cross_domain_call, it should throw an exception
5245     v8::TryCatch try_catch;
5246     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5247     CHECK(try_catch.HasCaught());
5248   }
5249 
5250   env2.Dispose();
5251 }
5252 
5253 
5254 // Regression test case for issue 1183439.
THREADED_TEST(SecurityChecksForPrototypeChain)5255 THREADED_TEST(SecurityChecksForPrototypeChain) {
5256   v8::HandleScope scope;
5257   LocalContext current;
5258   v8::Persistent<Context> other = Context::New();
5259 
5260   // Change context to be able to get to the Object function in the
5261   // other context without hitting the security checks.
5262   v8::Local<Value> other_object;
5263   { Context::Scope scope(other);
5264     other_object = other->Global()->Get(v8_str("Object"));
5265     other->Global()->Set(v8_num(42), v8_num(87));
5266   }
5267 
5268   current->Global()->Set(v8_str("other"), other->Global());
5269   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5270 
5271   // Make sure the security check fails here and we get an undefined
5272   // result instead of getting the Object function. Repeat in a loop
5273   // to make sure to exercise the IC code.
5274   v8::Local<Script> access_other0 = v8_compile("other.Object");
5275   v8::Local<Script> access_other1 = v8_compile("other[42]");
5276   for (int i = 0; i < 5; i++) {
5277     CHECK(!access_other0->Run()->Equals(other_object));
5278     CHECK(access_other0->Run()->IsUndefined());
5279     CHECK(!access_other1->Run()->Equals(v8_num(87)));
5280     CHECK(access_other1->Run()->IsUndefined());
5281   }
5282 
5283   // Create an object that has 'other' in its prototype chain and make
5284   // sure we cannot access the Object function indirectly through
5285   // that. Repeat in a loop to make sure to exercise the IC code.
5286   v8_compile("function F() { };"
5287              "F.prototype = other;"
5288              "var f = new F();")->Run();
5289   v8::Local<Script> access_f0 = v8_compile("f.Object");
5290   v8::Local<Script> access_f1 = v8_compile("f[42]");
5291   for (int j = 0; j < 5; j++) {
5292     CHECK(!access_f0->Run()->Equals(other_object));
5293     CHECK(access_f0->Run()->IsUndefined());
5294     CHECK(!access_f1->Run()->Equals(v8_num(87)));
5295     CHECK(access_f1->Run()->IsUndefined());
5296   }
5297 
5298   // Now it gets hairy: Set the prototype for the other global object
5299   // to be the current global object. The prototype chain for 'f' now
5300   // goes through 'other' but ends up in the current global object.
5301   { Context::Scope scope(other);
5302     other->Global()->Set(v8_str("__proto__"), current->Global());
5303   }
5304   // Set a named and an index property on the current global
5305   // object. To force the lookup to go through the other global object,
5306   // the properties must not exist in the other global object.
5307   current->Global()->Set(v8_str("foo"), v8_num(100));
5308   current->Global()->Set(v8_num(99), v8_num(101));
5309   // Try to read the properties from f and make sure that the access
5310   // gets stopped by the security checks on the other global object.
5311   Local<Script> access_f2 = v8_compile("f.foo");
5312   Local<Script> access_f3 = v8_compile("f[99]");
5313   for (int k = 0; k < 5; k++) {
5314     CHECK(!access_f2->Run()->Equals(v8_num(100)));
5315     CHECK(access_f2->Run()->IsUndefined());
5316     CHECK(!access_f3->Run()->Equals(v8_num(101)));
5317     CHECK(access_f3->Run()->IsUndefined());
5318   }
5319   other.Dispose();
5320 }
5321 
5322 
THREADED_TEST(CrossDomainDelete)5323 THREADED_TEST(CrossDomainDelete) {
5324   v8::HandleScope handle_scope;
5325   LocalContext env1;
5326   v8::Persistent<Context> env2 = Context::New();
5327 
5328   Local<Value> foo = v8_str("foo");
5329   Local<Value> bar = v8_str("bar");
5330 
5331   // Set to the same domain.
5332   env1->SetSecurityToken(foo);
5333   env2->SetSecurityToken(foo);
5334 
5335   env1->Global()->Set(v8_str("prop"), v8_num(3));
5336   env2->Global()->Set(v8_str("env1"), env1->Global());
5337 
5338   // Change env2 to a different domain and delete env1.prop.
5339   env2->SetSecurityToken(bar);
5340   {
5341     Context::Scope scope_env2(env2);
5342     Local<Value> result =
5343         Script::Compile(v8_str("delete env1.prop"))->Run();
5344     CHECK(result->IsFalse());
5345   }
5346 
5347   // Check that env1.prop still exists.
5348   Local<Value> v = env1->Global()->Get(v8_str("prop"));
5349   CHECK(v->IsNumber());
5350   CHECK_EQ(3, v->Int32Value());
5351 
5352   env2.Dispose();
5353 }
5354 
5355 
THREADED_TEST(CrossDomainIsPropertyEnumerable)5356 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5357   v8::HandleScope handle_scope;
5358   LocalContext env1;
5359   v8::Persistent<Context> env2 = Context::New();
5360 
5361   Local<Value> foo = v8_str("foo");
5362   Local<Value> bar = v8_str("bar");
5363 
5364   // Set to the same domain.
5365   env1->SetSecurityToken(foo);
5366   env2->SetSecurityToken(foo);
5367 
5368   env1->Global()->Set(v8_str("prop"), v8_num(3));
5369   env2->Global()->Set(v8_str("env1"), env1->Global());
5370 
5371   // env1.prop is enumerable in env2.
5372   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5373   {
5374     Context::Scope scope_env2(env2);
5375     Local<Value> result = Script::Compile(test)->Run();
5376     CHECK(result->IsTrue());
5377   }
5378 
5379   // Change env2 to a different domain and test again.
5380   env2->SetSecurityToken(bar);
5381   {
5382     Context::Scope scope_env2(env2);
5383     Local<Value> result = Script::Compile(test)->Run();
5384     CHECK(result->IsFalse());
5385   }
5386 
5387   env2.Dispose();
5388 }
5389 
5390 
THREADED_TEST(CrossDomainForIn)5391 THREADED_TEST(CrossDomainForIn) {
5392   v8::HandleScope handle_scope;
5393   LocalContext env1;
5394   v8::Persistent<Context> env2 = Context::New();
5395 
5396   Local<Value> foo = v8_str("foo");
5397   Local<Value> bar = v8_str("bar");
5398 
5399   // Set to the same domain.
5400   env1->SetSecurityToken(foo);
5401   env2->SetSecurityToken(foo);
5402 
5403   env1->Global()->Set(v8_str("prop"), v8_num(3));
5404   env2->Global()->Set(v8_str("env1"), env1->Global());
5405 
5406   // Change env2 to a different domain and set env1's global object
5407   // as the __proto__ of an object in env2 and enumerate properties
5408   // in for-in. It shouldn't enumerate properties on env1's global
5409   // object.
5410   env2->SetSecurityToken(bar);
5411   {
5412     Context::Scope scope_env2(env2);
5413     Local<Value> result =
5414         CompileRun("(function(){var obj = {'__proto__':env1};"
5415                    "for (var p in obj)"
5416                    "   if (p == 'prop') return false;"
5417                    "return true;})()");
5418     CHECK(result->IsTrue());
5419   }
5420   env2.Dispose();
5421 }
5422 
5423 
TEST(ContextDetachGlobal)5424 TEST(ContextDetachGlobal) {
5425   v8::HandleScope handle_scope;
5426   LocalContext env1;
5427   v8::Persistent<Context> env2 = Context::New();
5428 
5429   Local<v8::Object> global1 = env1->Global();
5430 
5431   Local<Value> foo = v8_str("foo");
5432 
5433   // Set to the same domain.
5434   env1->SetSecurityToken(foo);
5435   env2->SetSecurityToken(foo);
5436 
5437   // Enter env2
5438   env2->Enter();
5439 
5440   // Create a function in env2 and add a reference to it in env1.
5441   Local<v8::Object> global2 = env2->Global();
5442   global2->Set(v8_str("prop"), v8::Integer::New(1));
5443   CompileRun("function getProp() {return prop;}");
5444 
5445   env1->Global()->Set(v8_str("getProp"),
5446                       global2->Get(v8_str("getProp")));
5447 
5448   // Detach env2's global, and reuse the global object of env2
5449   env2->Exit();
5450   env2->DetachGlobal();
5451   // env2 has a new global object.
5452   CHECK(!env2->Global()->Equals(global2));
5453 
5454   v8::Persistent<Context> env3 =
5455       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5456   env3->SetSecurityToken(v8_str("bar"));
5457   env3->Enter();
5458 
5459   Local<v8::Object> global3 = env3->Global();
5460   CHECK_EQ(global2, global3);
5461   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5462   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5463   global3->Set(v8_str("prop"), v8::Integer::New(-1));
5464   global3->Set(v8_str("prop2"), v8::Integer::New(2));
5465   env3->Exit();
5466 
5467   // Call getProp in env1, and it should return the value 1
5468   {
5469     Local<Value> get_prop = global1->Get(v8_str("getProp"));
5470     CHECK(get_prop->IsFunction());
5471     v8::TryCatch try_catch;
5472     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5473     CHECK(!try_catch.HasCaught());
5474     CHECK_EQ(1, r->Int32Value());
5475   }
5476 
5477   // Check that env3 is not accessible from env1
5478   {
5479     Local<Value> r = global3->Get(v8_str("prop2"));
5480     CHECK(r->IsUndefined());
5481   }
5482 
5483   env2.Dispose();
5484   env3.Dispose();
5485 }
5486 
5487 
TEST(DetachAndReattachGlobal)5488 TEST(DetachAndReattachGlobal) {
5489   v8::HandleScope scope;
5490   LocalContext env1;
5491 
5492   // Create second environment.
5493   v8::Persistent<Context> env2 = Context::New();
5494 
5495   Local<Value> foo = v8_str("foo");
5496 
5497   // Set same security token for env1 and env2.
5498   env1->SetSecurityToken(foo);
5499   env2->SetSecurityToken(foo);
5500 
5501   // Create a property on the global object in env2.
5502   {
5503     v8::Context::Scope scope(env2);
5504     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5505   }
5506 
5507   // Create a reference to env2 global from env1 global.
5508   env1->Global()->Set(v8_str("other"), env2->Global());
5509 
5510   // Check that we have access to other.p in env2 from env1.
5511   Local<Value> result = CompileRun("other.p");
5512   CHECK(result->IsInt32());
5513   CHECK_EQ(42, result->Int32Value());
5514 
5515   // Hold on to global from env2 and detach global from env2.
5516   Local<v8::Object> global2 = env2->Global();
5517   env2->DetachGlobal();
5518 
5519   // Check that the global has been detached. No other.p property can
5520   // be found.
5521   result = CompileRun("other.p");
5522   CHECK(result->IsUndefined());
5523 
5524   // Reuse global2 for env3.
5525   v8::Persistent<Context> env3 =
5526       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5527   CHECK_EQ(global2, env3->Global());
5528 
5529   // Start by using the same security token for env3 as for env1 and env2.
5530   env3->SetSecurityToken(foo);
5531 
5532   // Create a property on the global object in env3.
5533   {
5534     v8::Context::Scope scope(env3);
5535     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5536   }
5537 
5538   // Check that other.p is now the property in env3 and that we have access.
5539   result = CompileRun("other.p");
5540   CHECK(result->IsInt32());
5541   CHECK_EQ(24, result->Int32Value());
5542 
5543   // Change security token for env3 to something different from env1 and env2.
5544   env3->SetSecurityToken(v8_str("bar"));
5545 
5546   // Check that we do not have access to other.p in env1. |other| is now
5547   // the global object for env3 which has a different security token,
5548   // so access should be blocked.
5549   result = CompileRun("other.p");
5550   CHECK(result->IsUndefined());
5551 
5552   // Detach the global for env3 and reattach it to env2.
5553   env3->DetachGlobal();
5554   env2->ReattachGlobal(global2);
5555 
5556   // Check that we have access to other.p again in env1.  |other| is now
5557   // the global object for env2 which has the same security token as env1.
5558   result = CompileRun("other.p");
5559   CHECK(result->IsInt32());
5560   CHECK_EQ(42, result->Int32Value());
5561 
5562   env2.Dispose();
5563   env3.Dispose();
5564 }
5565 
5566 
5567 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
NamedAccessBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)5568 static bool NamedAccessBlocker(Local<v8::Object> global,
5569                                Local<Value> name,
5570                                v8::AccessType type,
5571                                Local<Value> data) {
5572   return Context::GetCurrent()->Global()->Equals(global) ||
5573       allowed_access_type[type];
5574 }
5575 
5576 
IndexedAccessBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)5577 static bool IndexedAccessBlocker(Local<v8::Object> global,
5578                                  uint32_t key,
5579                                  v8::AccessType type,
5580                                  Local<Value> data) {
5581   return Context::GetCurrent()->Global()->Equals(global) ||
5582       allowed_access_type[type];
5583 }
5584 
5585 
5586 static int g_echo_value = -1;
EchoGetter(Local<String> name,const AccessorInfo & info)5587 static v8::Handle<Value> EchoGetter(Local<String> name,
5588                                     const AccessorInfo& info) {
5589   return v8_num(g_echo_value);
5590 }
5591 
5592 
EchoSetter(Local<String> name,Local<Value> value,const AccessorInfo &)5593 static void EchoSetter(Local<String> name,
5594                        Local<Value> value,
5595                        const AccessorInfo&) {
5596   if (value->IsNumber())
5597     g_echo_value = value->Int32Value();
5598 }
5599 
5600 
UnreachableGetter(Local<String> name,const AccessorInfo & info)5601 static v8::Handle<Value> UnreachableGetter(Local<String> name,
5602                                            const AccessorInfo& info) {
5603   CHECK(false);  // This function should not be called..
5604   return v8::Undefined();
5605 }
5606 
5607 
UnreachableSetter(Local<String>,Local<Value>,const AccessorInfo &)5608 static void UnreachableSetter(Local<String>, Local<Value>,
5609                               const AccessorInfo&) {
5610   CHECK(false);  // This function should nto be called.
5611 }
5612 
5613 
TEST(AccessControl)5614 TEST(AccessControl) {
5615   v8::HandleScope handle_scope;
5616   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5617 
5618   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5619                                            IndexedAccessBlocker);
5620 
5621   // Add an accessor accessible by cross-domain JS code.
5622   global_template->SetAccessor(
5623       v8_str("accessible_prop"),
5624       EchoGetter, EchoSetter,
5625       v8::Handle<Value>(),
5626       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5627 
5628   // Add an accessor that is not accessible by cross-domain JS code.
5629   global_template->SetAccessor(v8_str("blocked_prop"),
5630                                UnreachableGetter, UnreachableSetter,
5631                                v8::Handle<Value>(),
5632                                v8::DEFAULT);
5633 
5634   // Create an environment
5635   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5636   context0->Enter();
5637 
5638   v8::Handle<v8::Object> global0 = context0->Global();
5639 
5640   // Define a property with JS getter and setter.
5641   CompileRun(
5642       "function getter() { return 'getter'; };\n"
5643       "function setter() { return 'setter'; }\n"
5644       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5645 
5646   Local<Value> getter = global0->Get(v8_str("getter"));
5647   Local<Value> setter = global0->Get(v8_str("setter"));
5648 
5649   // And define normal element.
5650   global0->Set(239, v8_str("239"));
5651 
5652   // Define an element with JS getter and setter.
5653   CompileRun(
5654       "function el_getter() { return 'el_getter'; };\n"
5655       "function el_setter() { return 'el_setter'; };\n"
5656       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5657 
5658   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5659   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5660 
5661   v8::HandleScope scope1;
5662 
5663   v8::Persistent<Context> context1 = Context::New();
5664   context1->Enter();
5665 
5666   v8::Handle<v8::Object> global1 = context1->Global();
5667   global1->Set(v8_str("other"), global0);
5668 
5669   // Access blocked property.
5670   CompileRun("other.blocked_prop = 1");
5671 
5672   ExpectUndefined("other.blocked_prop");
5673   ExpectUndefined(
5674       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5675   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
5676 
5677   // Enable ACCESS_HAS
5678   allowed_access_type[v8::ACCESS_HAS] = true;
5679   ExpectUndefined("other.blocked_prop");
5680   // ... and now we can get the descriptor...
5681   ExpectUndefined(
5682       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
5683   // ... and enumerate the property.
5684   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
5685   allowed_access_type[v8::ACCESS_HAS] = false;
5686 
5687   // Access blocked element.
5688   CompileRun("other[239] = 1");
5689 
5690   ExpectUndefined("other[239]");
5691   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
5692   ExpectFalse("propertyIsEnumerable.call(other, '239')");
5693 
5694   // Enable ACCESS_HAS
5695   allowed_access_type[v8::ACCESS_HAS] = true;
5696   ExpectUndefined("other[239]");
5697   // ... and now we can get the descriptor...
5698   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
5699   // ... and enumerate the property.
5700   ExpectTrue("propertyIsEnumerable.call(other, '239')");
5701   allowed_access_type[v8::ACCESS_HAS] = false;
5702 
5703   // Access a property with JS accessor.
5704   CompileRun("other.js_accessor_p = 2");
5705 
5706   ExpectUndefined("other.js_accessor_p");
5707   ExpectUndefined(
5708       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
5709 
5710   // Enable ACCESS_HAS.
5711   allowed_access_type[v8::ACCESS_HAS] = true;
5712   ExpectUndefined("other.js_accessor_p");
5713   ExpectUndefined(
5714       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5715   ExpectUndefined(
5716       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5717   ExpectUndefined(
5718       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5719   allowed_access_type[v8::ACCESS_HAS] = false;
5720 
5721   // Enable both ACCESS_HAS and ACCESS_GET.
5722   allowed_access_type[v8::ACCESS_HAS] = true;
5723   allowed_access_type[v8::ACCESS_GET] = true;
5724 
5725   ExpectString("other.js_accessor_p", "getter");
5726   ExpectObject(
5727       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5728   ExpectUndefined(
5729       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5730   ExpectUndefined(
5731       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5732 
5733   allowed_access_type[v8::ACCESS_GET] = false;
5734   allowed_access_type[v8::ACCESS_HAS] = false;
5735 
5736   // Enable both ACCESS_HAS and ACCESS_SET.
5737   allowed_access_type[v8::ACCESS_HAS] = true;
5738   allowed_access_type[v8::ACCESS_SET] = true;
5739 
5740   ExpectUndefined("other.js_accessor_p");
5741   ExpectUndefined(
5742       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5743   ExpectObject(
5744       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5745   ExpectUndefined(
5746       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5747 
5748   allowed_access_type[v8::ACCESS_SET] = false;
5749   allowed_access_type[v8::ACCESS_HAS] = false;
5750 
5751   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5752   allowed_access_type[v8::ACCESS_HAS] = true;
5753   allowed_access_type[v8::ACCESS_GET] = true;
5754   allowed_access_type[v8::ACCESS_SET] = true;
5755 
5756   ExpectString("other.js_accessor_p", "getter");
5757   ExpectObject(
5758       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5759   ExpectObject(
5760       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5761   ExpectUndefined(
5762       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5763 
5764   allowed_access_type[v8::ACCESS_SET] = false;
5765   allowed_access_type[v8::ACCESS_GET] = false;
5766   allowed_access_type[v8::ACCESS_HAS] = false;
5767 
5768   // Access an element with JS accessor.
5769   CompileRun("other[42] = 2");
5770 
5771   ExpectUndefined("other[42]");
5772   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
5773 
5774   // Enable ACCESS_HAS.
5775   allowed_access_type[v8::ACCESS_HAS] = true;
5776   ExpectUndefined("other[42]");
5777   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5778   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5779   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5780   allowed_access_type[v8::ACCESS_HAS] = false;
5781 
5782   // Enable both ACCESS_HAS and ACCESS_GET.
5783   allowed_access_type[v8::ACCESS_HAS] = true;
5784   allowed_access_type[v8::ACCESS_GET] = true;
5785 
5786   ExpectString("other[42]", "el_getter");
5787   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5788   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5789   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5790 
5791   allowed_access_type[v8::ACCESS_GET] = false;
5792   allowed_access_type[v8::ACCESS_HAS] = false;
5793 
5794   // Enable both ACCESS_HAS and ACCESS_SET.
5795   allowed_access_type[v8::ACCESS_HAS] = true;
5796   allowed_access_type[v8::ACCESS_SET] = true;
5797 
5798   ExpectUndefined("other[42]");
5799   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5800   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5801   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5802 
5803   allowed_access_type[v8::ACCESS_SET] = false;
5804   allowed_access_type[v8::ACCESS_HAS] = false;
5805 
5806   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5807   allowed_access_type[v8::ACCESS_HAS] = true;
5808   allowed_access_type[v8::ACCESS_GET] = true;
5809   allowed_access_type[v8::ACCESS_SET] = true;
5810 
5811   ExpectString("other[42]", "el_getter");
5812   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5813   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5814   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5815 
5816   allowed_access_type[v8::ACCESS_SET] = false;
5817   allowed_access_type[v8::ACCESS_GET] = false;
5818   allowed_access_type[v8::ACCESS_HAS] = false;
5819 
5820   v8::Handle<Value> value;
5821 
5822   // Access accessible property
5823   value = CompileRun("other.accessible_prop = 3");
5824   CHECK(value->IsNumber());
5825   CHECK_EQ(3, value->Int32Value());
5826   CHECK_EQ(3, g_echo_value);
5827 
5828   value = CompileRun("other.accessible_prop");
5829   CHECK(value->IsNumber());
5830   CHECK_EQ(3, value->Int32Value());
5831 
5832   value = CompileRun(
5833       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5834   CHECK(value->IsNumber());
5835   CHECK_EQ(3, value->Int32Value());
5836 
5837   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
5838   CHECK(value->IsTrue());
5839 
5840   // Enumeration doesn't enumerate accessors from inaccessible objects in
5841   // the prototype chain even if the accessors are in themselves accessible.
5842   value =
5843       CompileRun("(function(){var obj = {'__proto__':other};"
5844                  "for (var p in obj)"
5845                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
5846                  "     return false;"
5847                  "   }"
5848                  "return true;})()");
5849   CHECK(value->IsTrue());
5850 
5851   context1->Exit();
5852   context0->Exit();
5853   context1.Dispose();
5854   context0.Dispose();
5855 }
5856 
5857 
TEST(AccessControlES5)5858 TEST(AccessControlES5) {
5859   v8::HandleScope handle_scope;
5860   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5861 
5862   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5863                                            IndexedAccessBlocker);
5864 
5865   // Add accessible accessor.
5866   global_template->SetAccessor(
5867       v8_str("accessible_prop"),
5868       EchoGetter, EchoSetter,
5869       v8::Handle<Value>(),
5870       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5871 
5872 
5873   // Add an accessor that is not accessible by cross-domain JS code.
5874   global_template->SetAccessor(v8_str("blocked_prop"),
5875                                UnreachableGetter, UnreachableSetter,
5876                                v8::Handle<Value>(),
5877                                v8::DEFAULT);
5878 
5879   // Create an environment
5880   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5881   context0->Enter();
5882 
5883   v8::Handle<v8::Object> global0 = context0->Global();
5884 
5885   v8::Persistent<Context> context1 = Context::New();
5886   context1->Enter();
5887   v8::Handle<v8::Object> global1 = context1->Global();
5888   global1->Set(v8_str("other"), global0);
5889 
5890   // Regression test for issue 1154.
5891   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
5892 
5893   ExpectUndefined("other.blocked_prop");
5894 
5895   // Regression test for issue 1027.
5896   CompileRun("Object.defineProperty(\n"
5897              "  other, 'blocked_prop', {configurable: false})");
5898   ExpectUndefined("other.blocked_prop");
5899   ExpectUndefined(
5900       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5901 
5902   // Regression test for issue 1171.
5903   ExpectTrue("Object.isExtensible(other)");
5904   CompileRun("Object.preventExtensions(other)");
5905   ExpectTrue("Object.isExtensible(other)");
5906 
5907   // Object.seal and Object.freeze.
5908   CompileRun("Object.freeze(other)");
5909   ExpectTrue("Object.isExtensible(other)");
5910 
5911   CompileRun("Object.seal(other)");
5912   ExpectTrue("Object.isExtensible(other)");
5913 
5914   // Regression test for issue 1250.
5915   // Make sure that we can set the accessible accessors value using normal
5916   // assignment.
5917   CompileRun("other.accessible_prop = 42");
5918   CHECK_EQ(42, g_echo_value);
5919 
5920   v8::Handle<Value> value;
5921   // We follow Safari in ignoring assignments to host object accessors.
5922   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
5923   value = CompileRun("other.accessible_prop == 42");
5924   CHECK(value->IsTrue());
5925 }
5926 
5927 
GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)5928 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5929                                             Local<Value> name,
5930                                             v8::AccessType type,
5931                                             Local<Value> data) {
5932   return false;
5933 }
5934 
5935 
GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)5936 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5937                                               uint32_t key,
5938                                               v8::AccessType type,
5939                                               Local<Value> data) {
5940   return false;
5941 }
5942 
5943 
THREADED_TEST(AccessControlGetOwnPropertyNames)5944 THREADED_TEST(AccessControlGetOwnPropertyNames) {
5945   v8::HandleScope handle_scope;
5946   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5947 
5948   obj_template->Set(v8_str("x"), v8::Integer::New(42));
5949   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5950                                         GetOwnPropertyNamesIndexedBlocker);
5951 
5952   // Create an environment
5953   v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5954   context0->Enter();
5955 
5956   v8::Handle<v8::Object> global0 = context0->Global();
5957 
5958   v8::HandleScope scope1;
5959 
5960   v8::Persistent<Context> context1 = Context::New();
5961   context1->Enter();
5962 
5963   v8::Handle<v8::Object> global1 = context1->Global();
5964   global1->Set(v8_str("other"), global0);
5965   global1->Set(v8_str("object"), obj_template->NewInstance());
5966 
5967   v8::Handle<Value> value;
5968 
5969   // Attempt to get the property names of the other global object and
5970   // of an object that requires access checks.  Accessing the other
5971   // global object should be blocked by access checks on the global
5972   // proxy object.  Accessing the object that requires access checks
5973   // is blocked by the access checks on the object itself.
5974   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5975   CHECK(value->IsTrue());
5976 
5977   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5978   CHECK(value->IsTrue());
5979 
5980   context1->Exit();
5981   context0->Exit();
5982   context1.Dispose();
5983   context0.Dispose();
5984 }
5985 
5986 
NamedPropertyEnumerator(const AccessorInfo & info)5987 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5988   v8::Handle<v8::Array> result = v8::Array::New(1);
5989   result->Set(0, v8_str("x"));
5990   return result;
5991 }
5992 
5993 
THREADED_TEST(GetOwnPropertyNamesWithInterceptor)5994 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5995   v8::HandleScope handle_scope;
5996   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5997 
5998   obj_template->Set(v8_str("x"), v8::Integer::New(42));
5999   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6000                                         NamedPropertyEnumerator);
6001 
6002   LocalContext context;
6003   v8::Handle<v8::Object> global = context->Global();
6004   global->Set(v8_str("object"), obj_template->NewInstance());
6005 
6006   v8::Handle<Value> value =
6007       CompileRun("Object.getOwnPropertyNames(object).join(',')");
6008   CHECK_EQ(v8_str("x"), value);
6009 }
6010 
6011 
ConstTenGetter(Local<String> name,const AccessorInfo & info)6012 static v8::Handle<Value> ConstTenGetter(Local<String> name,
6013                                         const AccessorInfo& info) {
6014   return v8_num(10);
6015 }
6016 
6017 
THREADED_TEST(CrossDomainAccessors)6018 THREADED_TEST(CrossDomainAccessors) {
6019   v8::HandleScope handle_scope;
6020 
6021   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6022 
6023   v8::Handle<v8::ObjectTemplate> global_template =
6024       func_template->InstanceTemplate();
6025 
6026   v8::Handle<v8::ObjectTemplate> proto_template =
6027       func_template->PrototypeTemplate();
6028 
6029   // Add an accessor to proto that's accessible by cross-domain JS code.
6030   proto_template->SetAccessor(v8_str("accessible"),
6031                               ConstTenGetter, 0,
6032                               v8::Handle<Value>(),
6033                               v8::ALL_CAN_READ);
6034 
6035   // Add an accessor that is not accessible by cross-domain JS code.
6036   global_template->SetAccessor(v8_str("unreachable"),
6037                                UnreachableGetter, 0,
6038                                v8::Handle<Value>(),
6039                                v8::DEFAULT);
6040 
6041   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6042   context0->Enter();
6043 
6044   Local<v8::Object> global = context0->Global();
6045   // Add a normal property that shadows 'accessible'
6046   global->Set(v8_str("accessible"), v8_num(11));
6047 
6048   // Enter a new context.
6049   v8::HandleScope scope1;
6050   v8::Persistent<Context> context1 = Context::New();
6051   context1->Enter();
6052 
6053   v8::Handle<v8::Object> global1 = context1->Global();
6054   global1->Set(v8_str("other"), global);
6055 
6056   // Should return 10, instead of 11
6057   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6058   CHECK(value->IsNumber());
6059   CHECK_EQ(10, value->Int32Value());
6060 
6061   value = v8_compile("other.unreachable")->Run();
6062   CHECK(value->IsUndefined());
6063 
6064   context1->Exit();
6065   context0->Exit();
6066   context1.Dispose();
6067   context0.Dispose();
6068 }
6069 
6070 
6071 static int named_access_count = 0;
6072 static int indexed_access_count = 0;
6073 
NamedAccessCounter(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)6074 static bool NamedAccessCounter(Local<v8::Object> global,
6075                                Local<Value> name,
6076                                v8::AccessType type,
6077                                Local<Value> data) {
6078   named_access_count++;
6079   return true;
6080 }
6081 
6082 
IndexedAccessCounter(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)6083 static bool IndexedAccessCounter(Local<v8::Object> global,
6084                                  uint32_t key,
6085                                  v8::AccessType type,
6086                                  Local<Value> data) {
6087   indexed_access_count++;
6088   return true;
6089 }
6090 
6091 
6092 // This one is too easily disturbed by other tests.
TEST(AccessControlIC)6093 TEST(AccessControlIC) {
6094   named_access_count = 0;
6095   indexed_access_count = 0;
6096 
6097   v8::HandleScope handle_scope;
6098 
6099   // Create an environment.
6100   v8::Persistent<Context> context0 = Context::New();
6101   context0->Enter();
6102 
6103   // Create an object that requires access-check functions to be
6104   // called for cross-domain access.
6105   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6106   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6107                                            IndexedAccessCounter);
6108   Local<v8::Object> object = object_template->NewInstance();
6109 
6110   v8::HandleScope scope1;
6111 
6112   // Create another environment.
6113   v8::Persistent<Context> context1 = Context::New();
6114   context1->Enter();
6115 
6116   // Make easy access to the object from the other environment.
6117   v8::Handle<v8::Object> global1 = context1->Global();
6118   global1->Set(v8_str("obj"), object);
6119 
6120   v8::Handle<Value> value;
6121 
6122   // Check that the named access-control function is called every time.
6123   CompileRun("function testProp(obj) {"
6124              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
6125              "  for (var j = 0; j < 10; j++) obj.prop;"
6126              "  return obj.prop"
6127              "}");
6128   value = CompileRun("testProp(obj)");
6129   CHECK(value->IsNumber());
6130   CHECK_EQ(1, value->Int32Value());
6131   CHECK_EQ(21, named_access_count);
6132 
6133   // Check that the named access-control function is called every time.
6134   CompileRun("var p = 'prop';"
6135              "function testKeyed(obj) {"
6136              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
6137              "  for (var j = 0; j < 10; j++) obj[p];"
6138              "  return obj[p];"
6139              "}");
6140   // Use obj which requires access checks.  No inline caching is used
6141   // in that case.
6142   value = CompileRun("testKeyed(obj)");
6143   CHECK(value->IsNumber());
6144   CHECK_EQ(1, value->Int32Value());
6145   CHECK_EQ(42, named_access_count);
6146   // Force the inline caches into generic state and try again.
6147   CompileRun("testKeyed({ a: 0 })");
6148   CompileRun("testKeyed({ b: 0 })");
6149   value = CompileRun("testKeyed(obj)");
6150   CHECK(value->IsNumber());
6151   CHECK_EQ(1, value->Int32Value());
6152   CHECK_EQ(63, named_access_count);
6153 
6154   // Check that the indexed access-control function is called every time.
6155   CompileRun("function testIndexed(obj) {"
6156              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
6157              "  for (var j = 0; j < 10; j++) obj[0];"
6158              "  return obj[0]"
6159              "}");
6160   value = CompileRun("testIndexed(obj)");
6161   CHECK(value->IsNumber());
6162   CHECK_EQ(1, value->Int32Value());
6163   CHECK_EQ(21, indexed_access_count);
6164   // Force the inline caches into generic state.
6165   CompileRun("testIndexed(new Array(1))");
6166   // Test that the indexed access check is called.
6167   value = CompileRun("testIndexed(obj)");
6168   CHECK(value->IsNumber());
6169   CHECK_EQ(1, value->Int32Value());
6170   CHECK_EQ(42, indexed_access_count);
6171 
6172   // Check that the named access check is called when invoking
6173   // functions on an object that requires access checks.
6174   CompileRun("obj.f = function() {}");
6175   CompileRun("function testCallNormal(obj) {"
6176              "  for (var i = 0; i < 10; i++) obj.f();"
6177              "}");
6178   CompileRun("testCallNormal(obj)");
6179   CHECK_EQ(74, named_access_count);
6180 
6181   // Force obj into slow case.
6182   value = CompileRun("delete obj.prop");
6183   CHECK(value->BooleanValue());
6184   // Force inline caches into dictionary probing mode.
6185   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6186   // Test that the named access check is called.
6187   value = CompileRun("testProp(obj);");
6188   CHECK(value->IsNumber());
6189   CHECK_EQ(1, value->Int32Value());
6190   CHECK_EQ(96, named_access_count);
6191 
6192   // Force the call inline cache into dictionary probing mode.
6193   CompileRun("o.f = function() {}; testCallNormal(o)");
6194   // Test that the named access check is still called for each
6195   // invocation of the function.
6196   value = CompileRun("testCallNormal(obj)");
6197   CHECK_EQ(106, named_access_count);
6198 
6199   context1->Exit();
6200   context0->Exit();
6201   context1.Dispose();
6202   context0.Dispose();
6203 }
6204 
6205 
NamedAccessFlatten(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)6206 static bool NamedAccessFlatten(Local<v8::Object> global,
6207                                Local<Value> name,
6208                                v8::AccessType type,
6209                                Local<Value> data) {
6210   char buf[100];
6211   int len;
6212 
6213   CHECK(name->IsString());
6214 
6215   memset(buf, 0x1, sizeof(buf));
6216   len = name.As<String>()->WriteAscii(buf);
6217   CHECK_EQ(4, len);
6218 
6219   uint16_t buf2[100];
6220 
6221   memset(buf, 0x1, sizeof(buf));
6222   len = name.As<String>()->Write(buf2);
6223   CHECK_EQ(4, len);
6224 
6225   return true;
6226 }
6227 
6228 
IndexedAccessFlatten(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)6229 static bool IndexedAccessFlatten(Local<v8::Object> global,
6230                                  uint32_t key,
6231                                  v8::AccessType type,
6232                                  Local<Value> data) {
6233   return true;
6234 }
6235 
6236 
6237 // Regression test.  In access checks, operations that may cause
6238 // garbage collection are not allowed.  It used to be the case that
6239 // using the Write operation on a string could cause a garbage
6240 // collection due to flattening of the string.  This is no longer the
6241 // case.
THREADED_TEST(AccessControlFlatten)6242 THREADED_TEST(AccessControlFlatten) {
6243   named_access_count = 0;
6244   indexed_access_count = 0;
6245 
6246   v8::HandleScope handle_scope;
6247 
6248   // Create an environment.
6249   v8::Persistent<Context> context0 = Context::New();
6250   context0->Enter();
6251 
6252   // Create an object that requires access-check functions to be
6253   // called for cross-domain access.
6254   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6255   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6256                                            IndexedAccessFlatten);
6257   Local<v8::Object> object = object_template->NewInstance();
6258 
6259   v8::HandleScope scope1;
6260 
6261   // Create another environment.
6262   v8::Persistent<Context> context1 = Context::New();
6263   context1->Enter();
6264 
6265   // Make easy access to the object from the other environment.
6266   v8::Handle<v8::Object> global1 = context1->Global();
6267   global1->Set(v8_str("obj"), object);
6268 
6269   v8::Handle<Value> value;
6270 
6271   value = v8_compile("var p = 'as' + 'df';")->Run();
6272   value = v8_compile("obj[p];")->Run();
6273 
6274   context1->Exit();
6275   context0->Exit();
6276   context1.Dispose();
6277   context0.Dispose();
6278 }
6279 
6280 
AccessControlNamedGetter(Local<String>,const AccessorInfo &)6281 static v8::Handle<Value> AccessControlNamedGetter(
6282     Local<String>, const AccessorInfo&) {
6283   return v8::Integer::New(42);
6284 }
6285 
6286 
AccessControlNamedSetter(Local<String>,Local<Value> value,const AccessorInfo &)6287 static v8::Handle<Value> AccessControlNamedSetter(
6288     Local<String>, Local<Value> value, const AccessorInfo&) {
6289   return value;
6290 }
6291 
6292 
AccessControlIndexedGetter(uint32_t index,const AccessorInfo & info)6293 static v8::Handle<Value> AccessControlIndexedGetter(
6294       uint32_t index,
6295       const AccessorInfo& info) {
6296   return v8_num(42);
6297 }
6298 
6299 
AccessControlIndexedSetter(uint32_t,Local<Value> value,const AccessorInfo &)6300 static v8::Handle<Value> AccessControlIndexedSetter(
6301     uint32_t, Local<Value> value, const AccessorInfo&) {
6302   return value;
6303 }
6304 
6305 
THREADED_TEST(AccessControlInterceptorIC)6306 THREADED_TEST(AccessControlInterceptorIC) {
6307   named_access_count = 0;
6308   indexed_access_count = 0;
6309 
6310   v8::HandleScope handle_scope;
6311 
6312   // Create an environment.
6313   v8::Persistent<Context> context0 = Context::New();
6314   context0->Enter();
6315 
6316   // Create an object that requires access-check functions to be
6317   // called for cross-domain access.  The object also has interceptors
6318   // interceptor.
6319   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6320   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6321                                            IndexedAccessCounter);
6322   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6323                                            AccessControlNamedSetter);
6324   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6325                                              AccessControlIndexedSetter);
6326   Local<v8::Object> object = object_template->NewInstance();
6327 
6328   v8::HandleScope scope1;
6329 
6330   // Create another environment.
6331   v8::Persistent<Context> context1 = Context::New();
6332   context1->Enter();
6333 
6334   // Make easy access to the object from the other environment.
6335   v8::Handle<v8::Object> global1 = context1->Global();
6336   global1->Set(v8_str("obj"), object);
6337 
6338   v8::Handle<Value> value;
6339 
6340   // Check that the named access-control function is called every time
6341   // eventhough there is an interceptor on the object.
6342   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6343   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6344                      "obj.x")->Run();
6345   CHECK(value->IsNumber());
6346   CHECK_EQ(42, value->Int32Value());
6347   CHECK_EQ(21, named_access_count);
6348 
6349   value = v8_compile("var p = 'x';")->Run();
6350   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6351   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6352                      "obj[p]")->Run();
6353   CHECK(value->IsNumber());
6354   CHECK_EQ(42, value->Int32Value());
6355   CHECK_EQ(42, named_access_count);
6356 
6357   // Check that the indexed access-control function is called every
6358   // time eventhough there is an interceptor on the object.
6359   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6360   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6361                      "obj[0]")->Run();
6362   CHECK(value->IsNumber());
6363   CHECK_EQ(42, value->Int32Value());
6364   CHECK_EQ(21, indexed_access_count);
6365 
6366   context1->Exit();
6367   context0->Exit();
6368   context1.Dispose();
6369   context0.Dispose();
6370 }
6371 
6372 
THREADED_TEST(Version)6373 THREADED_TEST(Version) {
6374   v8::V8::GetVersion();
6375 }
6376 
6377 
InstanceFunctionCallback(const v8::Arguments & args)6378 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6379   ApiTestFuzzer::Fuzz();
6380   return v8_num(12);
6381 }
6382 
6383 
THREADED_TEST(InstanceProperties)6384 THREADED_TEST(InstanceProperties) {
6385   v8::HandleScope handle_scope;
6386   LocalContext context;
6387 
6388   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6389   Local<ObjectTemplate> instance = t->InstanceTemplate();
6390 
6391   instance->Set(v8_str("x"), v8_num(42));
6392   instance->Set(v8_str("f"),
6393                 v8::FunctionTemplate::New(InstanceFunctionCallback));
6394 
6395   Local<Value> o = t->GetFunction()->NewInstance();
6396 
6397   context->Global()->Set(v8_str("i"), o);
6398   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6399   CHECK_EQ(42, value->Int32Value());
6400 
6401   value = Script::Compile(v8_str("i.f()"))->Run();
6402   CHECK_EQ(12, value->Int32Value());
6403 }
6404 
6405 
6406 static v8::Handle<Value>
GlobalObjectInstancePropertiesGet(Local<String> key,const AccessorInfo &)6407 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6408   ApiTestFuzzer::Fuzz();
6409   return v8::Handle<Value>();
6410 }
6411 
6412 
THREADED_TEST(GlobalObjectInstanceProperties)6413 THREADED_TEST(GlobalObjectInstanceProperties) {
6414   v8::HandleScope handle_scope;
6415 
6416   Local<Value> global_object;
6417 
6418   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6419   t->InstanceTemplate()->SetNamedPropertyHandler(
6420       GlobalObjectInstancePropertiesGet);
6421   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6422   instance_template->Set(v8_str("x"), v8_num(42));
6423   instance_template->Set(v8_str("f"),
6424                          v8::FunctionTemplate::New(InstanceFunctionCallback));
6425 
6426   // The script to check how Crankshaft compiles missing global function
6427   // invocations.  function g is not defined and should throw on call.
6428   const char* script =
6429       "function wrapper(call) {"
6430       "  var x = 0, y = 1;"
6431       "  for (var i = 0; i < 1000; i++) {"
6432       "    x += i * 100;"
6433       "    y += i * 100;"
6434       "  }"
6435       "  if (call) g();"
6436       "}"
6437       "for (var i = 0; i < 17; i++) wrapper(false);"
6438       "var thrown = 0;"
6439       "try { wrapper(true); } catch (e) { thrown = 1; };"
6440       "thrown";
6441 
6442   {
6443     LocalContext env(NULL, instance_template);
6444     // Hold on to the global object so it can be used again in another
6445     // environment initialization.
6446     global_object = env->Global();
6447 
6448     Local<Value> value = Script::Compile(v8_str("x"))->Run();
6449     CHECK_EQ(42, value->Int32Value());
6450     value = Script::Compile(v8_str("f()"))->Run();
6451     CHECK_EQ(12, value->Int32Value());
6452     value = Script::Compile(v8_str(script))->Run();
6453     CHECK_EQ(1, value->Int32Value());
6454   }
6455 
6456   {
6457     // Create new environment reusing the global object.
6458     LocalContext env(NULL, instance_template, global_object);
6459     Local<Value> value = Script::Compile(v8_str("x"))->Run();
6460     CHECK_EQ(42, value->Int32Value());
6461     value = Script::Compile(v8_str("f()"))->Run();
6462     CHECK_EQ(12, value->Int32Value());
6463     value = Script::Compile(v8_str(script))->Run();
6464     CHECK_EQ(1, value->Int32Value());
6465   }
6466 }
6467 
6468 
THREADED_TEST(CallKnownGlobalReceiver)6469 THREADED_TEST(CallKnownGlobalReceiver) {
6470   v8::HandleScope handle_scope;
6471 
6472   Local<Value> global_object;
6473 
6474   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6475   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6476 
6477   // The script to check that we leave global object not
6478   // global object proxy on stack when we deoptimize from inside
6479   // arguments evaluation.
6480   // To provoke error we need to both force deoptimization
6481   // from arguments evaluation and to force CallIC to take
6482   // CallIC_Miss code path that can't cope with global proxy.
6483   const char* script =
6484       "function bar(x, y) { try { } finally { } }"
6485       "function baz(x) { try { } finally { } }"
6486       "function bom(x) { try { } finally { } }"
6487       "function foo(x) { bar([x], bom(2)); }"
6488       "for (var i = 0; i < 10000; i++) foo(1);"
6489       "foo";
6490 
6491   Local<Value> foo;
6492   {
6493     LocalContext env(NULL, instance_template);
6494     // Hold on to the global object so it can be used again in another
6495     // environment initialization.
6496     global_object = env->Global();
6497     foo = Script::Compile(v8_str(script))->Run();
6498   }
6499 
6500   {
6501     // Create new environment reusing the global object.
6502     LocalContext env(NULL, instance_template, global_object);
6503     env->Global()->Set(v8_str("foo"), foo);
6504     Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
6505   }
6506 }
6507 
6508 
ShadowFunctionCallback(const v8::Arguments & args)6509 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6510   ApiTestFuzzer::Fuzz();
6511   return v8_num(42);
6512 }
6513 
6514 
6515 static int shadow_y;
6516 static int shadow_y_setter_call_count;
6517 static int shadow_y_getter_call_count;
6518 
6519 
ShadowYSetter(Local<String>,Local<Value>,const AccessorInfo &)6520 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
6521   shadow_y_setter_call_count++;
6522   shadow_y = 42;
6523 }
6524 
6525 
ShadowYGetter(Local<String> name,const AccessorInfo & info)6526 static v8::Handle<Value> ShadowYGetter(Local<String> name,
6527                                        const AccessorInfo& info) {
6528   ApiTestFuzzer::Fuzz();
6529   shadow_y_getter_call_count++;
6530   return v8_num(shadow_y);
6531 }
6532 
6533 
ShadowIndexedGet(uint32_t index,const AccessorInfo & info)6534 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6535                                           const AccessorInfo& info) {
6536   return v8::Handle<Value>();
6537 }
6538 
6539 
ShadowNamedGet(Local<String> key,const AccessorInfo &)6540 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6541                                         const AccessorInfo&) {
6542   return v8::Handle<Value>();
6543 }
6544 
6545 
THREADED_TEST(ShadowObject)6546 THREADED_TEST(ShadowObject) {
6547   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6548   v8::HandleScope handle_scope;
6549 
6550   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6551   LocalContext context(NULL, global_template);
6552 
6553   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6554   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6555   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6556   Local<ObjectTemplate> proto = t->PrototypeTemplate();
6557   Local<ObjectTemplate> instance = t->InstanceTemplate();
6558 
6559   // Only allow calls of f on instances of t.
6560   Local<v8::Signature> signature = v8::Signature::New(t);
6561   proto->Set(v8_str("f"),
6562              v8::FunctionTemplate::New(ShadowFunctionCallback,
6563                                        Local<Value>(),
6564                                        signature));
6565   proto->Set(v8_str("x"), v8_num(12));
6566 
6567   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6568 
6569   Local<Value> o = t->GetFunction()->NewInstance();
6570   context->Global()->Set(v8_str("__proto__"), o);
6571 
6572   Local<Value> value =
6573       Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6574   CHECK(value->IsBoolean());
6575   CHECK(!value->BooleanValue());
6576 
6577   value = Script::Compile(v8_str("x"))->Run();
6578   CHECK_EQ(12, value->Int32Value());
6579 
6580   value = Script::Compile(v8_str("f()"))->Run();
6581   CHECK_EQ(42, value->Int32Value());
6582 
6583   Script::Compile(v8_str("y = 42"))->Run();
6584   CHECK_EQ(1, shadow_y_setter_call_count);
6585   value = Script::Compile(v8_str("y"))->Run();
6586   CHECK_EQ(1, shadow_y_getter_call_count);
6587   CHECK_EQ(42, value->Int32Value());
6588 }
6589 
6590 
THREADED_TEST(HiddenPrototype)6591 THREADED_TEST(HiddenPrototype) {
6592   v8::HandleScope handle_scope;
6593   LocalContext context;
6594 
6595   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6596   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6597   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6598   t1->SetHiddenPrototype(true);
6599   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6600   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6601   t2->SetHiddenPrototype(true);
6602   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6603   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6604   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6605 
6606   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6607   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6608   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6609   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6610 
6611   // Setting the prototype on an object skips hidden prototypes.
6612   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6613   o0->Set(v8_str("__proto__"), o1);
6614   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6615   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6616   o0->Set(v8_str("__proto__"), o2);
6617   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6618   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6619   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6620   o0->Set(v8_str("__proto__"), o3);
6621   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6622   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6623   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6624   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6625 
6626   // Getting the prototype of o0 should get the first visible one
6627   // which is o3.  Therefore, z should not be defined on the prototype
6628   // object.
6629   Local<Value> proto = o0->Get(v8_str("__proto__"));
6630   CHECK(proto->IsObject());
6631   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
6632 }
6633 
6634 
THREADED_TEST(SetPrototype)6635 THREADED_TEST(SetPrototype) {
6636   v8::HandleScope handle_scope;
6637   LocalContext context;
6638 
6639   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6640   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6641   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6642   t1->SetHiddenPrototype(true);
6643   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6644   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6645   t2->SetHiddenPrototype(true);
6646   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6647   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6648   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6649 
6650   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6651   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6652   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6653   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6654 
6655   // Setting the prototype on an object does not skip hidden prototypes.
6656   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6657   CHECK(o0->SetPrototype(o1));
6658   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6659   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6660   CHECK(o1->SetPrototype(o2));
6661   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6662   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6663   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6664   CHECK(o2->SetPrototype(o3));
6665   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6666   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6667   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6668   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6669 
6670   // Getting the prototype of o0 should get the first visible one
6671   // which is o3.  Therefore, z should not be defined on the prototype
6672   // object.
6673   Local<Value> proto = o0->Get(v8_str("__proto__"));
6674   CHECK(proto->IsObject());
6675   CHECK_EQ(proto.As<v8::Object>(), o3);
6676 
6677   // However, Object::GetPrototype ignores hidden prototype.
6678   Local<Value> proto0 = o0->GetPrototype();
6679   CHECK(proto0->IsObject());
6680   CHECK_EQ(proto0.As<v8::Object>(), o1);
6681 
6682   Local<Value> proto1 = o1->GetPrototype();
6683   CHECK(proto1->IsObject());
6684   CHECK_EQ(proto1.As<v8::Object>(), o2);
6685 
6686   Local<Value> proto2 = o2->GetPrototype();
6687   CHECK(proto2->IsObject());
6688   CHECK_EQ(proto2.As<v8::Object>(), o3);
6689 }
6690 
6691 
THREADED_TEST(SetPrototypeThrows)6692 THREADED_TEST(SetPrototypeThrows) {
6693   v8::HandleScope handle_scope;
6694   LocalContext context;
6695 
6696   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6697 
6698   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6699   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6700 
6701   CHECK(o0->SetPrototype(o1));
6702   // If setting the prototype leads to the cycle, SetPrototype should
6703   // return false and keep VM in sane state.
6704   v8::TryCatch try_catch;
6705   CHECK(!o1->SetPrototype(o0));
6706   CHECK(!try_catch.HasCaught());
6707   ASSERT(!i::Isolate::Current()->has_pending_exception());
6708 
6709   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6710 }
6711 
6712 
THREADED_TEST(GetterSetterExceptions)6713 THREADED_TEST(GetterSetterExceptions) {
6714   v8::HandleScope handle_scope;
6715   LocalContext context;
6716   CompileRun(
6717     "function Foo() { };"
6718     "function Throw() { throw 5; };"
6719     "var x = { };"
6720     "x.__defineSetter__('set', Throw);"
6721     "x.__defineGetter__('get', Throw);");
6722   Local<v8::Object> x =
6723       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6724   v8::TryCatch try_catch;
6725   x->Set(v8_str("set"), v8::Integer::New(8));
6726   x->Get(v8_str("get"));
6727   x->Set(v8_str("set"), v8::Integer::New(8));
6728   x->Get(v8_str("get"));
6729   x->Set(v8_str("set"), v8::Integer::New(8));
6730   x->Get(v8_str("get"));
6731   x->Set(v8_str("set"), v8::Integer::New(8));
6732   x->Get(v8_str("get"));
6733 }
6734 
6735 
THREADED_TEST(Constructor)6736 THREADED_TEST(Constructor) {
6737   v8::HandleScope handle_scope;
6738   LocalContext context;
6739   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6740   templ->SetClassName(v8_str("Fun"));
6741   Local<Function> cons = templ->GetFunction();
6742   context->Global()->Set(v8_str("Fun"), cons);
6743   Local<v8::Object> inst = cons->NewInstance();
6744   i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6745   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6746   CHECK(value->BooleanValue());
6747 }
6748 
THREADED_TEST(FunctionDescriptorException)6749 THREADED_TEST(FunctionDescriptorException) {
6750   v8::HandleScope handle_scope;
6751   LocalContext context;
6752   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6753   templ->SetClassName(v8_str("Fun"));
6754   Local<Function> cons = templ->GetFunction();
6755   context->Global()->Set(v8_str("Fun"), cons);
6756   Local<Value> value = CompileRun(
6757     "function test() {"
6758     "  try {"
6759     "    (new Fun()).blah()"
6760     "  } catch (e) {"
6761     "    var str = String(e);"
6762     "    if (str.indexOf('TypeError') == -1) return 1;"
6763     "    if (str.indexOf('[object Fun]') != -1) return 2;"
6764     "    if (str.indexOf('#<Fun>') == -1) return 3;"
6765     "    return 0;"
6766     "  }"
6767     "  return 4;"
6768     "}"
6769     "test();");
6770   CHECK_EQ(0, value->Int32Value());
6771 }
6772 
6773 
THREADED_TEST(EvalAliasedDynamic)6774 THREADED_TEST(EvalAliasedDynamic) {
6775   v8::HandleScope scope;
6776   LocalContext current;
6777 
6778   // Tests where aliased eval can only be resolved dynamically.
6779   Local<Script> script =
6780       Script::Compile(v8_str("function f(x) { "
6781                              "  var foo = 2;"
6782                              "  with (x) { return eval('foo'); }"
6783                              "}"
6784                              "foo = 0;"
6785                              "result1 = f(new Object());"
6786                              "result2 = f(this);"
6787                              "var x = new Object();"
6788                              "x.eval = function(x) { return 1; };"
6789                              "result3 = f(x);"));
6790   script->Run();
6791   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6792   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6793   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6794 
6795   v8::TryCatch try_catch;
6796   script =
6797     Script::Compile(v8_str("function f(x) { "
6798                            "  var bar = 2;"
6799                            "  with (x) { return eval('bar'); }"
6800                            "}"
6801                            "f(this)"));
6802   script->Run();
6803   CHECK(try_catch.HasCaught());
6804   try_catch.Reset();
6805 }
6806 
6807 
THREADED_TEST(CrossEval)6808 THREADED_TEST(CrossEval) {
6809   v8::HandleScope scope;
6810   LocalContext other;
6811   LocalContext current;
6812 
6813   Local<String> token = v8_str("<security token>");
6814   other->SetSecurityToken(token);
6815   current->SetSecurityToken(token);
6816 
6817   // Setup reference from current to other.
6818   current->Global()->Set(v8_str("other"), other->Global());
6819 
6820   // Check that new variables are introduced in other context.
6821   Local<Script> script =
6822       Script::Compile(v8_str("other.eval('var foo = 1234')"));
6823   script->Run();
6824   Local<Value> foo = other->Global()->Get(v8_str("foo"));
6825   CHECK_EQ(1234, foo->Int32Value());
6826   CHECK(!current->Global()->Has(v8_str("foo")));
6827 
6828   // Check that writing to non-existing properties introduces them in
6829   // the other context.
6830   script =
6831       Script::Compile(v8_str("other.eval('na = 1234')"));
6832   script->Run();
6833   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6834   CHECK(!current->Global()->Has(v8_str("na")));
6835 
6836   // Check that global variables in current context are not visible in other
6837   // context.
6838   v8::TryCatch try_catch;
6839   script =
6840       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6841   Local<Value> result = script->Run();
6842   CHECK(try_catch.HasCaught());
6843   try_catch.Reset();
6844 
6845   // Check that local variables in current context are not visible in other
6846   // context.
6847   script =
6848       Script::Compile(v8_str("(function() { "
6849                              "  var baz = 87;"
6850                              "  return other.eval('baz');"
6851                              "})();"));
6852   result = script->Run();
6853   CHECK(try_catch.HasCaught());
6854   try_catch.Reset();
6855 
6856   // Check that global variables in the other environment are visible
6857   // when evaluting code.
6858   other->Global()->Set(v8_str("bis"), v8_num(1234));
6859   script = Script::Compile(v8_str("other.eval('bis')"));
6860   CHECK_EQ(1234, script->Run()->Int32Value());
6861   CHECK(!try_catch.HasCaught());
6862 
6863   // Check that the 'this' pointer points to the global object evaluating
6864   // code.
6865   other->Global()->Set(v8_str("t"), other->Global());
6866   script = Script::Compile(v8_str("other.eval('this == t')"));
6867   result = script->Run();
6868   CHECK(result->IsTrue());
6869   CHECK(!try_catch.HasCaught());
6870 
6871   // Check that variables introduced in with-statement are not visible in
6872   // other context.
6873   script =
6874       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6875   result = script->Run();
6876   CHECK(try_catch.HasCaught());
6877   try_catch.Reset();
6878 
6879   // Check that you cannot use 'eval.call' with another object than the
6880   // current global object.
6881   script =
6882       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6883   result = script->Run();
6884   CHECK(try_catch.HasCaught());
6885 }
6886 
6887 
6888 // Test that calling eval in a context which has been detached from
6889 // its global throws an exception.  This behavior is consistent with
6890 // other JavaScript implementations.
THREADED_TEST(EvalInDetachedGlobal)6891 THREADED_TEST(EvalInDetachedGlobal) {
6892   v8::HandleScope scope;
6893 
6894   v8::Persistent<Context> context0 = Context::New();
6895   v8::Persistent<Context> context1 = Context::New();
6896 
6897   // Setup function in context0 that uses eval from context0.
6898   context0->Enter();
6899   v8::Handle<v8::Value> fun =
6900       CompileRun("var x = 42;"
6901                  "(function() {"
6902                  "  var e = eval;"
6903                  "  return function(s) { return e(s); }"
6904                  "})()");
6905   context0->Exit();
6906 
6907   // Put the function into context1 and call it before and after
6908   // detaching the global.  Before detaching, the call succeeds and
6909   // after detaching and exception is thrown.
6910   context1->Enter();
6911   context1->Global()->Set(v8_str("fun"), fun);
6912   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6913   CHECK_EQ(42, x_value->Int32Value());
6914   context0->DetachGlobal();
6915   v8::TryCatch catcher;
6916   x_value = CompileRun("fun('x')");
6917   CHECK(x_value.IsEmpty());
6918   CHECK(catcher.HasCaught());
6919   context1->Exit();
6920 
6921   context1.Dispose();
6922   context0.Dispose();
6923 }
6924 
6925 
THREADED_TEST(CrossLazyLoad)6926 THREADED_TEST(CrossLazyLoad) {
6927   v8::HandleScope scope;
6928   LocalContext other;
6929   LocalContext current;
6930 
6931   Local<String> token = v8_str("<security token>");
6932   other->SetSecurityToken(token);
6933   current->SetSecurityToken(token);
6934 
6935   // Setup reference from current to other.
6936   current->Global()->Set(v8_str("other"), other->Global());
6937 
6938   // Trigger lazy loading in other context.
6939   Local<Script> script =
6940       Script::Compile(v8_str("other.eval('new Date(42)')"));
6941   Local<Value> value = script->Run();
6942   CHECK_EQ(42.0, value->NumberValue());
6943 }
6944 
6945 
call_as_function(const v8::Arguments & args)6946 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6947   ApiTestFuzzer::Fuzz();
6948   if (args.IsConstructCall()) {
6949     if (args[0]->IsInt32()) {
6950        return v8_num(-args[0]->Int32Value());
6951     }
6952   }
6953 
6954   return args[0];
6955 }
6956 
6957 
6958 // Test that a call handler can be set for objects which will allow
6959 // non-function objects created through the API to be called as
6960 // functions.
THREADED_TEST(CallAsFunction)6961 THREADED_TEST(CallAsFunction) {
6962   v8::HandleScope scope;
6963   LocalContext context;
6964 
6965   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6966   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6967   instance_template->SetCallAsFunctionHandler(call_as_function);
6968   Local<v8::Object> instance = t->GetFunction()->NewInstance();
6969   context->Global()->Set(v8_str("obj"), instance);
6970   v8::TryCatch try_catch;
6971   Local<Value> value;
6972   CHECK(!try_catch.HasCaught());
6973 
6974   value = CompileRun("obj(42)");
6975   CHECK(!try_catch.HasCaught());
6976   CHECK_EQ(42, value->Int32Value());
6977 
6978   value = CompileRun("(function(o){return o(49)})(obj)");
6979   CHECK(!try_catch.HasCaught());
6980   CHECK_EQ(49, value->Int32Value());
6981 
6982   // test special case of call as function
6983   value = CompileRun("[obj]['0'](45)");
6984   CHECK(!try_catch.HasCaught());
6985   CHECK_EQ(45, value->Int32Value());
6986 
6987   value = CompileRun("obj.call = Function.prototype.call;"
6988                      "obj.call(null, 87)");
6989   CHECK(!try_catch.HasCaught());
6990   CHECK_EQ(87, value->Int32Value());
6991 
6992   // Regression tests for bug #1116356: Calling call through call/apply
6993   // must work for non-function receivers.
6994   const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6995   value = CompileRun(apply_99);
6996   CHECK(!try_catch.HasCaught());
6997   CHECK_EQ(99, value->Int32Value());
6998 
6999   const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7000   value = CompileRun(call_17);
7001   CHECK(!try_catch.HasCaught());
7002   CHECK_EQ(17, value->Int32Value());
7003 
7004   // Check that the call-as-function handler can be called through
7005   // new.
7006   value = CompileRun("new obj(43)");
7007   CHECK(!try_catch.HasCaught());
7008   CHECK_EQ(-43, value->Int32Value());
7009 }
7010 
7011 
CountHandles()7012 static int CountHandles() {
7013   return v8::HandleScope::NumberOfHandles();
7014 }
7015 
7016 
Recurse(int depth,int iterations)7017 static int Recurse(int depth, int iterations) {
7018   v8::HandleScope scope;
7019   if (depth == 0) return CountHandles();
7020   for (int i = 0; i < iterations; i++) {
7021     Local<v8::Number> n = v8::Integer::New(42);
7022   }
7023   return Recurse(depth - 1, iterations);
7024 }
7025 
7026 
THREADED_TEST(HandleIteration)7027 THREADED_TEST(HandleIteration) {
7028   static const int kIterations = 500;
7029   static const int kNesting = 200;
7030   CHECK_EQ(0, CountHandles());
7031   {
7032     v8::HandleScope scope1;
7033     CHECK_EQ(0, CountHandles());
7034     for (int i = 0; i < kIterations; i++) {
7035       Local<v8::Number> n = v8::Integer::New(42);
7036       CHECK_EQ(i + 1, CountHandles());
7037     }
7038 
7039     CHECK_EQ(kIterations, CountHandles());
7040     {
7041       v8::HandleScope scope2;
7042       for (int j = 0; j < kIterations; j++) {
7043         Local<v8::Number> n = v8::Integer::New(42);
7044         CHECK_EQ(j + 1 + kIterations, CountHandles());
7045       }
7046     }
7047     CHECK_EQ(kIterations, CountHandles());
7048   }
7049   CHECK_EQ(0, CountHandles());
7050   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7051 }
7052 
7053 
InterceptorHasOwnPropertyGetter(Local<String> name,const AccessorInfo & info)7054 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7055     Local<String> name,
7056     const AccessorInfo& info) {
7057   ApiTestFuzzer::Fuzz();
7058   return v8::Handle<Value>();
7059 }
7060 
7061 
THREADED_TEST(InterceptorHasOwnProperty)7062 THREADED_TEST(InterceptorHasOwnProperty) {
7063   v8::HandleScope scope;
7064   LocalContext context;
7065   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7066   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7067   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7068   Local<Function> function = fun_templ->GetFunction();
7069   context->Global()->Set(v8_str("constructor"), function);
7070   v8::Handle<Value> value = CompileRun(
7071       "var o = new constructor();"
7072       "o.hasOwnProperty('ostehaps');");
7073   CHECK_EQ(false, value->BooleanValue());
7074   value = CompileRun(
7075       "o.ostehaps = 42;"
7076       "o.hasOwnProperty('ostehaps');");
7077   CHECK_EQ(true, value->BooleanValue());
7078   value = CompileRun(
7079       "var p = new constructor();"
7080       "p.hasOwnProperty('ostehaps');");
7081   CHECK_EQ(false, value->BooleanValue());
7082 }
7083 
7084 
InterceptorHasOwnPropertyGetterGC(Local<String> name,const AccessorInfo & info)7085 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7086     Local<String> name,
7087     const AccessorInfo& info) {
7088   ApiTestFuzzer::Fuzz();
7089   HEAP->CollectAllGarbage(false);
7090   return v8::Handle<Value>();
7091 }
7092 
7093 
THREADED_TEST(InterceptorHasOwnPropertyCausingGC)7094 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7095   v8::HandleScope scope;
7096   LocalContext context;
7097   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7098   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7099   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7100   Local<Function> function = fun_templ->GetFunction();
7101   context->Global()->Set(v8_str("constructor"), function);
7102   // Let's first make some stuff so we can be sure to get a good GC.
7103   CompileRun(
7104       "function makestr(size) {"
7105       "  switch (size) {"
7106       "    case 1: return 'f';"
7107       "    case 2: return 'fo';"
7108       "    case 3: return 'foo';"
7109       "  }"
7110       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
7111       "}"
7112       "var x = makestr(12345);"
7113       "x = makestr(31415);"
7114       "x = makestr(23456);");
7115   v8::Handle<Value> value = CompileRun(
7116       "var o = new constructor();"
7117       "o.__proto__ = new String(x);"
7118       "o.hasOwnProperty('ostehaps');");
7119   CHECK_EQ(false, value->BooleanValue());
7120 }
7121 
7122 
7123 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7124                                                  const AccessorInfo& info);
7125 
7126 
CheckInterceptorLoadIC(NamedPropertyGetter getter,const char * source,int expected)7127 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7128                                    const char* source,
7129                                    int expected) {
7130   v8::HandleScope scope;
7131   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7132   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
7133   LocalContext context;
7134   context->Global()->Set(v8_str("o"), templ->NewInstance());
7135   v8::Handle<Value> value = CompileRun(source);
7136   CHECK_EQ(expected, value->Int32Value());
7137 }
7138 
7139 
InterceptorLoadICGetter(Local<String> name,const AccessorInfo & info)7140 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7141                                                  const AccessorInfo& info) {
7142   ApiTestFuzzer::Fuzz();
7143   CHECK_EQ(v8_str("data"), info.Data());
7144   CHECK_EQ(v8_str("x"), name);
7145   return v8::Integer::New(42);
7146 }
7147 
7148 
7149 // This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC)7150 THREADED_TEST(InterceptorLoadIC) {
7151   CheckInterceptorLoadIC(InterceptorLoadICGetter,
7152     "var result = 0;"
7153     "for (var i = 0; i < 1000; i++) {"
7154     "  result = o.x;"
7155     "}",
7156     42);
7157 }
7158 
7159 
7160 // Below go several tests which verify that JITing for various
7161 // configurations of interceptor and explicit fields works fine
7162 // (those cases are special cased to get better performance).
7163 
InterceptorLoadXICGetter(Local<String> name,const AccessorInfo & info)7164 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7165                                                  const AccessorInfo& info) {
7166   ApiTestFuzzer::Fuzz();
7167   return v8_str("x")->Equals(name)
7168       ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7169 }
7170 
7171 
THREADED_TEST(InterceptorLoadICWithFieldOnHolder)7172 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7173   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7174     "var result = 0;"
7175     "o.y = 239;"
7176     "for (var i = 0; i < 1000; i++) {"
7177     "  result = o.y;"
7178     "}",
7179     239);
7180 }
7181 
7182 
THREADED_TEST(InterceptorLoadICWithSubstitutedProto)7183 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7184   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7185     "var result = 0;"
7186     "o.__proto__ = { 'y': 239 };"
7187     "for (var i = 0; i < 1000; i++) {"
7188     "  result = o.y + o.x;"
7189     "}",
7190     239 + 42);
7191 }
7192 
7193 
THREADED_TEST(InterceptorLoadICWithPropertyOnProto)7194 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7195   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7196     "var result = 0;"
7197     "o.__proto__.y = 239;"
7198     "for (var i = 0; i < 1000; i++) {"
7199     "  result = o.y + o.x;"
7200     "}",
7201     239 + 42);
7202 }
7203 
7204 
THREADED_TEST(InterceptorLoadICUndefined)7205 THREADED_TEST(InterceptorLoadICUndefined) {
7206   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7207     "var result = 0;"
7208     "for (var i = 0; i < 1000; i++) {"
7209     "  result = (o.y == undefined) ? 239 : 42;"
7210     "}",
7211     239);
7212 }
7213 
7214 
THREADED_TEST(InterceptorLoadICWithOverride)7215 THREADED_TEST(InterceptorLoadICWithOverride) {
7216   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7217     "fst = new Object();  fst.__proto__ = o;"
7218     "snd = new Object();  snd.__proto__ = fst;"
7219     "var result1 = 0;"
7220     "for (var i = 0; i < 1000;  i++) {"
7221     "  result1 = snd.x;"
7222     "}"
7223     "fst.x = 239;"
7224     "var result = 0;"
7225     "for (var i = 0; i < 1000; i++) {"
7226     "  result = snd.x;"
7227     "}"
7228     "result + result1",
7229     239 + 42);
7230 }
7231 
7232 
7233 // Test the case when we stored field into
7234 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICFieldNotNeeded)7235 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7236   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7237     "proto = new Object();"
7238     "o.__proto__ = proto;"
7239     "proto.x = 239;"
7240     "for (var i = 0; i < 1000; i++) {"
7241     "  o.x;"
7242     // Now it should be ICed and keep a reference to x defined on proto
7243     "}"
7244     "var result = 0;"
7245     "for (var i = 0; i < 1000; i++) {"
7246     "  result += o.x;"
7247     "}"
7248     "result;",
7249     42 * 1000);
7250 }
7251 
7252 
7253 // Test the case when we stored field into
7254 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedField)7255 THREADED_TEST(InterceptorLoadICInvalidatedField) {
7256   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7257     "proto1 = new Object();"
7258     "proto2 = new Object();"
7259     "o.__proto__ = proto1;"
7260     "proto1.__proto__ = proto2;"
7261     "proto2.y = 239;"
7262     "for (var i = 0; i < 1000; i++) {"
7263     "  o.y;"
7264     // Now it should be ICed and keep a reference to y defined on proto2
7265     "}"
7266     "proto1.y = 42;"
7267     "var result = 0;"
7268     "for (var i = 0; i < 1000; i++) {"
7269     "  result += o.y;"
7270     "}"
7271     "result;",
7272     42 * 1000);
7273 }
7274 
7275 
7276 static int interceptor_load_not_handled_calls = 0;
InterceptorLoadNotHandled(Local<String> name,const AccessorInfo & info)7277 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7278                                                    const AccessorInfo& info) {
7279   ++interceptor_load_not_handled_calls;
7280   return v8::Handle<v8::Value>();
7281 }
7282 
7283 
7284 // Test how post-interceptor lookups are done in the non-cacheable
7285 // case: the interceptor should not be invoked during this lookup.
THREADED_TEST(InterceptorLoadICPostInterceptor)7286 THREADED_TEST(InterceptorLoadICPostInterceptor) {
7287   interceptor_load_not_handled_calls = 0;
7288   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7289     "receiver = new Object();"
7290     "receiver.__proto__ = o;"
7291     "proto = new Object();"
7292     "/* Make proto a slow-case object. */"
7293     "for (var i = 0; i < 1000; i++) {"
7294     "  proto[\"xxxxxxxx\" + i] = [];"
7295     "}"
7296     "proto.x = 17;"
7297     "o.__proto__ = proto;"
7298     "var result = 0;"
7299     "for (var i = 0; i < 1000; i++) {"
7300     "  result += receiver.x;"
7301     "}"
7302     "result;",
7303     17 * 1000);
7304   CHECK_EQ(1000, interceptor_load_not_handled_calls);
7305 }
7306 
7307 
7308 // Test the case when we stored field into
7309 // a stub, but it got invalidated later on due to override on
7310 // global object which is between interceptor and fields' holders.
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal)7311 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7312   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7313     "o.__proto__ = this;"  // set a global to be a proto of o.
7314     "this.__proto__.y = 239;"
7315     "for (var i = 0; i < 10; i++) {"
7316     "  if (o.y != 239) throw 'oops: ' + o.y;"
7317     // Now it should be ICed and keep a reference to y defined on field_holder.
7318     "}"
7319     "this.y = 42;"  // Assign on a global.
7320     "var result = 0;"
7321     "for (var i = 0; i < 10; i++) {"
7322     "  result += o.y;"
7323     "}"
7324     "result;",
7325     42 * 10);
7326 }
7327 
7328 
SetOnThis(Local<String> name,Local<Value> value,const AccessorInfo & info)7329 static void SetOnThis(Local<String> name,
7330                       Local<Value> value,
7331                       const AccessorInfo& info) {
7332   info.This()->ForceSet(name, value);
7333 }
7334 
7335 
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder)7336 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
7337   v8::HandleScope scope;
7338   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7339   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7340   templ->SetAccessor(v8_str("y"), Return239);
7341   LocalContext context;
7342   context->Global()->Set(v8_str("o"), templ->NewInstance());
7343 
7344   // Check the case when receiver and interceptor's holder
7345   // are the same objects.
7346   v8::Handle<Value> value = CompileRun(
7347       "var result = 0;"
7348       "for (var i = 0; i < 7; i++) {"
7349       "  result = o.y;"
7350       "}");
7351   CHECK_EQ(239, value->Int32Value());
7352 
7353   // Check the case when interceptor's holder is in proto chain
7354   // of receiver.
7355   value = CompileRun(
7356       "r = { __proto__: o };"
7357       "var result = 0;"
7358       "for (var i = 0; i < 7; i++) {"
7359       "  result = r.y;"
7360       "}");
7361   CHECK_EQ(239, value->Int32Value());
7362 }
7363 
7364 
THREADED_TEST(InterceptorLoadICWithCallbackOnProto)7365 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
7366   v8::HandleScope scope;
7367   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7368   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7369   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7370   templ_p->SetAccessor(v8_str("y"), Return239);
7371 
7372   LocalContext context;
7373   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7374   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7375 
7376   // Check the case when receiver and interceptor's holder
7377   // are the same objects.
7378   v8::Handle<Value> value = CompileRun(
7379       "o.__proto__ = p;"
7380       "var result = 0;"
7381       "for (var i = 0; i < 7; i++) {"
7382       "  result = o.x + o.y;"
7383       "}");
7384   CHECK_EQ(239 + 42, value->Int32Value());
7385 
7386   // Check the case when interceptor's holder is in proto chain
7387   // of receiver.
7388   value = CompileRun(
7389       "r = { __proto__: o };"
7390       "var result = 0;"
7391       "for (var i = 0; i < 7; i++) {"
7392       "  result = r.x + r.y;"
7393       "}");
7394   CHECK_EQ(239 + 42, value->Int32Value());
7395 }
7396 
7397 
THREADED_TEST(InterceptorLoadICForCallbackWithOverride)7398 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
7399   v8::HandleScope scope;
7400   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7401   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7402   templ->SetAccessor(v8_str("y"), Return239);
7403 
7404   LocalContext context;
7405   context->Global()->Set(v8_str("o"), templ->NewInstance());
7406 
7407   v8::Handle<Value> value = CompileRun(
7408     "fst = new Object();  fst.__proto__ = o;"
7409     "snd = new Object();  snd.__proto__ = fst;"
7410     "var result1 = 0;"
7411     "for (var i = 0; i < 7;  i++) {"
7412     "  result1 = snd.x;"
7413     "}"
7414     "fst.x = 239;"
7415     "var result = 0;"
7416     "for (var i = 0; i < 7; i++) {"
7417     "  result = snd.x;"
7418     "}"
7419     "result + result1");
7420   CHECK_EQ(239 + 42, value->Int32Value());
7421 }
7422 
7423 
7424 // Test the case when we stored callback into
7425 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICCallbackNotNeeded)7426 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
7427   v8::HandleScope scope;
7428   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7429   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7430   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7431   templ_p->SetAccessor(v8_str("y"), Return239);
7432 
7433   LocalContext context;
7434   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7435   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7436 
7437   v8::Handle<Value> value = CompileRun(
7438     "o.__proto__ = p;"
7439     "for (var i = 0; i < 7; i++) {"
7440     "  o.x;"
7441     // Now it should be ICed and keep a reference to x defined on p
7442     "}"
7443     "var result = 0;"
7444     "for (var i = 0; i < 7; i++) {"
7445     "  result += o.x;"
7446     "}"
7447     "result");
7448   CHECK_EQ(42 * 7, value->Int32Value());
7449 }
7450 
7451 
7452 // Test the case when we stored callback into
7453 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedCallback)7454 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
7455   v8::HandleScope scope;
7456   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7457   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7458   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7459   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7460 
7461   LocalContext context;
7462   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7463   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7464 
7465   v8::Handle<Value> value = CompileRun(
7466     "inbetween = new Object();"
7467     "o.__proto__ = inbetween;"
7468     "inbetween.__proto__ = p;"
7469     "for (var i = 0; i < 10; i++) {"
7470     "  o.y;"
7471     // Now it should be ICed and keep a reference to y defined on p
7472     "}"
7473     "inbetween.y = 42;"
7474     "var result = 0;"
7475     "for (var i = 0; i < 10; i++) {"
7476     "  result += o.y;"
7477     "}"
7478     "result");
7479   CHECK_EQ(42 * 10, value->Int32Value());
7480 }
7481 
7482 
7483 // Test the case when we stored callback into
7484 // a stub, but it got invalidated later on due to override on
7485 // global object which is between interceptor and callbacks' holders.
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal)7486 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
7487   v8::HandleScope scope;
7488   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7489   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7490   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7491   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7492 
7493   LocalContext context;
7494   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7495   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7496 
7497   v8::Handle<Value> value = CompileRun(
7498     "o.__proto__ = this;"
7499     "this.__proto__ = p;"
7500     "for (var i = 0; i < 10; i++) {"
7501     "  if (o.y != 239) throw 'oops: ' + o.y;"
7502     // Now it should be ICed and keep a reference to y defined on p
7503     "}"
7504     "this.y = 42;"
7505     "var result = 0;"
7506     "for (var i = 0; i < 10; i++) {"
7507     "  result += o.y;"
7508     "}"
7509     "result");
7510   CHECK_EQ(42 * 10, value->Int32Value());
7511 }
7512 
7513 
InterceptorLoadICGetter0(Local<String> name,const AccessorInfo & info)7514 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7515                                                   const AccessorInfo& info) {
7516   ApiTestFuzzer::Fuzz();
7517   CHECK(v8_str("x")->Equals(name));
7518   return v8::Integer::New(0);
7519 }
7520 
7521 
THREADED_TEST(InterceptorReturningZero)7522 THREADED_TEST(InterceptorReturningZero) {
7523   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7524      "o.x == undefined ? 1 : 0",
7525      0);
7526 }
7527 
7528 
InterceptorStoreICSetter(Local<String> key,Local<Value> value,const AccessorInfo &)7529 static v8::Handle<Value> InterceptorStoreICSetter(
7530     Local<String> key, Local<Value> value, const AccessorInfo&) {
7531   CHECK(v8_str("x")->Equals(key));
7532   CHECK_EQ(42, value->Int32Value());
7533   return value;
7534 }
7535 
7536 
7537 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)7538 THREADED_TEST(InterceptorStoreIC) {
7539   v8::HandleScope scope;
7540   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7541   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
7542                                  InterceptorStoreICSetter,
7543                                  0, 0, 0, v8_str("data"));
7544   LocalContext context;
7545   context->Global()->Set(v8_str("o"), templ->NewInstance());
7546   v8::Handle<Value> value = CompileRun(
7547     "for (var i = 0; i < 1000; i++) {"
7548     "  o.x = 42;"
7549     "}");
7550 }
7551 
7552 
THREADED_TEST(InterceptorStoreICWithNoSetter)7553 THREADED_TEST(InterceptorStoreICWithNoSetter) {
7554   v8::HandleScope scope;
7555   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7556   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7557   LocalContext context;
7558   context->Global()->Set(v8_str("o"), templ->NewInstance());
7559   v8::Handle<Value> value = CompileRun(
7560     "for (var i = 0; i < 1000; i++) {"
7561     "  o.y = 239;"
7562     "}"
7563     "42 + o.y");
7564   CHECK_EQ(239 + 42, value->Int32Value());
7565 }
7566 
7567 
7568 
7569 
7570 v8::Handle<Value> call_ic_function;
7571 v8::Handle<Value> call_ic_function2;
7572 v8::Handle<Value> call_ic_function3;
7573 
InterceptorCallICGetter(Local<String> name,const AccessorInfo & info)7574 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7575                                                  const AccessorInfo& info) {
7576   ApiTestFuzzer::Fuzz();
7577   CHECK(v8_str("x")->Equals(name));
7578   return call_ic_function;
7579 }
7580 
7581 
7582 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)7583 THREADED_TEST(InterceptorCallIC) {
7584   v8::HandleScope scope;
7585   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7586   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7587   LocalContext context;
7588   context->Global()->Set(v8_str("o"), templ->NewInstance());
7589   call_ic_function =
7590       v8_compile("function f(x) { return x + 1; }; f")->Run();
7591   v8::Handle<Value> value = CompileRun(
7592     "var result = 0;"
7593     "for (var i = 0; i < 1000; i++) {"
7594     "  result = o.x(41);"
7595     "}");
7596   CHECK_EQ(42, value->Int32Value());
7597 }
7598 
7599 
7600 // This test checks that if interceptor doesn't provide
7601 // a value, we can fetch regular value.
THREADED_TEST(InterceptorCallICSeesOthers)7602 THREADED_TEST(InterceptorCallICSeesOthers) {
7603   v8::HandleScope scope;
7604   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7605   templ->SetNamedPropertyHandler(NoBlockGetterX);
7606   LocalContext context;
7607   context->Global()->Set(v8_str("o"), templ->NewInstance());
7608   v8::Handle<Value> value = CompileRun(
7609     "o.x = function f(x) { return x + 1; };"
7610     "var result = 0;"
7611     "for (var i = 0; i < 7; i++) {"
7612     "  result = o.x(41);"
7613     "}");
7614   CHECK_EQ(42, value->Int32Value());
7615 }
7616 
7617 
7618 static v8::Handle<Value> call_ic_function4;
InterceptorCallICGetter4(Local<String> name,const AccessorInfo & info)7619 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7620                                                   const AccessorInfo& info) {
7621   ApiTestFuzzer::Fuzz();
7622   CHECK(v8_str("x")->Equals(name));
7623   return call_ic_function4;
7624 }
7625 
7626 
7627 // This test checks that if interceptor provides a function,
7628 // even if we cached shadowed variant, interceptor's function
7629 // is invoked
THREADED_TEST(InterceptorCallICCacheableNotNeeded)7630 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7631   v8::HandleScope scope;
7632   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7633   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7634   LocalContext context;
7635   context->Global()->Set(v8_str("o"), templ->NewInstance());
7636   call_ic_function4 =
7637       v8_compile("function f(x) { return x - 1; }; f")->Run();
7638   v8::Handle<Value> value = CompileRun(
7639     "o.__proto__.x = function(x) { return x + 1; };"
7640     "var result = 0;"
7641     "for (var i = 0; i < 1000; i++) {"
7642     "  result = o.x(42);"
7643     "}");
7644   CHECK_EQ(41, value->Int32Value());
7645 }
7646 
7647 
7648 // Test the case when we stored cacheable lookup into
7649 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedCacheable)7650 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7651   v8::HandleScope scope;
7652   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7653   templ->SetNamedPropertyHandler(NoBlockGetterX);
7654   LocalContext context;
7655   context->Global()->Set(v8_str("o"), templ->NewInstance());
7656   v8::Handle<Value> value = CompileRun(
7657     "proto1 = new Object();"
7658     "proto2 = new Object();"
7659     "o.__proto__ = proto1;"
7660     "proto1.__proto__ = proto2;"
7661     "proto2.y = function(x) { return x + 1; };"
7662     // Invoke it many times to compile a stub
7663     "for (var i = 0; i < 7; i++) {"
7664     "  o.y(42);"
7665     "}"
7666     "proto1.y = function(x) { return x - 1; };"
7667     "var result = 0;"
7668     "for (var i = 0; i < 7; i++) {"
7669     "  result += o.y(42);"
7670     "}");
7671   CHECK_EQ(41 * 7, value->Int32Value());
7672 }
7673 
7674 
7675 static v8::Handle<Value> call_ic_function5;
InterceptorCallICGetter5(Local<String> name,const AccessorInfo & info)7676 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7677                                                   const AccessorInfo& info) {
7678   ApiTestFuzzer::Fuzz();
7679   if (v8_str("x")->Equals(name))
7680     return call_ic_function5;
7681   else
7682     return Local<Value>();
7683 }
7684 
7685 
7686 // This test checks that if interceptor doesn't provide a function,
7687 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)7688 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7689   v8::HandleScope scope;
7690   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7691   templ->SetNamedPropertyHandler(NoBlockGetterX);
7692   LocalContext context;
7693   context->Global()->Set(v8_str("o"), templ->NewInstance());
7694   v8::Handle<Value> value = CompileRun(
7695     "function inc(x) { return x + 1; };"
7696     "inc(1);"
7697     "o.x = inc;"
7698     "var result = 0;"
7699     "for (var i = 0; i < 1000; i++) {"
7700     "  result = o.x(42);"
7701     "}");
7702   CHECK_EQ(43, value->Int32Value());
7703 }
7704 
7705 
7706 // This test checks that if interceptor provides a function,
7707 // even if we cached constant function, interceptor's function
7708 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)7709 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7710   v8::HandleScope scope;
7711   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7712   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7713   LocalContext context;
7714   context->Global()->Set(v8_str("o"), templ->NewInstance());
7715   call_ic_function5 =
7716       v8_compile("function f(x) { return x - 1; }; f")->Run();
7717   v8::Handle<Value> value = CompileRun(
7718     "function inc(x) { return x + 1; };"
7719     "inc(1);"
7720     "o.x = inc;"
7721     "var result = 0;"
7722     "for (var i = 0; i < 1000; i++) {"
7723     "  result = o.x(42);"
7724     "}");
7725   CHECK_EQ(41, value->Int32Value());
7726 }
7727 
7728 
7729 // Test the case when we stored constant function into
7730 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)7731 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7732   v8::HandleScope scope;
7733   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7734   templ->SetNamedPropertyHandler(NoBlockGetterX);
7735   LocalContext context;
7736   context->Global()->Set(v8_str("o"), templ->NewInstance());
7737   v8::Handle<Value> value = CompileRun(
7738     "function inc(x) { return x + 1; };"
7739     "inc(1);"
7740     "proto1 = new Object();"
7741     "proto2 = new Object();"
7742     "o.__proto__ = proto1;"
7743     "proto1.__proto__ = proto2;"
7744     "proto2.y = inc;"
7745     // Invoke it many times to compile a stub
7746     "for (var i = 0; i < 7; i++) {"
7747     "  o.y(42);"
7748     "}"
7749     "proto1.y = function(x) { return x - 1; };"
7750     "var result = 0;"
7751     "for (var i = 0; i < 7; i++) {"
7752     "  result += o.y(42);"
7753     "}");
7754   CHECK_EQ(41 * 7, value->Int32Value());
7755 }
7756 
7757 
7758 // Test the case when we stored constant function into
7759 // a stub, but it got invalidated later on due to override on
7760 // global object which is between interceptor and constant function' holders.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)7761 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7762   v8::HandleScope scope;
7763   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7764   templ->SetNamedPropertyHandler(NoBlockGetterX);
7765   LocalContext context;
7766   context->Global()->Set(v8_str("o"), templ->NewInstance());
7767   v8::Handle<Value> value = CompileRun(
7768     "function inc(x) { return x + 1; };"
7769     "inc(1);"
7770     "o.__proto__ = this;"
7771     "this.__proto__.y = inc;"
7772     // Invoke it many times to compile a stub
7773     "for (var i = 0; i < 7; i++) {"
7774     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7775     "}"
7776     "this.y = function(x) { return x - 1; };"
7777     "var result = 0;"
7778     "for (var i = 0; i < 7; i++) {"
7779     "  result += o.y(42);"
7780     "}");
7781   CHECK_EQ(41 * 7, value->Int32Value());
7782 }
7783 
7784 
7785 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorCallICCachedFromGlobal)7786 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7787   v8::HandleScope scope;
7788   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7789   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7790 
7791   LocalContext context;
7792   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7793 
7794   v8::Handle<Value> value = CompileRun(
7795     "try {"
7796     "  o.__proto__ = this;"
7797     "  for (var i = 0; i < 10; i++) {"
7798     "    var v = o.parseFloat('239');"
7799     "    if (v != 239) throw v;"
7800       // Now it should be ICed and keep a reference to parseFloat.
7801     "  }"
7802     "  var result = 0;"
7803     "  for (var i = 0; i < 10; i++) {"
7804     "    result += o.parseFloat('239');"
7805     "  }"
7806     "  result"
7807     "} catch(e) {"
7808     "  e"
7809     "};");
7810   CHECK_EQ(239 * 10, value->Int32Value());
7811 }
7812 
InterceptorCallICFastApi(Local<String> name,const AccessorInfo & info)7813 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7814                                                   const AccessorInfo& info) {
7815   ApiTestFuzzer::Fuzz();
7816   int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7817   ++(*call_count);
7818   if ((*call_count) % 20 == 0) {
7819     HEAP->CollectAllGarbage(true);
7820   }
7821   return v8::Handle<Value>();
7822 }
7823 
FastApiCallback_TrivialSignature(const v8::Arguments & args)7824 static v8::Handle<Value> FastApiCallback_TrivialSignature(
7825     const v8::Arguments& args) {
7826   ApiTestFuzzer::Fuzz();
7827   CHECK_EQ(args.This(), args.Holder());
7828   CHECK(args.Data()->Equals(v8_str("method_data")));
7829   return v8::Integer::New(args[0]->Int32Value() + 1);
7830 }
7831 
FastApiCallback_SimpleSignature(const v8::Arguments & args)7832 static v8::Handle<Value> FastApiCallback_SimpleSignature(
7833     const v8::Arguments& args) {
7834   ApiTestFuzzer::Fuzz();
7835   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7836   CHECK(args.Data()->Equals(v8_str("method_data")));
7837   // Note, we're using HasRealNamedProperty instead of Has to avoid
7838   // invoking the interceptor again.
7839   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7840   return v8::Integer::New(args[0]->Int32Value() + 1);
7841 }
7842 
7843 // Helper to maximize the odds of object moving.
GenerateSomeGarbage()7844 static void GenerateSomeGarbage() {
7845   CompileRun(
7846       "var garbage;"
7847       "for (var i = 0; i < 1000; i++) {"
7848       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7849       "}"
7850       "garbage = undefined;");
7851 }
7852 
7853 
DirectApiCallback(const v8::Arguments & args)7854 v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
7855   static int count = 0;
7856   if (count++ % 3 == 0) {
7857     HEAP->  CollectAllGarbage(true);  // This should move the stub
7858     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
7859   }
7860   return v8::Handle<v8::Value>();
7861 }
7862 
7863 
THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub)7864 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
7865   v8::HandleScope scope;
7866   LocalContext context;
7867   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7868   nativeobject_templ->Set("callback",
7869                           v8::FunctionTemplate::New(DirectApiCallback));
7870   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7871   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7872   // call the api function multiple times to ensure direct call stub creation.
7873   CompileRun(
7874         "function f() {"
7875         "  for (var i = 1; i <= 30; i++) {"
7876         "    nativeobject.callback();"
7877         "  }"
7878         "}"
7879         "f();");
7880 }
7881 
7882 
ThrowingDirectApiCallback(const v8::Arguments & args)7883 v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
7884   return v8::ThrowException(v8_str("g"));
7885 }
7886 
7887 
THREADED_TEST(CallICFastApi_DirectCall_Throw)7888 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
7889   v8::HandleScope scope;
7890   LocalContext context;
7891   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7892   nativeobject_templ->Set("callback",
7893                           v8::FunctionTemplate::New(ThrowingDirectApiCallback));
7894   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7895   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7896   // call the api function multiple times to ensure direct call stub creation.
7897   v8::Handle<Value> result = CompileRun(
7898       "var result = '';"
7899       "function f() {"
7900       "  for (var i = 1; i <= 5; i++) {"
7901       "    try { nativeobject.callback(); } catch (e) { result += e; }"
7902       "  }"
7903       "}"
7904       "f(); result;");
7905   CHECK_EQ(v8_str("ggggg"), result);
7906 }
7907 
7908 
DirectGetterCallback(Local<String> name,const v8::AccessorInfo & info)7909 v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
7910                                            const v8::AccessorInfo& info) {
7911   if (++p_getter_count % 3 == 0) {
7912     HEAP->CollectAllGarbage(true);
7913     GenerateSomeGarbage();
7914   }
7915   return v8::Handle<v8::Value>();
7916 }
7917 
7918 
THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub)7919 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
7920   v8::HandleScope scope;
7921   LocalContext context;
7922   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7923   obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
7924   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7925   p_getter_count = 0;
7926   CompileRun(
7927       "function f() {"
7928       "  for (var i = 0; i < 30; i++) o1.p1;"
7929       "}"
7930       "f();");
7931   CHECK_EQ(30, p_getter_count);
7932 }
7933 
7934 
ThrowingDirectGetterCallback(Local<String> name,const v8::AccessorInfo & info)7935 v8::Handle<v8::Value> ThrowingDirectGetterCallback(
7936     Local<String> name, const v8::AccessorInfo& info) {
7937   return v8::ThrowException(v8_str("g"));
7938 }
7939 
7940 
THREADED_TEST(LoadICFastApi_DirectCall_Throw)7941 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
7942   v8::HandleScope scope;
7943   LocalContext context;
7944   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7945   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
7946   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7947   v8::Handle<Value> result = CompileRun(
7948       "var result = '';"
7949       "for (var i = 0; i < 5; i++) {"
7950       "    try { o1.p1; } catch (e) { result += e; }"
7951       "}"
7952       "result;");
7953   CHECK_EQ(v8_str("ggggg"), result);
7954 }
7955 
7956 
THREADED_TEST(InterceptorCallICFastApi_TrivialSignature)7957 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7958   int interceptor_call_count = 0;
7959   v8::HandleScope scope;
7960   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7961   v8::Handle<v8::FunctionTemplate> method_templ =
7962       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7963                                 v8_str("method_data"),
7964                                 v8::Handle<v8::Signature>());
7965   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7966   proto_templ->Set(v8_str("method"), method_templ);
7967   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7968   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7969                                  NULL, NULL, NULL, NULL,
7970                                  v8::External::Wrap(&interceptor_call_count));
7971   LocalContext context;
7972   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7973   GenerateSomeGarbage();
7974   context->Global()->Set(v8_str("o"), fun->NewInstance());
7975   v8::Handle<Value> value = CompileRun(
7976       "var result = 0;"
7977       "for (var i = 0; i < 100; i++) {"
7978       "  result = o.method(41);"
7979       "}");
7980   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7981   CHECK_EQ(100, interceptor_call_count);
7982 }
7983 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature)7984 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7985   int interceptor_call_count = 0;
7986   v8::HandleScope scope;
7987   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7988   v8::Handle<v8::FunctionTemplate> method_templ =
7989       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7990                                 v8_str("method_data"),
7991                                 v8::Signature::New(fun_templ));
7992   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7993   proto_templ->Set(v8_str("method"), method_templ);
7994   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7995   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7996                                  NULL, NULL, NULL, NULL,
7997                                  v8::External::Wrap(&interceptor_call_count));
7998   LocalContext context;
7999   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8000   GenerateSomeGarbage();
8001   context->Global()->Set(v8_str("o"), fun->NewInstance());
8002   v8::Handle<Value> value = CompileRun(
8003       "o.foo = 17;"
8004       "var receiver = {};"
8005       "receiver.__proto__ = o;"
8006       "var result = 0;"
8007       "for (var i = 0; i < 100; i++) {"
8008       "  result = receiver.method(41);"
8009       "}");
8010   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8011   CHECK_EQ(100, interceptor_call_count);
8012 }
8013 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1)8014 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8015   int interceptor_call_count = 0;
8016   v8::HandleScope scope;
8017   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8018   v8::Handle<v8::FunctionTemplate> method_templ =
8019       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8020                                 v8_str("method_data"),
8021                                 v8::Signature::New(fun_templ));
8022   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8023   proto_templ->Set(v8_str("method"), method_templ);
8024   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8025   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8026                                  NULL, NULL, NULL, NULL,
8027                                  v8::External::Wrap(&interceptor_call_count));
8028   LocalContext context;
8029   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8030   GenerateSomeGarbage();
8031   context->Global()->Set(v8_str("o"), fun->NewInstance());
8032   v8::Handle<Value> value = CompileRun(
8033       "o.foo = 17;"
8034       "var receiver = {};"
8035       "receiver.__proto__ = o;"
8036       "var result = 0;"
8037       "var saved_result = 0;"
8038       "for (var i = 0; i < 100; i++) {"
8039       "  result = receiver.method(41);"
8040       "  if (i == 50) {"
8041       "    saved_result = result;"
8042       "    receiver = {method: function(x) { return x - 1 }};"
8043       "  }"
8044       "}");
8045   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8046   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8047   CHECK_GE(interceptor_call_count, 50);
8048 }
8049 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2)8050 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8051   int interceptor_call_count = 0;
8052   v8::HandleScope scope;
8053   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8054   v8::Handle<v8::FunctionTemplate> method_templ =
8055       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8056                                 v8_str("method_data"),
8057                                 v8::Signature::New(fun_templ));
8058   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8059   proto_templ->Set(v8_str("method"), method_templ);
8060   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8061   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8062                                  NULL, NULL, NULL, NULL,
8063                                  v8::External::Wrap(&interceptor_call_count));
8064   LocalContext context;
8065   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8066   GenerateSomeGarbage();
8067   context->Global()->Set(v8_str("o"), fun->NewInstance());
8068   v8::Handle<Value> value = CompileRun(
8069       "o.foo = 17;"
8070       "var receiver = {};"
8071       "receiver.__proto__ = o;"
8072       "var result = 0;"
8073       "var saved_result = 0;"
8074       "for (var i = 0; i < 100; i++) {"
8075       "  result = receiver.method(41);"
8076       "  if (i == 50) {"
8077       "    saved_result = result;"
8078       "    o.method = function(x) { return x - 1 };"
8079       "  }"
8080       "}");
8081   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8082   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8083   CHECK_GE(interceptor_call_count, 50);
8084 }
8085 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3)8086 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8087   int interceptor_call_count = 0;
8088   v8::HandleScope scope;
8089   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8090   v8::Handle<v8::FunctionTemplate> method_templ =
8091       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8092                                 v8_str("method_data"),
8093                                 v8::Signature::New(fun_templ));
8094   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8095   proto_templ->Set(v8_str("method"), method_templ);
8096   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8097   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8098                                  NULL, NULL, NULL, NULL,
8099                                  v8::External::Wrap(&interceptor_call_count));
8100   LocalContext context;
8101   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8102   GenerateSomeGarbage();
8103   context->Global()->Set(v8_str("o"), fun->NewInstance());
8104   v8::TryCatch try_catch;
8105   v8::Handle<Value> value = CompileRun(
8106       "o.foo = 17;"
8107       "var receiver = {};"
8108       "receiver.__proto__ = o;"
8109       "var result = 0;"
8110       "var saved_result = 0;"
8111       "for (var i = 0; i < 100; i++) {"
8112       "  result = receiver.method(41);"
8113       "  if (i == 50) {"
8114       "    saved_result = result;"
8115       "    receiver = 333;"
8116       "  }"
8117       "}");
8118   CHECK(try_catch.HasCaught());
8119   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8120            try_catch.Exception()->ToString());
8121   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8122   CHECK_GE(interceptor_call_count, 50);
8123 }
8124 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError)8125 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8126   int interceptor_call_count = 0;
8127   v8::HandleScope scope;
8128   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8129   v8::Handle<v8::FunctionTemplate> method_templ =
8130       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8131                                 v8_str("method_data"),
8132                                 v8::Signature::New(fun_templ));
8133   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8134   proto_templ->Set(v8_str("method"), method_templ);
8135   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8136   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8137                                  NULL, NULL, NULL, NULL,
8138                                  v8::External::Wrap(&interceptor_call_count));
8139   LocalContext context;
8140   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8141   GenerateSomeGarbage();
8142   context->Global()->Set(v8_str("o"), fun->NewInstance());
8143   v8::TryCatch try_catch;
8144   v8::Handle<Value> value = CompileRun(
8145       "o.foo = 17;"
8146       "var receiver = {};"
8147       "receiver.__proto__ = o;"
8148       "var result = 0;"
8149       "var saved_result = 0;"
8150       "for (var i = 0; i < 100; i++) {"
8151       "  result = receiver.method(41);"
8152       "  if (i == 50) {"
8153       "    saved_result = result;"
8154       "    receiver = {method: receiver.method};"
8155       "  }"
8156       "}");
8157   CHECK(try_catch.HasCaught());
8158   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8159            try_catch.Exception()->ToString());
8160   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8161   CHECK_GE(interceptor_call_count, 50);
8162 }
8163 
THREADED_TEST(CallICFastApi_TrivialSignature)8164 THREADED_TEST(CallICFastApi_TrivialSignature) {
8165   v8::HandleScope scope;
8166   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8167   v8::Handle<v8::FunctionTemplate> method_templ =
8168       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8169                                 v8_str("method_data"),
8170                                 v8::Handle<v8::Signature>());
8171   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8172   proto_templ->Set(v8_str("method"), method_templ);
8173   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8174   LocalContext context;
8175   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8176   GenerateSomeGarbage();
8177   context->Global()->Set(v8_str("o"), fun->NewInstance());
8178   v8::Handle<Value> value = CompileRun(
8179       "var result = 0;"
8180       "for (var i = 0; i < 100; i++) {"
8181       "  result = o.method(41);"
8182       "}");
8183 
8184   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8185 }
8186 
THREADED_TEST(CallICFastApi_SimpleSignature)8187 THREADED_TEST(CallICFastApi_SimpleSignature) {
8188   v8::HandleScope scope;
8189   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8190   v8::Handle<v8::FunctionTemplate> method_templ =
8191       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8192                                 v8_str("method_data"),
8193                                 v8::Signature::New(fun_templ));
8194   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8195   proto_templ->Set(v8_str("method"), method_templ);
8196   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8197   LocalContext context;
8198   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8199   GenerateSomeGarbage();
8200   context->Global()->Set(v8_str("o"), fun->NewInstance());
8201   v8::Handle<Value> value = CompileRun(
8202       "o.foo = 17;"
8203       "var receiver = {};"
8204       "receiver.__proto__ = o;"
8205       "var result = 0;"
8206       "for (var i = 0; i < 100; i++) {"
8207       "  result = receiver.method(41);"
8208       "}");
8209 
8210   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8211 }
8212 
THREADED_TEST(CallICFastApi_SimpleSignature_Miss1)8213 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
8214   v8::HandleScope scope;
8215   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8216   v8::Handle<v8::FunctionTemplate> method_templ =
8217       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8218                                 v8_str("method_data"),
8219                                 v8::Signature::New(fun_templ));
8220   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8221   proto_templ->Set(v8_str("method"), method_templ);
8222   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8223   LocalContext context;
8224   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8225   GenerateSomeGarbage();
8226   context->Global()->Set(v8_str("o"), fun->NewInstance());
8227   v8::Handle<Value> value = CompileRun(
8228       "o.foo = 17;"
8229       "var receiver = {};"
8230       "receiver.__proto__ = o;"
8231       "var result = 0;"
8232       "var saved_result = 0;"
8233       "for (var i = 0; i < 100; i++) {"
8234       "  result = receiver.method(41);"
8235       "  if (i == 50) {"
8236       "    saved_result = result;"
8237       "    receiver = {method: function(x) { return x - 1 }};"
8238       "  }"
8239       "}");
8240   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8241   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8242 }
8243 
THREADED_TEST(CallICFastApi_SimpleSignature_Miss2)8244 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8245   v8::HandleScope scope;
8246   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8247   v8::Handle<v8::FunctionTemplate> method_templ =
8248       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8249                                 v8_str("method_data"),
8250                                 v8::Signature::New(fun_templ));
8251   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8252   proto_templ->Set(v8_str("method"), method_templ);
8253   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8254   LocalContext context;
8255   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8256   GenerateSomeGarbage();
8257   context->Global()->Set(v8_str("o"), fun->NewInstance());
8258   v8::TryCatch try_catch;
8259   v8::Handle<Value> value = CompileRun(
8260       "o.foo = 17;"
8261       "var receiver = {};"
8262       "receiver.__proto__ = o;"
8263       "var result = 0;"
8264       "var saved_result = 0;"
8265       "for (var i = 0; i < 100; i++) {"
8266       "  result = receiver.method(41);"
8267       "  if (i == 50) {"
8268       "    saved_result = result;"
8269       "    receiver = 333;"
8270       "  }"
8271       "}");
8272   CHECK(try_catch.HasCaught());
8273   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8274            try_catch.Exception()->ToString());
8275   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8276 }
8277 
8278 
8279 v8::Handle<Value> keyed_call_ic_function;
8280 
InterceptorKeyedCallICGetter(Local<String> name,const AccessorInfo & info)8281 static v8::Handle<Value> InterceptorKeyedCallICGetter(
8282     Local<String> name, const AccessorInfo& info) {
8283   ApiTestFuzzer::Fuzz();
8284   if (v8_str("x")->Equals(name)) {
8285     return keyed_call_ic_function;
8286   }
8287   return v8::Handle<Value>();
8288 }
8289 
8290 
8291 // Test the case when we stored cacheable lookup into
8292 // a stub, but the function name changed (to another cacheable function).
THREADED_TEST(InterceptorKeyedCallICKeyChange1)8293 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8294   v8::HandleScope scope;
8295   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8296   templ->SetNamedPropertyHandler(NoBlockGetterX);
8297   LocalContext context;
8298   context->Global()->Set(v8_str("o"), templ->NewInstance());
8299   v8::Handle<Value> value = CompileRun(
8300     "proto = new Object();"
8301     "proto.y = function(x) { return x + 1; };"
8302     "proto.z = function(x) { return x - 1; };"
8303     "o.__proto__ = proto;"
8304     "var result = 0;"
8305     "var method = 'y';"
8306     "for (var i = 0; i < 10; i++) {"
8307     "  if (i == 5) { method = 'z'; };"
8308     "  result += o[method](41);"
8309     "}");
8310   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8311 }
8312 
8313 
8314 // Test the case when we stored cacheable lookup into
8315 // a stub, but the function name changed (and the new function is present
8316 // both before and after the interceptor in the prototype chain).
THREADED_TEST(InterceptorKeyedCallICKeyChange2)8317 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8318   v8::HandleScope scope;
8319   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8320   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
8321   LocalContext context;
8322   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
8323   keyed_call_ic_function =
8324       v8_compile("function f(x) { return x - 1; }; f")->Run();
8325   v8::Handle<Value> value = CompileRun(
8326     "o = new Object();"
8327     "proto2 = new Object();"
8328     "o.y = function(x) { return x + 1; };"
8329     "proto2.y = function(x) { return x + 2; };"
8330     "o.__proto__ = proto1;"
8331     "proto1.__proto__ = proto2;"
8332     "var result = 0;"
8333     "var method = 'x';"
8334     "for (var i = 0; i < 10; i++) {"
8335     "  if (i == 5) { method = 'y'; };"
8336     "  result += o[method](41);"
8337     "}");
8338   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8339 }
8340 
8341 
8342 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
8343 // on the global object.
THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal)8344 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
8345   v8::HandleScope scope;
8346   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8347   templ->SetNamedPropertyHandler(NoBlockGetterX);
8348   LocalContext context;
8349   context->Global()->Set(v8_str("o"), templ->NewInstance());
8350   v8::Handle<Value> value = CompileRun(
8351     "function inc(x) { return x + 1; };"
8352     "inc(1);"
8353     "function dec(x) { return x - 1; };"
8354     "dec(1);"
8355     "o.__proto__ = this;"
8356     "this.__proto__.x = inc;"
8357     "this.__proto__.y = dec;"
8358     "var result = 0;"
8359     "var method = 'x';"
8360     "for (var i = 0; i < 10; i++) {"
8361     "  if (i == 5) { method = 'y'; };"
8362     "  result += o[method](41);"
8363     "}");
8364   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8365 }
8366 
8367 
8368 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorKeyedCallICFromGlobal)8369 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
8370   v8::HandleScope scope;
8371   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8372   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8373   LocalContext context;
8374   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8375 
8376   v8::Handle<Value> value = CompileRun(
8377     "function len(x) { return x.length; };"
8378     "o.__proto__ = this;"
8379     "var m = 'parseFloat';"
8380     "var result = 0;"
8381     "for (var i = 0; i < 10; i++) {"
8382     "  if (i == 5) {"
8383     "    m = 'len';"
8384     "    saved_result = result;"
8385     "  };"
8386     "  result = o[m]('239');"
8387     "}");
8388   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
8389   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8390 }
8391 
8392 // Test the map transition before the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore)8393 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
8394   v8::HandleScope scope;
8395   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8396   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8397   LocalContext context;
8398   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
8399 
8400   v8::Handle<Value> value = CompileRun(
8401     "var o = new Object();"
8402     "o.__proto__ = proto;"
8403     "o.method = function(x) { return x + 1; };"
8404     "var m = 'method';"
8405     "var result = 0;"
8406     "for (var i = 0; i < 10; i++) {"
8407     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
8408     "  result += o[m](41);"
8409     "}");
8410   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8411 }
8412 
8413 
8414 // Test the map transition after the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeAfter)8415 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
8416   v8::HandleScope scope;
8417   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8418   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8419   LocalContext context;
8420   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8421 
8422   v8::Handle<Value> value = CompileRun(
8423     "var proto = new Object();"
8424     "o.__proto__ = proto;"
8425     "proto.method = function(x) { return x + 1; };"
8426     "var m = 'method';"
8427     "var result = 0;"
8428     "for (var i = 0; i < 10; i++) {"
8429     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
8430     "  result += o[m](41);"
8431     "}");
8432   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8433 }
8434 
8435 
8436 static int interceptor_call_count = 0;
8437 
InterceptorICRefErrorGetter(Local<String> name,const AccessorInfo & info)8438 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
8439                                                      const AccessorInfo& info) {
8440   ApiTestFuzzer::Fuzz();
8441   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
8442     return call_ic_function2;
8443   }
8444   return v8::Handle<Value>();
8445 }
8446 
8447 
8448 // This test should hit load and call ICs for the interceptor case.
8449 // Once in a while, the interceptor will reply that a property was not
8450 // found in which case we should get a reference error.
THREADED_TEST(InterceptorICReferenceErrors)8451 THREADED_TEST(InterceptorICReferenceErrors) {
8452   v8::HandleScope scope;
8453   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8454   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
8455   LocalContext context(0, templ, v8::Handle<Value>());
8456   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
8457   v8::Handle<Value> value = CompileRun(
8458     "function f() {"
8459     "  for (var i = 0; i < 1000; i++) {"
8460     "    try { x; } catch(e) { return true; }"
8461     "  }"
8462     "  return false;"
8463     "};"
8464     "f();");
8465   CHECK_EQ(true, value->BooleanValue());
8466   interceptor_call_count = 0;
8467   value = CompileRun(
8468     "function g() {"
8469     "  for (var i = 0; i < 1000; i++) {"
8470     "    try { x(42); } catch(e) { return true; }"
8471     "  }"
8472     "  return false;"
8473     "};"
8474     "g();");
8475   CHECK_EQ(true, value->BooleanValue());
8476 }
8477 
8478 
8479 static int interceptor_ic_exception_get_count = 0;
8480 
InterceptorICExceptionGetter(Local<String> name,const AccessorInfo & info)8481 static v8::Handle<Value> InterceptorICExceptionGetter(
8482     Local<String> name,
8483     const AccessorInfo& info) {
8484   ApiTestFuzzer::Fuzz();
8485   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
8486     return call_ic_function3;
8487   }
8488   if (interceptor_ic_exception_get_count == 20) {
8489     return v8::ThrowException(v8_num(42));
8490   }
8491   // Do not handle get for properties other than x.
8492   return v8::Handle<Value>();
8493 }
8494 
8495 // Test interceptor load/call IC where the interceptor throws an
8496 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)8497 THREADED_TEST(InterceptorICGetterExceptions) {
8498   interceptor_ic_exception_get_count = 0;
8499   v8::HandleScope scope;
8500   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8501   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
8502   LocalContext context(0, templ, v8::Handle<Value>());
8503   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
8504   v8::Handle<Value> value = CompileRun(
8505     "function f() {"
8506     "  for (var i = 0; i < 100; i++) {"
8507     "    try { x; } catch(e) { return true; }"
8508     "  }"
8509     "  return false;"
8510     "};"
8511     "f();");
8512   CHECK_EQ(true, value->BooleanValue());
8513   interceptor_ic_exception_get_count = 0;
8514   value = CompileRun(
8515     "function f() {"
8516     "  for (var i = 0; i < 100; i++) {"
8517     "    try { x(42); } catch(e) { return true; }"
8518     "  }"
8519     "  return false;"
8520     "};"
8521     "f();");
8522   CHECK_EQ(true, value->BooleanValue());
8523 }
8524 
8525 
8526 static int interceptor_ic_exception_set_count = 0;
8527 
InterceptorICExceptionSetter(Local<String> key,Local<Value> value,const AccessorInfo &)8528 static v8::Handle<Value> InterceptorICExceptionSetter(
8529       Local<String> key, Local<Value> value, const AccessorInfo&) {
8530   ApiTestFuzzer::Fuzz();
8531   if (++interceptor_ic_exception_set_count > 20) {
8532     return v8::ThrowException(v8_num(42));
8533   }
8534   // Do not actually handle setting.
8535   return v8::Handle<Value>();
8536 }
8537 
8538 // Test interceptor store IC where the interceptor throws an exception
8539 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)8540 THREADED_TEST(InterceptorICSetterExceptions) {
8541   interceptor_ic_exception_set_count = 0;
8542   v8::HandleScope scope;
8543   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8544   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
8545   LocalContext context(0, templ, v8::Handle<Value>());
8546   v8::Handle<Value> value = CompileRun(
8547     "function f() {"
8548     "  for (var i = 0; i < 100; i++) {"
8549     "    try { x = 42; } catch(e) { return true; }"
8550     "  }"
8551     "  return false;"
8552     "};"
8553     "f();");
8554   CHECK_EQ(true, value->BooleanValue());
8555 }
8556 
8557 
8558 // Test that we ignore null interceptors.
THREADED_TEST(NullNamedInterceptor)8559 THREADED_TEST(NullNamedInterceptor) {
8560   v8::HandleScope scope;
8561   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8562   templ->SetNamedPropertyHandler(0);
8563   LocalContext context;
8564   templ->Set("x", v8_num(42));
8565   v8::Handle<v8::Object> obj = templ->NewInstance();
8566   context->Global()->Set(v8_str("obj"), obj);
8567   v8::Handle<Value> value = CompileRun("obj.x");
8568   CHECK(value->IsInt32());
8569   CHECK_EQ(42, value->Int32Value());
8570 }
8571 
8572 
8573 // Test that we ignore null interceptors.
THREADED_TEST(NullIndexedInterceptor)8574 THREADED_TEST(NullIndexedInterceptor) {
8575   v8::HandleScope scope;
8576   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8577   templ->SetIndexedPropertyHandler(0);
8578   LocalContext context;
8579   templ->Set("42", v8_num(42));
8580   v8::Handle<v8::Object> obj = templ->NewInstance();
8581   context->Global()->Set(v8_str("obj"), obj);
8582   v8::Handle<Value> value = CompileRun("obj[42]");
8583   CHECK(value->IsInt32());
8584   CHECK_EQ(42, value->Int32Value());
8585 }
8586 
8587 
THREADED_TEST(NamedPropertyHandlerGetterAttributes)8588 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
8589   v8::HandleScope scope;
8590   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8591   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8592   LocalContext env;
8593   env->Global()->Set(v8_str("obj"),
8594                      templ->GetFunction()->NewInstance());
8595   ExpectTrue("obj.x === 42");
8596   ExpectTrue("!obj.propertyIsEnumerable('x')");
8597 }
8598 
8599 
ThrowingGetter(Local<String> name,const AccessorInfo & info)8600 static Handle<Value> ThrowingGetter(Local<String> name,
8601                                     const AccessorInfo& info) {
8602   ApiTestFuzzer::Fuzz();
8603   ThrowException(Handle<Value>());
8604   return Undefined();
8605 }
8606 
8607 
THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks)8608 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
8609   HandleScope scope;
8610   LocalContext context;
8611 
8612   Local<FunctionTemplate> templ = FunctionTemplate::New();
8613   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
8614   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
8615 
8616   Local<Object> instance = templ->GetFunction()->NewInstance();
8617 
8618   Local<Object> another = Object::New();
8619   another->SetPrototype(instance);
8620 
8621   Local<Object> with_js_getter = CompileRun(
8622       "o = {};\n"
8623       "o.__defineGetter__('f', function() { throw undefined; });\n"
8624       "o\n").As<Object>();
8625   CHECK(!with_js_getter.IsEmpty());
8626 
8627   TryCatch try_catch;
8628 
8629   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
8630   CHECK(try_catch.HasCaught());
8631   try_catch.Reset();
8632   CHECK(result.IsEmpty());
8633 
8634   result = another->GetRealNamedProperty(v8_str("f"));
8635   CHECK(try_catch.HasCaught());
8636   try_catch.Reset();
8637   CHECK(result.IsEmpty());
8638 
8639   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
8640   CHECK(try_catch.HasCaught());
8641   try_catch.Reset();
8642   CHECK(result.IsEmpty());
8643 
8644   result = another->Get(v8_str("f"));
8645   CHECK(try_catch.HasCaught());
8646   try_catch.Reset();
8647   CHECK(result.IsEmpty());
8648 
8649   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
8650   CHECK(try_catch.HasCaught());
8651   try_catch.Reset();
8652   CHECK(result.IsEmpty());
8653 
8654   result = with_js_getter->Get(v8_str("f"));
8655   CHECK(try_catch.HasCaught());
8656   try_catch.Reset();
8657   CHECK(result.IsEmpty());
8658 }
8659 
8660 
ThrowingCallbackWithTryCatch(const Arguments & args)8661 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
8662   TryCatch try_catch;
8663   // Verboseness is important: it triggers message delivery which can call into
8664   // external code.
8665   try_catch.SetVerbose(true);
8666   CompileRun("throw 'from JS';");
8667   CHECK(try_catch.HasCaught());
8668   CHECK(!i::Isolate::Current()->has_pending_exception());
8669   CHECK(!i::Isolate::Current()->has_scheduled_exception());
8670   return Undefined();
8671 }
8672 
8673 
8674 static int call_depth;
8675 
8676 
WithTryCatch(Handle<Message> message,Handle<Value> data)8677 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
8678   TryCatch try_catch;
8679 }
8680 
8681 
ThrowFromJS(Handle<Message> message,Handle<Value> data)8682 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
8683   if (--call_depth) CompileRun("throw 'ThrowInJS';");
8684 }
8685 
8686 
ThrowViaApi(Handle<Message> message,Handle<Value> data)8687 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
8688   if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
8689 }
8690 
8691 
WebKitLike(Handle<Message> message,Handle<Value> data)8692 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
8693   Handle<String> errorMessageString = message->Get();
8694   CHECK(!errorMessageString.IsEmpty());
8695   message->GetStackTrace();
8696   message->GetScriptResourceName();
8697 }
8698 
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch)8699 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
8700   HandleScope scope;
8701   LocalContext context;
8702 
8703   Local<Function> func =
8704       FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
8705   context->Global()->Set(v8_str("func"), func);
8706 
8707   MessageCallback callbacks[] =
8708       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
8709   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
8710     MessageCallback callback = callbacks[i];
8711     if (callback != NULL) {
8712       V8::AddMessageListener(callback);
8713     }
8714     call_depth = 5;
8715     ExpectFalse(
8716         "var thrown = false;\n"
8717         "try { func(); } catch(e) { thrown = true; }\n"
8718         "thrown\n");
8719     if (callback != NULL) {
8720       V8::RemoveMessageListeners(callback);
8721     }
8722   }
8723 }
8724 
8725 
ParentGetter(Local<String> name,const AccessorInfo & info)8726 static v8::Handle<Value> ParentGetter(Local<String> name,
8727                                       const AccessorInfo& info) {
8728   ApiTestFuzzer::Fuzz();
8729   return v8_num(1);
8730 }
8731 
8732 
ChildGetter(Local<String> name,const AccessorInfo & info)8733 static v8::Handle<Value> ChildGetter(Local<String> name,
8734                                      const AccessorInfo& info) {
8735   ApiTestFuzzer::Fuzz();
8736   return v8_num(42);
8737 }
8738 
8739 
THREADED_TEST(Overriding)8740 THREADED_TEST(Overriding) {
8741   v8::HandleScope scope;
8742   LocalContext context;
8743 
8744   // Parent template.
8745   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8746   Local<ObjectTemplate> parent_instance_templ =
8747       parent_templ->InstanceTemplate();
8748   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8749 
8750   // Template that inherits from the parent template.
8751   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8752   Local<ObjectTemplate> child_instance_templ =
8753       child_templ->InstanceTemplate();
8754   child_templ->Inherit(parent_templ);
8755   // Override 'f'.  The child version of 'f' should get called for child
8756   // instances.
8757   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8758   // Add 'g' twice.  The 'g' added last should get called for instances.
8759   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8760   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8761 
8762   // Add 'h' as an accessor to the proto template with ReadOnly attributes
8763   // so 'h' can be shadowed on the instance object.
8764   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8765   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8766       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8767 
8768   // Add 'i' as an accessor to the instance template with ReadOnly attributes
8769   // but the attribute does not have effect because it is duplicated with
8770   // NULL setter.
8771   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8772       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8773 
8774 
8775 
8776   // Instantiate the child template.
8777   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8778 
8779   // Check that the child function overrides the parent one.
8780   context->Global()->Set(v8_str("o"), instance);
8781   Local<Value> value = v8_compile("o.f")->Run();
8782   // Check that the 'g' that was added last is hit.
8783   CHECK_EQ(42, value->Int32Value());
8784   value = v8_compile("o.g")->Run();
8785   CHECK_EQ(42, value->Int32Value());
8786 
8787   // Check 'h' can be shadowed.
8788   value = v8_compile("o.h = 3; o.h")->Run();
8789   CHECK_EQ(3, value->Int32Value());
8790 
8791   // Check 'i' is cannot be shadowed or changed.
8792   value = v8_compile("o.i = 3; o.i")->Run();
8793   CHECK_EQ(42, value->Int32Value());
8794 }
8795 
8796 
IsConstructHandler(const v8::Arguments & args)8797 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8798   ApiTestFuzzer::Fuzz();
8799   if (args.IsConstructCall()) {
8800     return v8::Boolean::New(true);
8801   }
8802   return v8::Boolean::New(false);
8803 }
8804 
8805 
THREADED_TEST(IsConstructCall)8806 THREADED_TEST(IsConstructCall) {
8807   v8::HandleScope scope;
8808 
8809   // Function template with call handler.
8810   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8811   templ->SetCallHandler(IsConstructHandler);
8812 
8813   LocalContext context;
8814 
8815   context->Global()->Set(v8_str("f"), templ->GetFunction());
8816   Local<Value> value = v8_compile("f()")->Run();
8817   CHECK(!value->BooleanValue());
8818   value = v8_compile("new f()")->Run();
8819   CHECK(value->BooleanValue());
8820 }
8821 
8822 
THREADED_TEST(ObjectProtoToString)8823 THREADED_TEST(ObjectProtoToString) {
8824   v8::HandleScope scope;
8825   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8826   templ->SetClassName(v8_str("MyClass"));
8827 
8828   LocalContext context;
8829 
8830   Local<String> customized_tostring = v8_str("customized toString");
8831 
8832   // Replace Object.prototype.toString
8833   v8_compile("Object.prototype.toString = function() {"
8834                   "  return 'customized toString';"
8835                   "}")->Run();
8836 
8837   // Normal ToString call should call replaced Object.prototype.toString
8838   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8839   Local<String> value = instance->ToString();
8840   CHECK(value->IsString() && value->Equals(customized_tostring));
8841 
8842   // ObjectProtoToString should not call replace toString function.
8843   value = instance->ObjectProtoToString();
8844   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8845 
8846   // Check global
8847   value = context->Global()->ObjectProtoToString();
8848   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8849 
8850   // Check ordinary object
8851   Local<Value> object = v8_compile("new Object()")->Run();
8852   value = object.As<v8::Object>()->ObjectProtoToString();
8853   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8854 }
8855 
8856 
THREADED_TEST(ObjectGetConstructorName)8857 THREADED_TEST(ObjectGetConstructorName) {
8858   v8::HandleScope scope;
8859   LocalContext context;
8860   v8_compile("function Parent() {};"
8861              "function Child() {};"
8862              "Child.prototype = new Parent();"
8863              "var outer = { inner: function() { } };"
8864              "var p = new Parent();"
8865              "var c = new Child();"
8866              "var x = new outer.inner();")->Run();
8867 
8868   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8869   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8870       v8_str("Parent")));
8871 
8872   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8873   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8874       v8_str("Child")));
8875 
8876   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8877   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8878       v8_str("outer.inner")));
8879 }
8880 
8881 
8882 bool ApiTestFuzzer::fuzzing_ = false;
8883 i::Semaphore* ApiTestFuzzer::all_tests_done_=
8884   i::OS::CreateSemaphore(0);
8885 int ApiTestFuzzer::active_tests_;
8886 int ApiTestFuzzer::tests_being_run_;
8887 int ApiTestFuzzer::current_;
8888 
8889 
8890 // We are in a callback and want to switch to another thread (if we
8891 // are currently running the thread fuzzing test).
Fuzz()8892 void ApiTestFuzzer::Fuzz() {
8893   if (!fuzzing_) return;
8894   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8895   test->ContextSwitch();
8896 }
8897 
8898 
8899 // Let the next thread go.  Since it is also waiting on the V8 lock it may
8900 // not start immediately.
NextThread()8901 bool ApiTestFuzzer::NextThread() {
8902   int test_position = GetNextTestNumber();
8903   const char* test_name = RegisterThreadedTest::nth(current_)->name();
8904   if (test_position == current_) {
8905     if (kLogThreading)
8906       printf("Stay with %s\n", test_name);
8907     return false;
8908   }
8909   if (kLogThreading) {
8910     printf("Switch from %s to %s\n",
8911            test_name,
8912            RegisterThreadedTest::nth(test_position)->name());
8913   }
8914   current_ = test_position;
8915   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8916   return true;
8917 }
8918 
8919 
Run()8920 void ApiTestFuzzer::Run() {
8921   // When it is our turn...
8922   gate_->Wait();
8923   {
8924     // ... get the V8 lock and start running the test.
8925     v8::Locker locker;
8926     CallTest();
8927   }
8928   // This test finished.
8929   active_ = false;
8930   active_tests_--;
8931   // If it was the last then signal that fact.
8932   if (active_tests_ == 0) {
8933     all_tests_done_->Signal();
8934   } else {
8935     // Otherwise select a new test and start that.
8936     NextThread();
8937   }
8938 }
8939 
8940 
8941 static unsigned linear_congruential_generator;
8942 
8943 
Setup(PartOfTest part)8944 void ApiTestFuzzer::Setup(PartOfTest part) {
8945   linear_congruential_generator = i::FLAG_testing_prng_seed;
8946   fuzzing_ = true;
8947   int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8948   int end = (part == FIRST_PART)
8949       ? (RegisterThreadedTest::count() >> 1)
8950       : RegisterThreadedTest::count();
8951   active_tests_ = tests_being_run_ = end - start;
8952   for (int i = 0; i < tests_being_run_; i++) {
8953     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
8954         i::Isolate::Current(), i + start);
8955   }
8956   for (int i = 0; i < active_tests_; i++) {
8957     RegisterThreadedTest::nth(i)->fuzzer_->Start();
8958   }
8959 }
8960 
8961 
CallTestNumber(int test_number)8962 static void CallTestNumber(int test_number) {
8963   (RegisterThreadedTest::nth(test_number)->callback())();
8964 }
8965 
8966 
RunAllTests()8967 void ApiTestFuzzer::RunAllTests() {
8968   // Set off the first test.
8969   current_ = -1;
8970   NextThread();
8971   // Wait till they are all done.
8972   all_tests_done_->Wait();
8973 }
8974 
8975 
GetNextTestNumber()8976 int ApiTestFuzzer::GetNextTestNumber() {
8977   int next_test;
8978   do {
8979     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8980     linear_congruential_generator *= 1664525u;
8981     linear_congruential_generator += 1013904223u;
8982   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8983   return next_test;
8984 }
8985 
8986 
ContextSwitch()8987 void ApiTestFuzzer::ContextSwitch() {
8988   // If the new thread is the same as the current thread there is nothing to do.
8989   if (NextThread()) {
8990     // Now it can start.
8991     v8::Unlocker unlocker;
8992     // Wait till someone starts us again.
8993     gate_->Wait();
8994     // And we're off.
8995   }
8996 }
8997 
8998 
TearDown()8999 void ApiTestFuzzer::TearDown() {
9000   fuzzing_ = false;
9001   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9002     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9003     if (fuzzer != NULL) fuzzer->Join();
9004   }
9005 }
9006 
9007 
9008 // Lets not be needlessly self-referential.
TEST(Threading)9009 TEST(Threading) {
9010   ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9011   ApiTestFuzzer::RunAllTests();
9012   ApiTestFuzzer::TearDown();
9013 }
9014 
TEST(Threading2)9015 TEST(Threading2) {
9016   ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9017   ApiTestFuzzer::RunAllTests();
9018   ApiTestFuzzer::TearDown();
9019 }
9020 
9021 
CallTest()9022 void ApiTestFuzzer::CallTest() {
9023   if (kLogThreading)
9024     printf("Start test %d\n", test_number_);
9025   CallTestNumber(test_number_);
9026   if (kLogThreading)
9027     printf("End test %d\n", test_number_);
9028 }
9029 
9030 
ThrowInJS(const v8::Arguments & args)9031 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
9032   CHECK(v8::Locker::IsLocked());
9033   ApiTestFuzzer::Fuzz();
9034   v8::Unlocker unlocker;
9035   const char* code = "throw 7;";
9036   {
9037     v8::Locker nested_locker;
9038     v8::HandleScope scope;
9039     v8::Handle<Value> exception;
9040     { v8::TryCatch try_catch;
9041       v8::Handle<Value> value = CompileRun(code);
9042       CHECK(value.IsEmpty());
9043       CHECK(try_catch.HasCaught());
9044       // Make sure to wrap the exception in a new handle because
9045       // the handle returned from the TryCatch is destroyed
9046       // when the TryCatch is destroyed.
9047       exception = Local<Value>::New(try_catch.Exception());
9048     }
9049     return v8::ThrowException(exception);
9050   }
9051 }
9052 
9053 
ThrowInJSNoCatch(const v8::Arguments & args)9054 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
9055   CHECK(v8::Locker::IsLocked());
9056   ApiTestFuzzer::Fuzz();
9057   v8::Unlocker unlocker;
9058   const char* code = "throw 7;";
9059   {
9060     v8::Locker nested_locker;
9061     v8::HandleScope scope;
9062     v8::Handle<Value> value = CompileRun(code);
9063     CHECK(value.IsEmpty());
9064     return v8_str("foo");
9065   }
9066 }
9067 
9068 
9069 // These are locking tests that don't need to be run again
9070 // as part of the locking aggregation tests.
TEST(NestedLockers)9071 TEST(NestedLockers) {
9072   v8::Locker locker;
9073   CHECK(v8::Locker::IsLocked());
9074   v8::HandleScope scope;
9075   LocalContext env;
9076   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9077   Local<Function> fun = fun_templ->GetFunction();
9078   env->Global()->Set(v8_str("throw_in_js"), fun);
9079   Local<Script> script = v8_compile("(function () {"
9080                                     "  try {"
9081                                     "    throw_in_js();"
9082                                     "    return 42;"
9083                                     "  } catch (e) {"
9084                                     "    return e * 13;"
9085                                     "  }"
9086                                     "})();");
9087   CHECK_EQ(91, script->Run()->Int32Value());
9088 }
9089 
9090 
9091 // These are locking tests that don't need to be run again
9092 // as part of the locking aggregation tests.
TEST(NestedLockersNoTryCatch)9093 TEST(NestedLockersNoTryCatch) {
9094   v8::Locker locker;
9095   v8::HandleScope scope;
9096   LocalContext env;
9097   Local<v8::FunctionTemplate> fun_templ =
9098       v8::FunctionTemplate::New(ThrowInJSNoCatch);
9099   Local<Function> fun = fun_templ->GetFunction();
9100   env->Global()->Set(v8_str("throw_in_js"), fun);
9101   Local<Script> script = v8_compile("(function () {"
9102                                     "  try {"
9103                                     "    throw_in_js();"
9104                                     "    return 42;"
9105                                     "  } catch (e) {"
9106                                     "    return e * 13;"
9107                                     "  }"
9108                                     "})();");
9109   CHECK_EQ(91, script->Run()->Int32Value());
9110 }
9111 
9112 
THREADED_TEST(RecursiveLocking)9113 THREADED_TEST(RecursiveLocking) {
9114   v8::Locker locker;
9115   {
9116     v8::Locker locker2;
9117     CHECK(v8::Locker::IsLocked());
9118   }
9119 }
9120 
9121 
UnlockForAMoment(const v8::Arguments & args)9122 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9123   ApiTestFuzzer::Fuzz();
9124   v8::Unlocker unlocker;
9125   return v8::Undefined();
9126 }
9127 
9128 
THREADED_TEST(LockUnlockLock)9129 THREADED_TEST(LockUnlockLock) {
9130   {
9131     v8::Locker locker;
9132     v8::HandleScope scope;
9133     LocalContext env;
9134     Local<v8::FunctionTemplate> fun_templ =
9135         v8::FunctionTemplate::New(UnlockForAMoment);
9136     Local<Function> fun = fun_templ->GetFunction();
9137     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9138     Local<Script> script = v8_compile("(function () {"
9139                                       "  unlock_for_a_moment();"
9140                                       "  return 42;"
9141                                       "})();");
9142     CHECK_EQ(42, script->Run()->Int32Value());
9143   }
9144   {
9145     v8::Locker locker;
9146     v8::HandleScope scope;
9147     LocalContext env;
9148     Local<v8::FunctionTemplate> fun_templ =
9149         v8::FunctionTemplate::New(UnlockForAMoment);
9150     Local<Function> fun = fun_templ->GetFunction();
9151     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9152     Local<Script> script = v8_compile("(function () {"
9153                                       "  unlock_for_a_moment();"
9154                                       "  return 42;"
9155                                       "})();");
9156     CHECK_EQ(42, script->Run()->Int32Value());
9157   }
9158 }
9159 
9160 
GetGlobalObjectsCount()9161 static int GetGlobalObjectsCount() {
9162   int count = 0;
9163   i::HeapIterator it;
9164   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9165     if (object->IsJSGlobalObject()) count++;
9166   return count;
9167 }
9168 
9169 
CheckSurvivingGlobalObjectsCount(int expected)9170 static void CheckSurvivingGlobalObjectsCount(int expected) {
9171   // We need to collect all garbage twice to be sure that everything
9172   // has been collected.  This is because inline caches are cleared in
9173   // the first garbage collection but some of the maps have already
9174   // been marked at that point.  Therefore some of the maps are not
9175   // collected until the second garbage collection.
9176   HEAP->CollectAllGarbage(false);
9177   HEAP->CollectAllGarbage(false);
9178   int count = GetGlobalObjectsCount();
9179 #ifdef DEBUG
9180   if (count != expected) HEAP->TracePathToGlobal();
9181 #endif
9182   CHECK_EQ(expected, count);
9183 }
9184 
9185 
TEST(DontLeakGlobalObjects)9186 TEST(DontLeakGlobalObjects) {
9187   // Regression test for issues 1139850 and 1174891.
9188 
9189   v8::V8::Initialize();
9190 
9191   for (int i = 0; i < 5; i++) {
9192     { v8::HandleScope scope;
9193       LocalContext context;
9194     }
9195     CheckSurvivingGlobalObjectsCount(0);
9196 
9197     { v8::HandleScope scope;
9198       LocalContext context;
9199       v8_compile("Date")->Run();
9200     }
9201     CheckSurvivingGlobalObjectsCount(0);
9202 
9203     { v8::HandleScope scope;
9204       LocalContext context;
9205       v8_compile("/aaa/")->Run();
9206     }
9207     CheckSurvivingGlobalObjectsCount(0);
9208 
9209     { v8::HandleScope scope;
9210       const char* extension_list[] = { "v8/gc" };
9211       v8::ExtensionConfiguration extensions(1, extension_list);
9212       LocalContext context(&extensions);
9213       v8_compile("gc();")->Run();
9214     }
9215     CheckSurvivingGlobalObjectsCount(0);
9216   }
9217 }
9218 
9219 
9220 v8::Persistent<v8::Object> some_object;
9221 v8::Persistent<v8::Object> bad_handle;
9222 
NewPersistentHandleCallback(v8::Persistent<v8::Value> handle,void *)9223 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
9224   v8::HandleScope scope;
9225   bad_handle = v8::Persistent<v8::Object>::New(some_object);
9226   handle.Dispose();
9227 }
9228 
9229 
THREADED_TEST(NewPersistentHandleFromWeakCallback)9230 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9231   LocalContext context;
9232 
9233   v8::Persistent<v8::Object> handle1, handle2;
9234   {
9235     v8::HandleScope scope;
9236     some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9237     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9238     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9239   }
9240   // Note: order is implementation dependent alas: currently
9241   // global handle nodes are processed by PostGarbageCollectionProcessing
9242   // in reverse allocation order, so if second allocated handle is deleted,
9243   // weak callback of the first handle would be able to 'reallocate' it.
9244   handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9245   handle2.Dispose();
9246   HEAP->CollectAllGarbage(false);
9247 }
9248 
9249 
9250 v8::Persistent<v8::Object> to_be_disposed;
9251 
DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle,void *)9252 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9253   to_be_disposed.Dispose();
9254   HEAP->CollectAllGarbage(false);
9255   handle.Dispose();
9256 }
9257 
9258 
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc)9259 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9260   LocalContext context;
9261 
9262   v8::Persistent<v8::Object> handle1, handle2;
9263   {
9264     v8::HandleScope scope;
9265     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9266     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9267   }
9268   handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9269   to_be_disposed = handle2;
9270   HEAP->CollectAllGarbage(false);
9271 }
9272 
DisposingCallback(v8::Persistent<v8::Value> handle,void *)9273 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9274   handle.Dispose();
9275 }
9276 
HandleCreatingCallback(v8::Persistent<v8::Value> handle,void *)9277 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9278   v8::HandleScope scope;
9279   v8::Persistent<v8::Object>::New(v8::Object::New());
9280   handle.Dispose();
9281 }
9282 
9283 
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback)9284 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9285   LocalContext context;
9286 
9287   v8::Persistent<v8::Object> handle1, handle2, handle3;
9288   {
9289     v8::HandleScope scope;
9290     handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9291     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9292     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9293   }
9294   handle2.MakeWeak(NULL, DisposingCallback);
9295   handle3.MakeWeak(NULL, HandleCreatingCallback);
9296   HEAP->CollectAllGarbage(false);
9297 }
9298 
9299 
THREADED_TEST(CheckForCrossContextObjectLiterals)9300 THREADED_TEST(CheckForCrossContextObjectLiterals) {
9301   v8::V8::Initialize();
9302 
9303   const int nof = 2;
9304   const char* sources[nof] = {
9305     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9306     "Object()"
9307   };
9308 
9309   for (int i = 0; i < nof; i++) {
9310     const char* source = sources[i];
9311     { v8::HandleScope scope;
9312       LocalContext context;
9313       CompileRun(source);
9314     }
9315     { v8::HandleScope scope;
9316       LocalContext context;
9317       CompileRun(source);
9318     }
9319   }
9320 }
9321 
9322 
NestedScope(v8::Persistent<Context> env)9323 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
9324   v8::HandleScope inner;
9325   env->Enter();
9326   v8::Handle<Value> three = v8_num(3);
9327   v8::Handle<Value> value = inner.Close(three);
9328   env->Exit();
9329   return value;
9330 }
9331 
9332 
THREADED_TEST(NestedHandleScopeAndContexts)9333 THREADED_TEST(NestedHandleScopeAndContexts) {
9334   v8::HandleScope outer;
9335   v8::Persistent<Context> env = Context::New();
9336   env->Enter();
9337   v8::Handle<Value> value = NestedScope(env);
9338   v8::Handle<String> str = value->ToString();
9339   env->Exit();
9340   env.Dispose();
9341 }
9342 
9343 
THREADED_TEST(ExternalAllocatedMemory)9344 THREADED_TEST(ExternalAllocatedMemory) {
9345   v8::HandleScope outer;
9346   v8::Persistent<Context> env = Context::New();
9347   const int kSize = 1024*1024;
9348   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
9349   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
9350 }
9351 
9352 
THREADED_TEST(DisposeEnteredContext)9353 THREADED_TEST(DisposeEnteredContext) {
9354   v8::HandleScope scope;
9355   LocalContext outer;
9356   { v8::Persistent<v8::Context> inner = v8::Context::New();
9357     inner->Enter();
9358     inner.Dispose();
9359     inner.Clear();
9360     inner->Exit();
9361   }
9362 }
9363 
9364 
9365 // Regression test for issue 54, object templates with internal fields
9366 // but no accessors or interceptors did not get their internal field
9367 // count set on instances.
THREADED_TEST(Regress54)9368 THREADED_TEST(Regress54) {
9369   v8::HandleScope outer;
9370   LocalContext context;
9371   static v8::Persistent<v8::ObjectTemplate> templ;
9372   if (templ.IsEmpty()) {
9373     v8::HandleScope inner;
9374     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
9375     local->SetInternalFieldCount(1);
9376     templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
9377   }
9378   v8::Handle<v8::Object> result = templ->NewInstance();
9379   CHECK_EQ(1, result->InternalFieldCount());
9380 }
9381 
9382 
9383 // If part of the threaded tests, this test makes ThreadingTest fail
9384 // on mac.
TEST(CatchStackOverflow)9385 TEST(CatchStackOverflow) {
9386   v8::HandleScope scope;
9387   LocalContext context;
9388   v8::TryCatch try_catch;
9389   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
9390     "function f() {"
9391     "  return f();"
9392     "}"
9393     ""
9394     "f();"));
9395   v8::Handle<v8::Value> result = script->Run();
9396   CHECK(result.IsEmpty());
9397 }
9398 
9399 
CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,const char * resource_name,int line_offset)9400 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
9401                                     const char* resource_name,
9402                                     int line_offset) {
9403   v8::HandleScope scope;
9404   v8::TryCatch try_catch;
9405   v8::Handle<v8::Value> result = script->Run();
9406   CHECK(result.IsEmpty());
9407   CHECK(try_catch.HasCaught());
9408   v8::Handle<v8::Message> message = try_catch.Message();
9409   CHECK(!message.IsEmpty());
9410   CHECK_EQ(10 + line_offset, message->GetLineNumber());
9411   CHECK_EQ(91, message->GetStartPosition());
9412   CHECK_EQ(92, message->GetEndPosition());
9413   CHECK_EQ(2, message->GetStartColumn());
9414   CHECK_EQ(3, message->GetEndColumn());
9415   v8::String::AsciiValue line(message->GetSourceLine());
9416   CHECK_EQ("  throw 'nirk';", *line);
9417   v8::String::AsciiValue name(message->GetScriptResourceName());
9418   CHECK_EQ(resource_name, *name);
9419 }
9420 
9421 
THREADED_TEST(TryCatchSourceInfo)9422 THREADED_TEST(TryCatchSourceInfo) {
9423   v8::HandleScope scope;
9424   LocalContext context;
9425   v8::Handle<v8::String> source = v8::String::New(
9426       "function Foo() {\n"
9427       "  return Bar();\n"
9428       "}\n"
9429       "\n"
9430       "function Bar() {\n"
9431       "  return Baz();\n"
9432       "}\n"
9433       "\n"
9434       "function Baz() {\n"
9435       "  throw 'nirk';\n"
9436       "}\n"
9437       "\n"
9438       "Foo();\n");
9439 
9440   const char* resource_name;
9441   v8::Handle<v8::Script> script;
9442   resource_name = "test.js";
9443   script = v8::Script::Compile(source, v8::String::New(resource_name));
9444   CheckTryCatchSourceInfo(script, resource_name, 0);
9445 
9446   resource_name = "test1.js";
9447   v8::ScriptOrigin origin1(v8::String::New(resource_name));
9448   script = v8::Script::Compile(source, &origin1);
9449   CheckTryCatchSourceInfo(script, resource_name, 0);
9450 
9451   resource_name = "test2.js";
9452   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
9453   script = v8::Script::Compile(source, &origin2);
9454   CheckTryCatchSourceInfo(script, resource_name, 7);
9455 }
9456 
9457 
THREADED_TEST(CompilationCache)9458 THREADED_TEST(CompilationCache) {
9459   v8::HandleScope scope;
9460   LocalContext context;
9461   v8::Handle<v8::String> source0 = v8::String::New("1234");
9462   v8::Handle<v8::String> source1 = v8::String::New("1234");
9463   v8::Handle<v8::Script> script0 =
9464       v8::Script::Compile(source0, v8::String::New("test.js"));
9465   v8::Handle<v8::Script> script1 =
9466       v8::Script::Compile(source1, v8::String::New("test.js"));
9467   v8::Handle<v8::Script> script2 =
9468       v8::Script::Compile(source0);  // different origin
9469   CHECK_EQ(1234, script0->Run()->Int32Value());
9470   CHECK_EQ(1234, script1->Run()->Int32Value());
9471   CHECK_EQ(1234, script2->Run()->Int32Value());
9472 }
9473 
9474 
FunctionNameCallback(const v8::Arguments & args)9475 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
9476   ApiTestFuzzer::Fuzz();
9477   return v8_num(42);
9478 }
9479 
9480 
THREADED_TEST(CallbackFunctionName)9481 THREADED_TEST(CallbackFunctionName) {
9482   v8::HandleScope scope;
9483   LocalContext context;
9484   Local<ObjectTemplate> t = ObjectTemplate::New();
9485   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
9486   context->Global()->Set(v8_str("obj"), t->NewInstance());
9487   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
9488   CHECK(value->IsString());
9489   v8::String::AsciiValue name(value);
9490   CHECK_EQ("asdf", *name);
9491 }
9492 
9493 
THREADED_TEST(DateAccess)9494 THREADED_TEST(DateAccess) {
9495   v8::HandleScope scope;
9496   LocalContext context;
9497   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
9498   CHECK(date->IsDate());
9499   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
9500 }
9501 
9502 
CheckProperties(v8::Handle<v8::Value> val,int elmc,const char * elmv[])9503 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
9504   v8::Handle<v8::Object> obj = val.As<v8::Object>();
9505   v8::Handle<v8::Array> props = obj->GetPropertyNames();
9506   CHECK_EQ(elmc, props->Length());
9507   for (int i = 0; i < elmc; i++) {
9508     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
9509     CHECK_EQ(elmv[i], *elm);
9510   }
9511 }
9512 
9513 
THREADED_TEST(PropertyEnumeration)9514 THREADED_TEST(PropertyEnumeration) {
9515   v8::HandleScope scope;
9516   LocalContext context;
9517   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9518       "var result = [];"
9519       "result[0] = {};"
9520       "result[1] = {a: 1, b: 2};"
9521       "result[2] = [1, 2, 3];"
9522       "var proto = {x: 1, y: 2, z: 3};"
9523       "var x = { __proto__: proto, w: 0, z: 1 };"
9524       "result[3] = x;"
9525       "result;"))->Run();
9526   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9527   CHECK_EQ(4, elms->Length());
9528   int elmc0 = 0;
9529   const char** elmv0 = NULL;
9530   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9531   int elmc1 = 2;
9532   const char* elmv1[] = {"a", "b"};
9533   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
9534   int elmc2 = 3;
9535   const char* elmv2[] = {"0", "1", "2"};
9536   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
9537   int elmc3 = 4;
9538   const char* elmv3[] = {"w", "z", "x", "y"};
9539   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
9540 }
9541 
THREADED_TEST(PropertyEnumeration2)9542 THREADED_TEST(PropertyEnumeration2) {
9543   v8::HandleScope scope;
9544   LocalContext context;
9545   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9546       "var result = [];"
9547       "result[0] = {};"
9548       "result[1] = {a: 1, b: 2};"
9549       "result[2] = [1, 2, 3];"
9550       "var proto = {x: 1, y: 2, z: 3};"
9551       "var x = { __proto__: proto, w: 0, z: 1 };"
9552       "result[3] = x;"
9553       "result;"))->Run();
9554   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9555   CHECK_EQ(4, elms->Length());
9556   int elmc0 = 0;
9557   const char** elmv0 = NULL;
9558   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9559 
9560   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
9561   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
9562   CHECK_EQ(0, props->Length());
9563   for (uint32_t i = 0; i < props->Length(); i++) {
9564     printf("p[%d]\n", i);
9565   }
9566 }
9567 
NamedSetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)9568 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
9569                                   Local<Value> name,
9570                                   v8::AccessType type,
9571                                   Local<Value> data) {
9572   return type != v8::ACCESS_SET;
9573 }
9574 
9575 
IndexedSetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)9576 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
9577                                     uint32_t key,
9578                                     v8::AccessType type,
9579                                     Local<Value> data) {
9580   return type != v8::ACCESS_SET;
9581 }
9582 
9583 
THREADED_TEST(DisableAccessChecksWhileConfiguring)9584 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
9585   v8::HandleScope scope;
9586   LocalContext context;
9587   Local<ObjectTemplate> templ = ObjectTemplate::New();
9588   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9589                                  IndexedSetAccessBlocker);
9590   templ->Set(v8_str("x"), v8::True());
9591   Local<v8::Object> instance = templ->NewInstance();
9592   context->Global()->Set(v8_str("obj"), instance);
9593   Local<Value> value = CompileRun("obj.x");
9594   CHECK(value->BooleanValue());
9595 }
9596 
9597 
NamedGetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)9598 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
9599                                   Local<Value> name,
9600                                   v8::AccessType type,
9601                                   Local<Value> data) {
9602   return false;
9603 }
9604 
9605 
IndexedGetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)9606 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
9607                                     uint32_t key,
9608                                     v8::AccessType type,
9609                                     Local<Value> data) {
9610   return false;
9611 }
9612 
9613 
9614 
THREADED_TEST(AccessChecksReenabledCorrectly)9615 THREADED_TEST(AccessChecksReenabledCorrectly) {
9616   v8::HandleScope scope;
9617   LocalContext context;
9618   Local<ObjectTemplate> templ = ObjectTemplate::New();
9619   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9620                                  IndexedGetAccessBlocker);
9621   templ->Set(v8_str("a"), v8_str("a"));
9622   // Add more than 8 (see kMaxFastProperties) properties
9623   // so that the constructor will force copying map.
9624   // Cannot sprintf, gcc complains unsafety.
9625   char buf[4];
9626   for (char i = '0'; i <= '9' ; i++) {
9627     buf[0] = i;
9628     for (char j = '0'; j <= '9'; j++) {
9629       buf[1] = j;
9630       for (char k = '0'; k <= '9'; k++) {
9631         buf[2] = k;
9632         buf[3] = 0;
9633         templ->Set(v8_str(buf), v8::Number::New(k));
9634       }
9635     }
9636   }
9637 
9638   Local<v8::Object> instance_1 = templ->NewInstance();
9639   context->Global()->Set(v8_str("obj_1"), instance_1);
9640 
9641   Local<Value> value_1 = CompileRun("obj_1.a");
9642   CHECK(value_1->IsUndefined());
9643 
9644   Local<v8::Object> instance_2 = templ->NewInstance();
9645   context->Global()->Set(v8_str("obj_2"), instance_2);
9646 
9647   Local<Value> value_2 = CompileRun("obj_2.a");
9648   CHECK(value_2->IsUndefined());
9649 }
9650 
9651 
9652 // This tests that access check information remains on the global
9653 // object template when creating contexts.
THREADED_TEST(AccessControlRepeatedContextCreation)9654 THREADED_TEST(AccessControlRepeatedContextCreation) {
9655   v8::HandleScope handle_scope;
9656   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9657   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9658                                            IndexedSetAccessBlocker);
9659   i::Handle<i::ObjectTemplateInfo> internal_template =
9660       v8::Utils::OpenHandle(*global_template);
9661   CHECK(!internal_template->constructor()->IsUndefined());
9662   i::Handle<i::FunctionTemplateInfo> constructor(
9663       i::FunctionTemplateInfo::cast(internal_template->constructor()));
9664   CHECK(!constructor->access_check_info()->IsUndefined());
9665   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
9666   CHECK(!constructor->access_check_info()->IsUndefined());
9667 }
9668 
9669 
THREADED_TEST(TurnOnAccessCheck)9670 THREADED_TEST(TurnOnAccessCheck) {
9671   v8::HandleScope handle_scope;
9672 
9673   // Create an environment with access check to the global object disabled by
9674   // default.
9675   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9676   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9677                                            IndexedGetAccessBlocker,
9678                                            v8::Handle<v8::Value>(),
9679                                            false);
9680   v8::Persistent<Context> context = Context::New(NULL, global_template);
9681   Context::Scope context_scope(context);
9682 
9683   // Set up a property and a number of functions.
9684   context->Global()->Set(v8_str("a"), v8_num(1));
9685   CompileRun("function f1() {return a;}"
9686              "function f2() {return a;}"
9687              "function g1() {return h();}"
9688              "function g2() {return h();}"
9689              "function h() {return 1;}");
9690   Local<Function> f1 =
9691       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9692   Local<Function> f2 =
9693       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9694   Local<Function> g1 =
9695       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9696   Local<Function> g2 =
9697       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9698   Local<Function> h =
9699       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9700 
9701   // Get the global object.
9702   v8::Handle<v8::Object> global = context->Global();
9703 
9704   // Call f1 one time and f2 a number of times. This will ensure that f1 still
9705   // uses the runtime system to retreive property a whereas f2 uses global load
9706   // inline cache.
9707   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9708   for (int i = 0; i < 4; i++) {
9709     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9710   }
9711 
9712   // Same for g1 and g2.
9713   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9714   for (int i = 0; i < 4; i++) {
9715     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9716   }
9717 
9718   // Detach the global and turn on access check.
9719   context->DetachGlobal();
9720   context->Global()->TurnOnAccessCheck();
9721 
9722   // Failing access check to property get results in undefined.
9723   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9724   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9725 
9726   // Failing access check to function call results in exception.
9727   CHECK(g1->Call(global, 0, NULL).IsEmpty());
9728   CHECK(g2->Call(global, 0, NULL).IsEmpty());
9729 
9730   // No failing access check when just returning a constant.
9731   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9732 }
9733 
9734 
9735 v8::Handle<v8::String> a;
9736 v8::Handle<v8::String> h;
9737 
NamedGetAccessBlockAandH(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)9738 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
9739                                        Local<Value> name,
9740                                        v8::AccessType type,
9741                                        Local<Value> data) {
9742   return !(name->Equals(a) || name->Equals(h));
9743 }
9744 
9745 
THREADED_TEST(TurnOnAccessCheckAndRecompile)9746 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
9747   v8::HandleScope handle_scope;
9748 
9749   // Create an environment with access check to the global object disabled by
9750   // default. When the registered access checker will block access to properties
9751   // a and h
9752   a = v8_str("a");
9753   h = v8_str("h");
9754   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9755   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
9756                                            IndexedGetAccessBlocker,
9757                                            v8::Handle<v8::Value>(),
9758                                            false);
9759   v8::Persistent<Context> context = Context::New(NULL, global_template);
9760   Context::Scope context_scope(context);
9761 
9762   // Set up a property and a number of functions.
9763   context->Global()->Set(v8_str("a"), v8_num(1));
9764   static const char* source = "function f1() {return a;}"
9765                               "function f2() {return a;}"
9766                               "function g1() {return h();}"
9767                               "function g2() {return h();}"
9768                               "function h() {return 1;}";
9769 
9770   CompileRun(source);
9771   Local<Function> f1;
9772   Local<Function> f2;
9773   Local<Function> g1;
9774   Local<Function> g2;
9775   Local<Function> h;
9776   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9777   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9778   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9779   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9780   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9781 
9782   // Get the global object.
9783   v8::Handle<v8::Object> global = context->Global();
9784 
9785   // Call f1 one time and f2 a number of times. This will ensure that f1 still
9786   // uses the runtime system to retreive property a whereas f2 uses global load
9787   // inline cache.
9788   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9789   for (int i = 0; i < 4; i++) {
9790     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9791   }
9792 
9793   // Same for g1 and g2.
9794   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9795   for (int i = 0; i < 4; i++) {
9796     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9797   }
9798 
9799   // Detach the global and turn on access check now blocking access to property
9800   // a and function h.
9801   context->DetachGlobal();
9802   context->Global()->TurnOnAccessCheck();
9803 
9804   // Failing access check to property get results in undefined.
9805   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9806   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9807 
9808   // Failing access check to function call results in exception.
9809   CHECK(g1->Call(global, 0, NULL).IsEmpty());
9810   CHECK(g2->Call(global, 0, NULL).IsEmpty());
9811 
9812   // No failing access check when just returning a constant.
9813   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9814 
9815   // Now compile the source again. And get the newly compiled functions, except
9816   // for h for which access is blocked.
9817   CompileRun(source);
9818   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9819   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9820   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9821   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9822   CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9823 
9824   // Failing access check to property get results in undefined.
9825   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9826   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9827 
9828   // Failing access check to function call results in exception.
9829   CHECK(g1->Call(global, 0, NULL).IsEmpty());
9830   CHECK(g2->Call(global, 0, NULL).IsEmpty());
9831 }
9832 
9833 
9834 // This test verifies that pre-compilation (aka preparsing) can be called
9835 // without initializing the whole VM. Thus we cannot run this test in a
9836 // multi-threaded setup.
TEST(PreCompile)9837 TEST(PreCompile) {
9838   // TODO(155): This test would break without the initialization of V8. This is
9839   // a workaround for now to make this test not fail.
9840   v8::V8::Initialize();
9841   const char* script = "function foo(a) { return a+1; }";
9842   v8::ScriptData* sd =
9843       v8::ScriptData::PreCompile(script, i::StrLength(script));
9844   CHECK_NE(sd->Length(), 0);
9845   CHECK_NE(sd->Data(), NULL);
9846   CHECK(!sd->HasError());
9847   delete sd;
9848 }
9849 
9850 
TEST(PreCompileWithError)9851 TEST(PreCompileWithError) {
9852   v8::V8::Initialize();
9853   const char* script = "function foo(a) { return 1 * * 2; }";
9854   v8::ScriptData* sd =
9855       v8::ScriptData::PreCompile(script, i::StrLength(script));
9856   CHECK(sd->HasError());
9857   delete sd;
9858 }
9859 
9860 
TEST(Regress31661)9861 TEST(Regress31661) {
9862   v8::V8::Initialize();
9863   const char* script = " The Definintive Guide";
9864   v8::ScriptData* sd =
9865       v8::ScriptData::PreCompile(script, i::StrLength(script));
9866   CHECK(sd->HasError());
9867   delete sd;
9868 }
9869 
9870 
9871 // Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization)9872 TEST(PreCompileSerialization) {
9873   v8::V8::Initialize();
9874   const char* script = "function foo(a) { return a+1; }";
9875   v8::ScriptData* sd =
9876       v8::ScriptData::PreCompile(script, i::StrLength(script));
9877 
9878   // Serialize.
9879   int serialized_data_length = sd->Length();
9880   char* serialized_data = i::NewArray<char>(serialized_data_length);
9881   memcpy(serialized_data, sd->Data(), serialized_data_length);
9882 
9883   // Deserialize.
9884   v8::ScriptData* deserialized_sd =
9885       v8::ScriptData::New(serialized_data, serialized_data_length);
9886 
9887   // Verify that the original is the same as the deserialized.
9888   CHECK_EQ(sd->Length(), deserialized_sd->Length());
9889   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9890   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9891 
9892   delete sd;
9893   delete deserialized_sd;
9894 }
9895 
9896 
9897 // Attempts to deserialize bad data.
TEST(PreCompileDeserializationError)9898 TEST(PreCompileDeserializationError) {
9899   v8::V8::Initialize();
9900   const char* data = "DONT CARE";
9901   int invalid_size = 3;
9902   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9903 
9904   CHECK_EQ(0, sd->Length());
9905 
9906   delete sd;
9907 }
9908 
9909 
9910 // Attempts to deserialize bad data.
TEST(PreCompileInvalidPreparseDataError)9911 TEST(PreCompileInvalidPreparseDataError) {
9912   v8::V8::Initialize();
9913   v8::HandleScope scope;
9914   LocalContext context;
9915 
9916   const char* script = "function foo(){ return 5;}\n"
9917       "function bar(){ return 6 + 7;}  foo();";
9918   v8::ScriptData* sd =
9919       v8::ScriptData::PreCompile(script, i::StrLength(script));
9920   CHECK(!sd->HasError());
9921   // ScriptDataImpl private implementation details
9922   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
9923   const int kFunctionEntrySize = i::FunctionEntry::kSize;
9924   const int kFunctionEntryStartOffset = 0;
9925   const int kFunctionEntryEndOffset = 1;
9926   unsigned* sd_data =
9927       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9928 
9929   // Overwrite function bar's end position with 0.
9930   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9931   v8::TryCatch try_catch;
9932 
9933   Local<String> source = String::New(script);
9934   Local<Script> compiled_script = Script::New(source, NULL, sd);
9935   CHECK(try_catch.HasCaught());
9936   String::AsciiValue exception_value(try_catch.Message()->Get());
9937   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9938            *exception_value);
9939 
9940   try_catch.Reset();
9941   // Overwrite function bar's start position with 200.  The function entry
9942   // will not be found when searching for it by position.
9943   sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9944   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
9945   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9946       200;
9947   compiled_script = Script::New(source, NULL, sd);
9948   CHECK(try_catch.HasCaught());
9949   String::AsciiValue second_exception_value(try_catch.Message()->Get());
9950   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9951            *second_exception_value);
9952 
9953   delete sd;
9954 }
9955 
9956 
9957 // Verifies that the Handle<String> and const char* versions of the API produce
9958 // the same results (at least for one trivial case).
TEST(PreCompileAPIVariationsAreSame)9959 TEST(PreCompileAPIVariationsAreSame) {
9960   v8::V8::Initialize();
9961   v8::HandleScope scope;
9962 
9963   const char* cstring = "function foo(a) { return a+1; }";
9964 
9965   v8::ScriptData* sd_from_cstring =
9966       v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9967 
9968   TestAsciiResource* resource = new TestAsciiResource(cstring);
9969   v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
9970       v8::String::NewExternal(resource));
9971 
9972   v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9973       v8::String::New(cstring));
9974 
9975   CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
9976   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9977                      sd_from_external_string->Data(),
9978                      sd_from_cstring->Length()));
9979 
9980   CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9981   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9982                      sd_from_string->Data(),
9983                      sd_from_cstring->Length()));
9984 
9985 
9986   delete sd_from_cstring;
9987   delete sd_from_external_string;
9988   delete sd_from_string;
9989 }
9990 
9991 
9992 // This tests that we do not allow dictionary load/call inline caches
9993 // to use functions that have not yet been compiled.  The potential
9994 // problem of loading a function that has not yet been compiled can
9995 // arise because we share code between contexts via the compilation
9996 // cache.
THREADED_TEST(DictionaryICLoadedFunction)9997 THREADED_TEST(DictionaryICLoadedFunction) {
9998   v8::HandleScope scope;
9999   // Test LoadIC.
10000   for (int i = 0; i < 2; i++) {
10001     LocalContext context;
10002     context->Global()->Set(v8_str("tmp"), v8::True());
10003     context->Global()->Delete(v8_str("tmp"));
10004     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10005   }
10006   // Test CallIC.
10007   for (int i = 0; i < 2; i++) {
10008     LocalContext context;
10009     context->Global()->Set(v8_str("tmp"), v8::True());
10010     context->Global()->Delete(v8_str("tmp"));
10011     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10012   }
10013 }
10014 
10015 
10016 // Test that cross-context new calls use the context of the callee to
10017 // create the new JavaScript object.
THREADED_TEST(CrossContextNew)10018 THREADED_TEST(CrossContextNew) {
10019   v8::HandleScope scope;
10020   v8::Persistent<Context> context0 = Context::New();
10021   v8::Persistent<Context> context1 = Context::New();
10022 
10023   // Allow cross-domain access.
10024   Local<String> token = v8_str("<security token>");
10025   context0->SetSecurityToken(token);
10026   context1->SetSecurityToken(token);
10027 
10028   // Set an 'x' property on the Object prototype and define a
10029   // constructor function in context0.
10030   context0->Enter();
10031   CompileRun("Object.prototype.x = 42; function C() {};");
10032   context0->Exit();
10033 
10034   // Call the constructor function from context0 and check that the
10035   // result has the 'x' property.
10036   context1->Enter();
10037   context1->Global()->Set(v8_str("other"), context0->Global());
10038   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10039   CHECK(value->IsInt32());
10040   CHECK_EQ(42, value->Int32Value());
10041   context1->Exit();
10042 
10043   // Dispose the contexts to allow them to be garbage collected.
10044   context0.Dispose();
10045   context1.Dispose();
10046 }
10047 
10048 
10049 class RegExpInterruptTest {
10050  public:
RegExpInterruptTest()10051   RegExpInterruptTest() : block_(NULL) {}
~RegExpInterruptTest()10052   ~RegExpInterruptTest() { delete block_; }
RunTest()10053   void RunTest() {
10054     block_ = i::OS::CreateSemaphore(0);
10055     gc_count_ = 0;
10056     gc_during_regexp_ = 0;
10057     regexp_success_ = false;
10058     gc_success_ = false;
10059     GCThread gc_thread(i::Isolate::Current(), this);
10060     gc_thread.Start();
10061     v8::Locker::StartPreemption(1);
10062 
10063     LongRunningRegExp();
10064     {
10065       v8::Unlocker unlock;
10066       gc_thread.Join();
10067     }
10068     v8::Locker::StopPreemption();
10069     CHECK(regexp_success_);
10070     CHECK(gc_success_);
10071   }
10072  private:
10073   // Number of garbage collections required.
10074   static const int kRequiredGCs = 5;
10075 
10076   class GCThread : public i::Thread {
10077    public:
GCThread(i::Isolate * isolate,RegExpInterruptTest * test)10078     explicit GCThread(i::Isolate* isolate, RegExpInterruptTest* test)
10079         : Thread(isolate, "GCThread"), test_(test) {}
Run()10080     virtual void Run() {
10081       test_->CollectGarbage();
10082     }
10083    private:
10084      RegExpInterruptTest* test_;
10085   };
10086 
CollectGarbage()10087   void CollectGarbage() {
10088     block_->Wait();
10089     while (gc_during_regexp_ < kRequiredGCs) {
10090       {
10091         v8::Locker lock;
10092         // TODO(lrn): Perhaps create some garbage before collecting.
10093         HEAP->CollectAllGarbage(false);
10094         gc_count_++;
10095       }
10096       i::OS::Sleep(1);
10097     }
10098     gc_success_ = true;
10099   }
10100 
LongRunningRegExp()10101   void LongRunningRegExp() {
10102     block_->Signal();  // Enable garbage collection thread on next preemption.
10103     int rounds = 0;
10104     while (gc_during_regexp_ < kRequiredGCs) {
10105       int gc_before = gc_count_;
10106       {
10107         // Match 15-30 "a"'s against 14 and a "b".
10108         const char* c_source =
10109             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10110             ".exec('aaaaaaaaaaaaaaab') === null";
10111         Local<String> source = String::New(c_source);
10112         Local<Script> script = Script::Compile(source);
10113         Local<Value> result = script->Run();
10114         if (!result->BooleanValue()) {
10115           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
10116           return;
10117         }
10118       }
10119       {
10120         // Match 15-30 "a"'s against 15 and a "b".
10121         const char* c_source =
10122             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10123             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10124         Local<String> source = String::New(c_source);
10125         Local<Script> script = Script::Compile(source);
10126         Local<Value> result = script->Run();
10127         if (!result->BooleanValue()) {
10128           gc_during_regexp_ = kRequiredGCs;
10129           return;
10130         }
10131       }
10132       int gc_after = gc_count_;
10133       gc_during_regexp_ += gc_after - gc_before;
10134       rounds++;
10135       i::OS::Sleep(1);
10136     }
10137     regexp_success_ = true;
10138   }
10139 
10140   i::Semaphore* block_;
10141   int gc_count_;
10142   int gc_during_regexp_;
10143   bool regexp_success_;
10144   bool gc_success_;
10145 };
10146 
10147 
10148 // Test that a regular expression execution can be interrupted and
10149 // survive a garbage collection.
TEST(RegExpInterruption)10150 TEST(RegExpInterruption) {
10151   v8::Locker lock;
10152   v8::V8::Initialize();
10153   v8::HandleScope scope;
10154   Local<Context> local_env;
10155   {
10156     LocalContext env;
10157     local_env = env.local();
10158   }
10159 
10160   // Local context should still be live.
10161   CHECK(!local_env.IsEmpty());
10162   local_env->Enter();
10163 
10164   // Should complete without problems.
10165   RegExpInterruptTest().RunTest();
10166 
10167   local_env->Exit();
10168 }
10169 
10170 
10171 class ApplyInterruptTest {
10172  public:
ApplyInterruptTest()10173   ApplyInterruptTest() : block_(NULL) {}
~ApplyInterruptTest()10174   ~ApplyInterruptTest() { delete block_; }
RunTest()10175   void RunTest() {
10176     block_ = i::OS::CreateSemaphore(0);
10177     gc_count_ = 0;
10178     gc_during_apply_ = 0;
10179     apply_success_ = false;
10180     gc_success_ = false;
10181     GCThread gc_thread(i::Isolate::Current(), this);
10182     gc_thread.Start();
10183     v8::Locker::StartPreemption(1);
10184 
10185     LongRunningApply();
10186     {
10187       v8::Unlocker unlock;
10188       gc_thread.Join();
10189     }
10190     v8::Locker::StopPreemption();
10191     CHECK(apply_success_);
10192     CHECK(gc_success_);
10193   }
10194  private:
10195   // Number of garbage collections required.
10196   static const int kRequiredGCs = 2;
10197 
10198   class GCThread : public i::Thread {
10199    public:
GCThread(i::Isolate * isolate,ApplyInterruptTest * test)10200     explicit GCThread(i::Isolate* isolate, ApplyInterruptTest* test)
10201         : Thread(isolate, "GCThread"), test_(test) {}
Run()10202     virtual void Run() {
10203       test_->CollectGarbage();
10204     }
10205    private:
10206      ApplyInterruptTest* test_;
10207   };
10208 
CollectGarbage()10209   void CollectGarbage() {
10210     block_->Wait();
10211     while (gc_during_apply_ < kRequiredGCs) {
10212       {
10213         v8::Locker lock;
10214         HEAP->CollectAllGarbage(false);
10215         gc_count_++;
10216       }
10217       i::OS::Sleep(1);
10218     }
10219     gc_success_ = true;
10220   }
10221 
LongRunningApply()10222   void LongRunningApply() {
10223     block_->Signal();
10224     int rounds = 0;
10225     while (gc_during_apply_ < kRequiredGCs) {
10226       int gc_before = gc_count_;
10227       {
10228         const char* c_source =
10229             "function do_very_little(bar) {"
10230             "  this.foo = bar;"
10231             "}"
10232             "for (var i = 0; i < 100000; i++) {"
10233             "  do_very_little.apply(this, ['bar']);"
10234             "}";
10235         Local<String> source = String::New(c_source);
10236         Local<Script> script = Script::Compile(source);
10237         Local<Value> result = script->Run();
10238         // Check that no exception was thrown.
10239         CHECK(!result.IsEmpty());
10240       }
10241       int gc_after = gc_count_;
10242       gc_during_apply_ += gc_after - gc_before;
10243       rounds++;
10244     }
10245     apply_success_ = true;
10246   }
10247 
10248   i::Semaphore* block_;
10249   int gc_count_;
10250   int gc_during_apply_;
10251   bool apply_success_;
10252   bool gc_success_;
10253 };
10254 
10255 
10256 // Test that nothing bad happens if we get a preemption just when we were
10257 // about to do an apply().
TEST(ApplyInterruption)10258 TEST(ApplyInterruption) {
10259   v8::Locker lock;
10260   v8::V8::Initialize();
10261   v8::HandleScope scope;
10262   Local<Context> local_env;
10263   {
10264     LocalContext env;
10265     local_env = env.local();
10266   }
10267 
10268   // Local context should still be live.
10269   CHECK(!local_env.IsEmpty());
10270   local_env->Enter();
10271 
10272   // Should complete without problems.
10273   ApplyInterruptTest().RunTest();
10274 
10275   local_env->Exit();
10276 }
10277 
10278 
10279 // Verify that we can clone an object
TEST(ObjectClone)10280 TEST(ObjectClone) {
10281   v8::HandleScope scope;
10282   LocalContext env;
10283 
10284   const char* sample =
10285     "var rv = {};"      \
10286     "rv.alpha = 'hello';" \
10287     "rv.beta = 123;"     \
10288     "rv;";
10289 
10290   // Create an object, verify basics.
10291   Local<Value> val = CompileRun(sample);
10292   CHECK(val->IsObject());
10293   Local<v8::Object> obj = val.As<v8::Object>();
10294   obj->Set(v8_str("gamma"), v8_str("cloneme"));
10295 
10296   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
10297   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10298   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
10299 
10300   // Clone it.
10301   Local<v8::Object> clone = obj->Clone();
10302   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
10303   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
10304   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
10305 
10306   // Set a property on the clone, verify each object.
10307   clone->Set(v8_str("beta"), v8::Integer::New(456));
10308   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10309   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
10310 }
10311 
10312 
10313 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
10314  public:
AsciiVectorResource(i::Vector<const char> vector)10315   explicit AsciiVectorResource(i::Vector<const char> vector)
10316       : data_(vector) {}
~AsciiVectorResource()10317   virtual ~AsciiVectorResource() {}
length() const10318   virtual size_t length() const { return data_.length(); }
data() const10319   virtual const char* data() const { return data_.start(); }
10320  private:
10321   i::Vector<const char> data_;
10322 };
10323 
10324 
10325 class UC16VectorResource : public v8::String::ExternalStringResource {
10326  public:
UC16VectorResource(i::Vector<const i::uc16> vector)10327   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
10328       : data_(vector) {}
~UC16VectorResource()10329   virtual ~UC16VectorResource() {}
length() const10330   virtual size_t length() const { return data_.length(); }
data() const10331   virtual const i::uc16* data() const { return data_.start(); }
10332  private:
10333   i::Vector<const i::uc16> data_;
10334 };
10335 
10336 
MorphAString(i::String * string,AsciiVectorResource * ascii_resource,UC16VectorResource * uc16_resource)10337 static void MorphAString(i::String* string,
10338                          AsciiVectorResource* ascii_resource,
10339                          UC16VectorResource* uc16_resource) {
10340   CHECK(i::StringShape(string).IsExternal());
10341   if (string->IsAsciiRepresentation()) {
10342     // Check old map is not symbol or long.
10343     CHECK(string->map() == HEAP->external_ascii_string_map());
10344     // Morph external string to be TwoByte string.
10345     string->set_map(HEAP->external_string_map());
10346     i::ExternalTwoByteString* morphed =
10347          i::ExternalTwoByteString::cast(string);
10348     morphed->set_resource(uc16_resource);
10349   } else {
10350     // Check old map is not symbol or long.
10351     CHECK(string->map() == HEAP->external_string_map());
10352     // Morph external string to be ASCII string.
10353     string->set_map(HEAP->external_ascii_string_map());
10354     i::ExternalAsciiString* morphed =
10355          i::ExternalAsciiString::cast(string);
10356     morphed->set_resource(ascii_resource);
10357   }
10358 }
10359 
10360 
10361 // Test that we can still flatten a string if the components it is built up
10362 // from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest)10363 THREADED_TEST(MorphCompositeStringTest) {
10364   const char* c_string = "Now is the time for all good men"
10365                          " to come to the aid of the party";
10366   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
10367   {
10368     v8::HandleScope scope;
10369     LocalContext env;
10370     AsciiVectorResource ascii_resource(
10371         i::Vector<const char>(c_string, i::StrLength(c_string)));
10372     UC16VectorResource uc16_resource(
10373         i::Vector<const uint16_t>(two_byte_string,
10374                                   i::StrLength(c_string)));
10375 
10376     Local<String> lhs(v8::Utils::ToLocal(
10377         FACTORY->NewExternalStringFromAscii(&ascii_resource)));
10378     Local<String> rhs(v8::Utils::ToLocal(
10379         FACTORY->NewExternalStringFromAscii(&ascii_resource)));
10380 
10381     env->Global()->Set(v8_str("lhs"), lhs);
10382     env->Global()->Set(v8_str("rhs"), rhs);
10383 
10384     CompileRun(
10385         "var cons = lhs + rhs;"
10386         "var slice = lhs.substring(1, lhs.length - 1);"
10387         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
10388 
10389     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
10390     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
10391 
10392     // Now do some stuff to make sure the strings are flattened, etc.
10393     CompileRun(
10394         "/[^a-z]/.test(cons);"
10395         "/[^a-z]/.test(slice);"
10396         "/[^a-z]/.test(slice_on_cons);");
10397     const char* expected_cons =
10398         "Now is the time for all good men to come to the aid of the party"
10399         "Now is the time for all good men to come to the aid of the party";
10400     const char* expected_slice =
10401         "ow is the time for all good men to come to the aid of the part";
10402     const char* expected_slice_on_cons =
10403         "ow is the time for all good men to come to the aid of the party"
10404         "Now is the time for all good men to come to the aid of the part";
10405     CHECK_EQ(String::New(expected_cons),
10406              env->Global()->Get(v8_str("cons")));
10407     CHECK_EQ(String::New(expected_slice),
10408              env->Global()->Get(v8_str("slice")));
10409     CHECK_EQ(String::New(expected_slice_on_cons),
10410              env->Global()->Get(v8_str("slice_on_cons")));
10411   }
10412   i::DeleteArray(two_byte_string);
10413 }
10414 
10415 
TEST(CompileExternalTwoByteSource)10416 TEST(CompileExternalTwoByteSource) {
10417   v8::HandleScope scope;
10418   LocalContext context;
10419 
10420   // This is a very short list of sources, which currently is to check for a
10421   // regression caused by r2703.
10422   const char* ascii_sources[] = {
10423     "0.5",
10424     "-0.5",   // This mainly testes PushBack in the Scanner.
10425     "--0.5",  // This mainly testes PushBack in the Scanner.
10426     NULL
10427   };
10428 
10429   // Compile the sources as external two byte strings.
10430   for (int i = 0; ascii_sources[i] != NULL; i++) {
10431     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
10432     UC16VectorResource uc16_resource(
10433         i::Vector<const uint16_t>(two_byte_string,
10434                                   i::StrLength(ascii_sources[i])));
10435     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
10436     v8::Script::Compile(source);
10437     i::DeleteArray(two_byte_string);
10438   }
10439 }
10440 
10441 
10442 class RegExpStringModificationTest {
10443  public:
RegExpStringModificationTest()10444   RegExpStringModificationTest()
10445       : block_(i::OS::CreateSemaphore(0)),
10446         morphs_(0),
10447         morphs_during_regexp_(0),
10448         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
10449         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
~RegExpStringModificationTest()10450   ~RegExpStringModificationTest() { delete block_; }
RunTest()10451   void RunTest() {
10452     regexp_success_ = false;
10453     morph_success_ = false;
10454 
10455     // Initialize the contents of two_byte_content_ to be a uc16 representation
10456     // of "aaaaaaaaaaaaaab".
10457     for (int i = 0; i < 14; i++) {
10458       two_byte_content_[i] = 'a';
10459     }
10460     two_byte_content_[14] = 'b';
10461 
10462     // Create the input string for the regexp - the one we are going to change
10463     // properties of.
10464     input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
10465 
10466     // Inject the input as a global variable.
10467     i::Handle<i::String> input_name =
10468         FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
10469     i::Isolate::Current()->global_context()->global()->SetProperty(
10470         *input_name,
10471         *input_,
10472         NONE,
10473         i::kNonStrictMode)->ToObjectChecked();
10474 
10475     MorphThread morph_thread(i::Isolate::Current(), this);
10476     morph_thread.Start();
10477     v8::Locker::StartPreemption(1);
10478     LongRunningRegExp();
10479     {
10480       v8::Unlocker unlock;
10481       morph_thread.Join();
10482     }
10483     v8::Locker::StopPreemption();
10484     CHECK(regexp_success_);
10485     CHECK(morph_success_);
10486   }
10487  private:
10488 
10489   // Number of string modifications required.
10490   static const int kRequiredModifications = 5;
10491   static const int kMaxModifications = 100;
10492 
10493   class MorphThread : public i::Thread {
10494    public:
MorphThread(i::Isolate * isolate,RegExpStringModificationTest * test)10495     explicit MorphThread(i::Isolate* isolate,
10496                          RegExpStringModificationTest* test)
10497         : Thread(isolate, "MorphThread"), test_(test) {}
Run()10498     virtual void Run() {
10499       test_->MorphString();
10500     }
10501    private:
10502      RegExpStringModificationTest* test_;
10503   };
10504 
MorphString()10505   void MorphString() {
10506     block_->Wait();
10507     while (morphs_during_regexp_ < kRequiredModifications &&
10508            morphs_ < kMaxModifications) {
10509       {
10510         v8::Locker lock;
10511         // Swap string between ascii and two-byte representation.
10512         i::String* string = *input_;
10513         MorphAString(string, &ascii_resource_, &uc16_resource_);
10514         morphs_++;
10515       }
10516       i::OS::Sleep(1);
10517     }
10518     morph_success_ = true;
10519   }
10520 
LongRunningRegExp()10521   void LongRunningRegExp() {
10522     block_->Signal();  // Enable morphing thread on next preemption.
10523     while (morphs_during_regexp_ < kRequiredModifications &&
10524            morphs_ < kMaxModifications) {
10525       int morphs_before = morphs_;
10526       {
10527         v8::HandleScope scope;
10528         // Match 15-30 "a"'s against 14 and a "b".
10529         const char* c_source =
10530             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10531             ".exec(input) === null";
10532         Local<String> source = String::New(c_source);
10533         Local<Script> script = Script::Compile(source);
10534         Local<Value> result = script->Run();
10535         CHECK(result->IsTrue());
10536       }
10537       int morphs_after = morphs_;
10538       morphs_during_regexp_ += morphs_after - morphs_before;
10539     }
10540     regexp_success_ = true;
10541   }
10542 
10543   i::uc16 two_byte_content_[15];
10544   i::Semaphore* block_;
10545   int morphs_;
10546   int morphs_during_regexp_;
10547   bool regexp_success_;
10548   bool morph_success_;
10549   i::Handle<i::String> input_;
10550   AsciiVectorResource ascii_resource_;
10551   UC16VectorResource uc16_resource_;
10552 };
10553 
10554 
10555 // Test that a regular expression execution can be interrupted and
10556 // the string changed without failing.
TEST(RegExpStringModification)10557 TEST(RegExpStringModification) {
10558   v8::Locker lock;
10559   v8::V8::Initialize();
10560   v8::HandleScope scope;
10561   Local<Context> local_env;
10562   {
10563     LocalContext env;
10564     local_env = env.local();
10565   }
10566 
10567   // Local context should still be live.
10568   CHECK(!local_env.IsEmpty());
10569   local_env->Enter();
10570 
10571   // Should complete without problems.
10572   RegExpStringModificationTest().RunTest();
10573 
10574   local_env->Exit();
10575 }
10576 
10577 
10578 // Test that we can set a property on the global object even if there
10579 // is a read-only property in the prototype chain.
TEST(ReadOnlyPropertyInGlobalProto)10580 TEST(ReadOnlyPropertyInGlobalProto) {
10581   v8::HandleScope scope;
10582   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10583   LocalContext context(0, templ);
10584   v8::Handle<v8::Object> global = context->Global();
10585   v8::Handle<v8::Object> global_proto =
10586       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
10587   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
10588   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
10589   // Check without 'eval' or 'with'.
10590   v8::Handle<v8::Value> res =
10591       CompileRun("function f() { x = 42; return x; }; f()");
10592   // Check with 'eval'.
10593   res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
10594   CHECK_EQ(v8::Integer::New(42), res);
10595   // Check with 'with'.
10596   res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
10597   CHECK_EQ(v8::Integer::New(42), res);
10598 }
10599 
10600 static int force_set_set_count = 0;
10601 static int force_set_get_count = 0;
10602 bool pass_on_get = false;
10603 
ForceSetGetter(v8::Local<v8::String> name,const v8::AccessorInfo & info)10604 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
10605                                             const v8::AccessorInfo& info) {
10606   force_set_get_count++;
10607   if (pass_on_get) {
10608     return v8::Handle<v8::Value>();
10609   } else {
10610     return v8::Int32::New(3);
10611   }
10612 }
10613 
ForceSetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)10614 static void ForceSetSetter(v8::Local<v8::String> name,
10615                            v8::Local<v8::Value> value,
10616                            const v8::AccessorInfo& info) {
10617   force_set_set_count++;
10618 }
10619 
ForceSetInterceptSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)10620 static v8::Handle<v8::Value> ForceSetInterceptSetter(
10621     v8::Local<v8::String> name,
10622     v8::Local<v8::Value> value,
10623     const v8::AccessorInfo& info) {
10624   force_set_set_count++;
10625   return v8::Undefined();
10626 }
10627 
TEST(ForceSet)10628 TEST(ForceSet) {
10629   force_set_get_count = 0;
10630   force_set_set_count = 0;
10631   pass_on_get = false;
10632 
10633   v8::HandleScope scope;
10634   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10635   v8::Handle<v8::String> access_property = v8::String::New("a");
10636   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
10637   LocalContext context(NULL, templ);
10638   v8::Handle<v8::Object> global = context->Global();
10639 
10640   // Ordinary properties
10641   v8::Handle<v8::String> simple_property = v8::String::New("p");
10642   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
10643   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10644   // This should fail because the property is read-only
10645   global->Set(simple_property, v8::Int32::New(5));
10646   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10647   // This should succeed even though the property is read-only
10648   global->ForceSet(simple_property, v8::Int32::New(6));
10649   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
10650 
10651   // Accessors
10652   CHECK_EQ(0, force_set_set_count);
10653   CHECK_EQ(0, force_set_get_count);
10654   CHECK_EQ(3, global->Get(access_property)->Int32Value());
10655   // CHECK_EQ the property shouldn't override it, just call the setter
10656   // which in this case does nothing.
10657   global->Set(access_property, v8::Int32::New(7));
10658   CHECK_EQ(3, global->Get(access_property)->Int32Value());
10659   CHECK_EQ(1, force_set_set_count);
10660   CHECK_EQ(2, force_set_get_count);
10661   // Forcing the property to be set should override the accessor without
10662   // calling it
10663   global->ForceSet(access_property, v8::Int32::New(8));
10664   CHECK_EQ(8, global->Get(access_property)->Int32Value());
10665   CHECK_EQ(1, force_set_set_count);
10666   CHECK_EQ(2, force_set_get_count);
10667 }
10668 
TEST(ForceSetWithInterceptor)10669 TEST(ForceSetWithInterceptor) {
10670   force_set_get_count = 0;
10671   force_set_set_count = 0;
10672   pass_on_get = false;
10673 
10674   v8::HandleScope scope;
10675   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10676   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
10677   LocalContext context(NULL, templ);
10678   v8::Handle<v8::Object> global = context->Global();
10679 
10680   v8::Handle<v8::String> some_property = v8::String::New("a");
10681   CHECK_EQ(0, force_set_set_count);
10682   CHECK_EQ(0, force_set_get_count);
10683   CHECK_EQ(3, global->Get(some_property)->Int32Value());
10684   // Setting the property shouldn't override it, just call the setter
10685   // which in this case does nothing.
10686   global->Set(some_property, v8::Int32::New(7));
10687   CHECK_EQ(3, global->Get(some_property)->Int32Value());
10688   CHECK_EQ(1, force_set_set_count);
10689   CHECK_EQ(2, force_set_get_count);
10690   // Getting the property when the interceptor returns an empty handle
10691   // should yield undefined, since the property isn't present on the
10692   // object itself yet.
10693   pass_on_get = true;
10694   CHECK(global->Get(some_property)->IsUndefined());
10695   CHECK_EQ(1, force_set_set_count);
10696   CHECK_EQ(3, force_set_get_count);
10697   // Forcing the property to be set should cause the value to be
10698   // set locally without calling the interceptor.
10699   global->ForceSet(some_property, v8::Int32::New(8));
10700   CHECK_EQ(8, global->Get(some_property)->Int32Value());
10701   CHECK_EQ(1, force_set_set_count);
10702   CHECK_EQ(4, force_set_get_count);
10703   // Reenabling the interceptor should cause it to take precedence over
10704   // the property
10705   pass_on_get = false;
10706   CHECK_EQ(3, global->Get(some_property)->Int32Value());
10707   CHECK_EQ(1, force_set_set_count);
10708   CHECK_EQ(5, force_set_get_count);
10709   // The interceptor should also work for other properties
10710   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
10711   CHECK_EQ(1, force_set_set_count);
10712   CHECK_EQ(6, force_set_get_count);
10713 }
10714 
10715 
THREADED_TEST(ForceDelete)10716 THREADED_TEST(ForceDelete) {
10717   v8::HandleScope scope;
10718   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10719   LocalContext context(NULL, templ);
10720   v8::Handle<v8::Object> global = context->Global();
10721 
10722   // Ordinary properties
10723   v8::Handle<v8::String> simple_property = v8::String::New("p");
10724   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
10725   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10726   // This should fail because the property is dont-delete.
10727   CHECK(!global->Delete(simple_property));
10728   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10729   // This should succeed even though the property is dont-delete.
10730   CHECK(global->ForceDelete(simple_property));
10731   CHECK(global->Get(simple_property)->IsUndefined());
10732 }
10733 
10734 
10735 static int force_delete_interceptor_count = 0;
10736 static bool pass_on_delete = false;
10737 
10738 
ForceDeleteDeleter(v8::Local<v8::String> name,const v8::AccessorInfo & info)10739 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
10740     v8::Local<v8::String> name,
10741     const v8::AccessorInfo& info) {
10742   force_delete_interceptor_count++;
10743   if (pass_on_delete) {
10744     return v8::Handle<v8::Boolean>();
10745   } else {
10746     return v8::True();
10747   }
10748 }
10749 
10750 
THREADED_TEST(ForceDeleteWithInterceptor)10751 THREADED_TEST(ForceDeleteWithInterceptor) {
10752   force_delete_interceptor_count = 0;
10753   pass_on_delete = false;
10754 
10755   v8::HandleScope scope;
10756   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10757   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
10758   LocalContext context(NULL, templ);
10759   v8::Handle<v8::Object> global = context->Global();
10760 
10761   v8::Handle<v8::String> some_property = v8::String::New("a");
10762   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
10763 
10764   // Deleting a property should get intercepted and nothing should
10765   // happen.
10766   CHECK_EQ(0, force_delete_interceptor_count);
10767   CHECK(global->Delete(some_property));
10768   CHECK_EQ(1, force_delete_interceptor_count);
10769   CHECK_EQ(42, global->Get(some_property)->Int32Value());
10770   // Deleting the property when the interceptor returns an empty
10771   // handle should not delete the property since it is DontDelete.
10772   pass_on_delete = true;
10773   CHECK(!global->Delete(some_property));
10774   CHECK_EQ(2, force_delete_interceptor_count);
10775   CHECK_EQ(42, global->Get(some_property)->Int32Value());
10776   // Forcing the property to be deleted should delete the value
10777   // without calling the interceptor.
10778   CHECK(global->ForceDelete(some_property));
10779   CHECK(global->Get(some_property)->IsUndefined());
10780   CHECK_EQ(2, force_delete_interceptor_count);
10781 }
10782 
10783 
10784 // Make sure that forcing a delete invalidates any IC stubs, so we
10785 // don't read the hole value.
THREADED_TEST(ForceDeleteIC)10786 THREADED_TEST(ForceDeleteIC) {
10787   v8::HandleScope scope;
10788   LocalContext context;
10789   // Create a DontDelete variable on the global object.
10790   CompileRun("this.__proto__ = { foo: 'horse' };"
10791              "var foo = 'fish';"
10792              "function f() { return foo.length; }");
10793   // Initialize the IC for foo in f.
10794   CompileRun("for (var i = 0; i < 4; i++) f();");
10795   // Make sure the value of foo is correct before the deletion.
10796   CHECK_EQ(4, CompileRun("f()")->Int32Value());
10797   // Force the deletion of foo.
10798   CHECK(context->Global()->ForceDelete(v8_str("foo")));
10799   // Make sure the value for foo is read from the prototype, and that
10800   // we don't get in trouble with reading the deleted cell value
10801   // sentinel.
10802   CHECK_EQ(5, CompileRun("f()")->Int32Value());
10803 }
10804 
10805 
10806 v8::Persistent<Context> calling_context0;
10807 v8::Persistent<Context> calling_context1;
10808 v8::Persistent<Context> calling_context2;
10809 
10810 
10811 // Check that the call to the callback is initiated in
10812 // calling_context2, the directly calling context is calling_context1
10813 // and the callback itself is in calling_context0.
GetCallingContextCallback(const v8::Arguments & args)10814 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10815   ApiTestFuzzer::Fuzz();
10816   CHECK(Context::GetCurrent() == calling_context0);
10817   CHECK(Context::GetCalling() == calling_context1);
10818   CHECK(Context::GetEntered() == calling_context2);
10819   return v8::Integer::New(42);
10820 }
10821 
10822 
THREADED_TEST(GetCallingContext)10823 THREADED_TEST(GetCallingContext) {
10824   v8::HandleScope scope;
10825 
10826   calling_context0 = Context::New();
10827   calling_context1 = Context::New();
10828   calling_context2 = Context::New();
10829 
10830   // Allow cross-domain access.
10831   Local<String> token = v8_str("<security token>");
10832   calling_context0->SetSecurityToken(token);
10833   calling_context1->SetSecurityToken(token);
10834   calling_context2->SetSecurityToken(token);
10835 
10836   // Create an object with a C++ callback in context0.
10837   calling_context0->Enter();
10838   Local<v8::FunctionTemplate> callback_templ =
10839       v8::FunctionTemplate::New(GetCallingContextCallback);
10840   calling_context0->Global()->Set(v8_str("callback"),
10841                                   callback_templ->GetFunction());
10842   calling_context0->Exit();
10843 
10844   // Expose context0 in context1 and setup a function that calls the
10845   // callback function.
10846   calling_context1->Enter();
10847   calling_context1->Global()->Set(v8_str("context0"),
10848                                   calling_context0->Global());
10849   CompileRun("function f() { context0.callback() }");
10850   calling_context1->Exit();
10851 
10852   // Expose context1 in context2 and call the callback function in
10853   // context0 indirectly through f in context1.
10854   calling_context2->Enter();
10855   calling_context2->Global()->Set(v8_str("context1"),
10856                                   calling_context1->Global());
10857   CompileRun("context1.f()");
10858   calling_context2->Exit();
10859 
10860   // Dispose the contexts to allow them to be garbage collected.
10861   calling_context0.Dispose();
10862   calling_context1.Dispose();
10863   calling_context2.Dispose();
10864   calling_context0.Clear();
10865   calling_context1.Clear();
10866   calling_context2.Clear();
10867 }
10868 
10869 
10870 // Check that a variable declaration with no explicit initialization
10871 // value does not shadow an existing property in the prototype chain.
10872 //
10873 // This is consistent with Firefox and Safari.
10874 //
10875 // See http://crbug.com/12548.
THREADED_TEST(InitGlobalVarInProtoChain)10876 THREADED_TEST(InitGlobalVarInProtoChain) {
10877   v8::HandleScope scope;
10878   LocalContext context;
10879   // Introduce a variable in the prototype chain.
10880   CompileRun("__proto__.x = 42");
10881   v8::Handle<v8::Value> result = CompileRun("var x; x");
10882   CHECK(!result->IsUndefined());
10883   CHECK_EQ(42, result->Int32Value());
10884 }
10885 
10886 
10887 // Regression test for issue 398.
10888 // If a function is added to an object, creating a constant function
10889 // field, and the result is cloned, replacing the constant function on the
10890 // original should not affect the clone.
10891 // See http://code.google.com/p/v8/issues/detail?id=398
THREADED_TEST(ReplaceConstantFunction)10892 THREADED_TEST(ReplaceConstantFunction) {
10893   v8::HandleScope scope;
10894   LocalContext context;
10895   v8::Handle<v8::Object> obj = v8::Object::New();
10896   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10897   v8::Handle<v8::String> foo_string = v8::String::New("foo");
10898   obj->Set(foo_string, func_templ->GetFunction());
10899   v8::Handle<v8::Object> obj_clone = obj->Clone();
10900   obj_clone->Set(foo_string, v8::String::New("Hello"));
10901   CHECK(!obj->Get(foo_string)->IsUndefined());
10902 }
10903 
10904 
10905 // Regression test for http://crbug.com/16276.
THREADED_TEST(Regress16276)10906 THREADED_TEST(Regress16276) {
10907   v8::HandleScope scope;
10908   LocalContext context;
10909   // Force the IC in f to be a dictionary load IC.
10910   CompileRun("function f(obj) { return obj.x; }\n"
10911              "var obj = { x: { foo: 42 }, y: 87 };\n"
10912              "var x = obj.x;\n"
10913              "delete obj.y;\n"
10914              "for (var i = 0; i < 5; i++) f(obj);");
10915   // Detach the global object to make 'this' refer directly to the
10916   // global object (not the proxy), and make sure that the dictionary
10917   // load IC doesn't mess up loading directly from the global object.
10918   context->DetachGlobal();
10919   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10920 }
10921 
10922 
THREADED_TEST(PixelArray)10923 THREADED_TEST(PixelArray) {
10924   v8::HandleScope scope;
10925   LocalContext context;
10926   const int kElementCount = 260;
10927   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10928   i::Handle<i::ExternalPixelArray> pixels =
10929       i::Handle<i::ExternalPixelArray>::cast(
10930           FACTORY->NewExternalArray(kElementCount,
10931                                        v8::kExternalPixelArray,
10932                                        pixel_data));
10933   HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
10934   for (int i = 0; i < kElementCount; i++) {
10935     pixels->set(i, i % 256);
10936   }
10937   HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
10938   for (int i = 0; i < kElementCount; i++) {
10939     CHECK_EQ(i % 256, pixels->get(i));
10940     CHECK_EQ(i % 256, pixel_data[i]);
10941   }
10942 
10943   v8::Handle<v8::Object> obj = v8::Object::New();
10944   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10945   // Set the elements to be the pixels.
10946   // jsobj->set_elements(*pixels);
10947   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
10948   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10949   obj->Set(v8_str("field"), v8::Int32::New(1503));
10950   context->Global()->Set(v8_str("pixels"), obj);
10951   v8::Handle<v8::Value> result = CompileRun("pixels.field");
10952   CHECK_EQ(1503, result->Int32Value());
10953   result = CompileRun("pixels[1]");
10954   CHECK_EQ(1, result->Int32Value());
10955 
10956   result = CompileRun("var sum = 0;"
10957                       "for (var i = 0; i < 8; i++) {"
10958                       "  sum += pixels[i] = pixels[i] = -i;"
10959                       "}"
10960                       "sum;");
10961   CHECK_EQ(-28, result->Int32Value());
10962 
10963   result = CompileRun("var sum = 0;"
10964                       "for (var i = 0; i < 8; i++) {"
10965                       "  sum += pixels[i] = pixels[i] = 0;"
10966                       "}"
10967                       "sum;");
10968   CHECK_EQ(0, result->Int32Value());
10969 
10970   result = CompileRun("var sum = 0;"
10971                       "for (var i = 0; i < 8; i++) {"
10972                       "  sum += pixels[i] = pixels[i] = 255;"
10973                       "}"
10974                       "sum;");
10975   CHECK_EQ(8 * 255, result->Int32Value());
10976 
10977   result = CompileRun("var sum = 0;"
10978                       "for (var i = 0; i < 8; i++) {"
10979                       "  sum += pixels[i] = pixels[i] = 256 + i;"
10980                       "}"
10981                       "sum;");
10982   CHECK_EQ(2076, result->Int32Value());
10983 
10984   result = CompileRun("var sum = 0;"
10985                       "for (var i = 0; i < 8; i++) {"
10986                       "  sum += pixels[i] = pixels[i] = i;"
10987                       "}"
10988                       "sum;");
10989   CHECK_EQ(28, result->Int32Value());
10990 
10991   result = CompileRun("var sum = 0;"
10992                       "for (var i = 0; i < 8; i++) {"
10993                       "  sum += pixels[i];"
10994                       "}"
10995                       "sum;");
10996   CHECK_EQ(28, result->Int32Value());
10997 
10998   i::Handle<i::Smi> value(i::Smi::FromInt(2));
10999   i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11000   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11001   *value.location() = i::Smi::FromInt(256);
11002   i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11003   CHECK_EQ(255,
11004            i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11005   *value.location() = i::Smi::FromInt(-1);
11006   i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11007   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11008 
11009   result = CompileRun("for (var i = 0; i < 8; i++) {"
11010                       "  pixels[i] = (i * 65) - 109;"
11011                       "}"
11012                       "pixels[1] + pixels[6];");
11013   CHECK_EQ(255, result->Int32Value());
11014   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11015   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11016   CHECK_EQ(21,
11017            i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11018   CHECK_EQ(86,
11019            i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11020   CHECK_EQ(151,
11021            i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11022   CHECK_EQ(216,
11023            i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11024   CHECK_EQ(255,
11025            i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11026   CHECK_EQ(255,
11027            i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11028   result = CompileRun("var sum = 0;"
11029                       "for (var i = 0; i < 8; i++) {"
11030                       "  sum += pixels[i];"
11031                       "}"
11032                       "sum;");
11033   CHECK_EQ(984, result->Int32Value());
11034 
11035   result = CompileRun("for (var i = 0; i < 8; i++) {"
11036                       "  pixels[i] = (i * 1.1);"
11037                       "}"
11038                       "pixels[1] + pixels[6];");
11039   CHECK_EQ(8, result->Int32Value());
11040   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11041   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11042   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11043   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11044   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11045   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11046   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11047   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11048 
11049   result = CompileRun("for (var i = 0; i < 8; i++) {"
11050                       "  pixels[7] = undefined;"
11051                       "}"
11052                       "pixels[7];");
11053   CHECK_EQ(0, result->Int32Value());
11054   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11055 
11056   result = CompileRun("for (var i = 0; i < 8; i++) {"
11057                       "  pixels[6] = '2.3';"
11058                       "}"
11059                       "pixels[6];");
11060   CHECK_EQ(2, result->Int32Value());
11061   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11062 
11063   result = CompileRun("for (var i = 0; i < 8; i++) {"
11064                       "  pixels[5] = NaN;"
11065                       "}"
11066                       "pixels[5];");
11067   CHECK_EQ(0, result->Int32Value());
11068   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11069 
11070   result = CompileRun("for (var i = 0; i < 8; i++) {"
11071                       "  pixels[8] = Infinity;"
11072                       "}"
11073                       "pixels[8];");
11074   CHECK_EQ(255, result->Int32Value());
11075   CHECK_EQ(255,
11076            i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
11077 
11078   result = CompileRun("for (var i = 0; i < 8; i++) {"
11079                       "  pixels[9] = -Infinity;"
11080                       "}"
11081                       "pixels[9];");
11082   CHECK_EQ(0, result->Int32Value());
11083   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
11084 
11085   result = CompileRun("pixels[3] = 33;"
11086                       "delete pixels[3];"
11087                       "pixels[3];");
11088   CHECK_EQ(33, result->Int32Value());
11089 
11090   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11091                       "pixels[2] = 12; pixels[3] = 13;"
11092                       "pixels.__defineGetter__('2',"
11093                       "function() { return 120; });"
11094                       "pixels[2];");
11095   CHECK_EQ(12, result->Int32Value());
11096 
11097   result = CompileRun("var js_array = new Array(40);"
11098                       "js_array[0] = 77;"
11099                       "js_array;");
11100   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11101 
11102   result = CompileRun("pixels[1] = 23;"
11103                       "pixels.__proto__ = [];"
11104                       "js_array.__proto__ = pixels;"
11105                       "js_array.concat(pixels);");
11106   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11107   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11108 
11109   result = CompileRun("pixels[1] = 23;");
11110   CHECK_EQ(23, result->Int32Value());
11111 
11112   // Test for index greater than 255.  Regression test for:
11113   // http://code.google.com/p/chromium/issues/detail?id=26337.
11114   result = CompileRun("pixels[256] = 255;");
11115   CHECK_EQ(255, result->Int32Value());
11116   result = CompileRun("var i = 0;"
11117                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11118                       "i");
11119   CHECK_EQ(255, result->Int32Value());
11120 
11121   // Make sure that pixel array ICs recognize when a non-pixel array
11122   // is passed to it.
11123   result = CompileRun("function pa_load(p) {"
11124                       "  var sum = 0;"
11125                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11126                       "  return sum;"
11127                       "}"
11128                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11129                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11130                       "just_ints = new Object();"
11131                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11132                       "for (var i = 0; i < 10; ++i) {"
11133                       "  result = pa_load(just_ints);"
11134                       "}"
11135                       "result");
11136   CHECK_EQ(32640, result->Int32Value());
11137 
11138   // Make sure that pixel array ICs recognize out-of-bound accesses.
11139   result = CompileRun("function pa_load(p, start) {"
11140                       "  var sum = 0;"
11141                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11142                       "  return sum;"
11143                       "}"
11144                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11145                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11146                       "for (var i = 0; i < 10; ++i) {"
11147                       "  result = pa_load(pixels,-10);"
11148                       "}"
11149                       "result");
11150   CHECK_EQ(0, result->Int32Value());
11151 
11152   // Make sure that generic ICs properly handles a pixel array.
11153   result = CompileRun("function pa_load(p) {"
11154                       "  var sum = 0;"
11155                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11156                       "  return sum;"
11157                       "}"
11158                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11159                       "just_ints = new Object();"
11160                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11161                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11162                       "for (var i = 0; i < 10; ++i) {"
11163                       "  result = pa_load(pixels);"
11164                       "}"
11165                       "result");
11166   CHECK_EQ(32640, result->Int32Value());
11167 
11168   // Make sure that generic load ICs recognize out-of-bound accesses in
11169   // pixel arrays.
11170   result = CompileRun("function pa_load(p, start) {"
11171                       "  var sum = 0;"
11172                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11173                       "  return sum;"
11174                       "}"
11175                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11176                       "just_ints = new Object();"
11177                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11178                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11179                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11180                       "for (var i = 0; i < 10; ++i) {"
11181                       "  result = pa_load(pixels,-10);"
11182                       "}"
11183                       "result");
11184   CHECK_EQ(0, result->Int32Value());
11185 
11186   // Make sure that generic ICs properly handles other types than pixel
11187   // arrays (that the inlined fast pixel array test leaves the right information
11188   // in the right registers).
11189   result = CompileRun("function pa_load(p) {"
11190                       "  var sum = 0;"
11191                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11192                       "  return sum;"
11193                       "}"
11194                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11195                       "just_ints = new Object();"
11196                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11197                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11198                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11199                       "sparse_array = new Object();"
11200                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11201                       "sparse_array[1000000] = 3;"
11202                       "for (var i = 0; i < 10; ++i) {"
11203                       "  result = pa_load(sparse_array);"
11204                       "}"
11205                       "result");
11206   CHECK_EQ(32640, result->Int32Value());
11207 
11208   // Make sure that pixel array store ICs clamp values correctly.
11209   result = CompileRun("function pa_store(p) {"
11210                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11211                       "}"
11212                       "pa_store(pixels);"
11213                       "var sum = 0;"
11214                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11215                       "sum");
11216   CHECK_EQ(48896, result->Int32Value());
11217 
11218   // Make sure that pixel array stores correctly handle accesses outside
11219   // of the pixel array..
11220   result = CompileRun("function pa_store(p,start) {"
11221                       "  for (var j = 0; j < 256; j++) {"
11222                       "    p[j+start] = j * 2;"
11223                       "  }"
11224                       "}"
11225                       "pa_store(pixels,0);"
11226                       "pa_store(pixels,-128);"
11227                       "var sum = 0;"
11228                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11229                       "sum");
11230   CHECK_EQ(65280, result->Int32Value());
11231 
11232   // Make sure that the generic store stub correctly handle accesses outside
11233   // of the pixel array..
11234   result = CompileRun("function pa_store(p,start) {"
11235                       "  for (var j = 0; j < 256; j++) {"
11236                       "    p[j+start] = j * 2;"
11237                       "  }"
11238                       "}"
11239                       "pa_store(pixels,0);"
11240                       "just_ints = new Object();"
11241                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11242                       "pa_store(just_ints, 0);"
11243                       "pa_store(pixels,-128);"
11244                       "var sum = 0;"
11245                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11246                       "sum");
11247   CHECK_EQ(65280, result->Int32Value());
11248 
11249   // Make sure that the generic keyed store stub clamps pixel array values
11250   // correctly.
11251   result = CompileRun("function pa_store(p) {"
11252                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11253                       "}"
11254                       "pa_store(pixels);"
11255                       "just_ints = new Object();"
11256                       "pa_store(just_ints);"
11257                       "pa_store(pixels);"
11258                       "var sum = 0;"
11259                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11260                       "sum");
11261   CHECK_EQ(48896, result->Int32Value());
11262 
11263   // Make sure that pixel array loads are optimized by crankshaft.
11264   result = CompileRun("function pa_load(p) {"
11265                       "  var sum = 0;"
11266                       "  for (var i=0; i<256; ++i) {"
11267                       "    sum += p[i];"
11268                       "  }"
11269                       "  return sum; "
11270                       "}"
11271                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11272                       "for (var i = 0; i < 5000; ++i) {"
11273                       "  result = pa_load(pixels);"
11274                       "}"
11275                       "result");
11276   CHECK_EQ(32640, result->Int32Value());
11277 
11278   // Make sure that pixel array stores are optimized by crankshaft.
11279   result = CompileRun("function pa_init(p) {"
11280                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11281                       "}"
11282                       "function pa_load(p) {"
11283                       "  var sum = 0;"
11284                       "  for (var i=0; i<256; ++i) {"
11285                       "    sum += p[i];"
11286                       "  }"
11287                       "  return sum; "
11288                       "}"
11289                       "for (var i = 0; i < 5000; ++i) {"
11290                       "  pa_init(pixels);"
11291                       "}"
11292                       "result = pa_load(pixels);"
11293                       "result");
11294   CHECK_EQ(32640, result->Int32Value());
11295 
11296   free(pixel_data);
11297 }
11298 
11299 
THREADED_TEST(PixelArrayInfo)11300 THREADED_TEST(PixelArrayInfo) {
11301   v8::HandleScope scope;
11302   LocalContext context;
11303   for (int size = 0; size < 100; size += 10) {
11304     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
11305     v8::Handle<v8::Object> obj = v8::Object::New();
11306     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
11307     CHECK(obj->HasIndexedPropertiesInPixelData());
11308     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
11309     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
11310     free(pixel_data);
11311   }
11312 }
11313 
11314 
NotHandledIndexedPropertyGetter(uint32_t index,const AccessorInfo & info)11315 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
11316     uint32_t index,
11317     const AccessorInfo& info) {
11318   ApiTestFuzzer::Fuzz();
11319   return v8::Handle<Value>();
11320 }
11321 
11322 
NotHandledIndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)11323 static v8::Handle<Value> NotHandledIndexedPropertySetter(
11324     uint32_t index,
11325     Local<Value> value,
11326     const AccessorInfo& info) {
11327   ApiTestFuzzer::Fuzz();
11328   return v8::Handle<Value>();
11329 }
11330 
11331 
THREADED_TEST(PixelArrayWithInterceptor)11332 THREADED_TEST(PixelArrayWithInterceptor) {
11333   v8::HandleScope scope;
11334   LocalContext context;
11335   const int kElementCount = 260;
11336   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
11337   i::Handle<i::ExternalPixelArray> pixels =
11338       i::Handle<i::ExternalPixelArray>::cast(
11339           FACTORY->NewExternalArray(kElementCount,
11340                                     v8::kExternalPixelArray,
11341                                     pixel_data));
11342   for (int i = 0; i < kElementCount; i++) {
11343     pixels->set(i, i % 256);
11344   }
11345   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11346   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
11347                                    NotHandledIndexedPropertySetter);
11348   v8::Handle<v8::Object> obj = templ->NewInstance();
11349   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
11350   context->Global()->Set(v8_str("pixels"), obj);
11351   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
11352   CHECK_EQ(1, result->Int32Value());
11353   result = CompileRun("var sum = 0;"
11354                       "for (var i = 0; i < 8; i++) {"
11355                       "  sum += pixels[i] = pixels[i] = -i;"
11356                       "}"
11357                       "sum;");
11358   CHECK_EQ(-28, result->Int32Value());
11359   result = CompileRun("pixels.hasOwnProperty('1')");
11360   CHECK(result->BooleanValue());
11361   free(pixel_data);
11362 }
11363 
11364 
ExternalArrayElementSize(v8::ExternalArrayType array_type)11365 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
11366   switch (array_type) {
11367     case v8::kExternalByteArray:
11368     case v8::kExternalUnsignedByteArray:
11369     case v8::kExternalPixelArray:
11370       return 1;
11371       break;
11372     case v8::kExternalShortArray:
11373     case v8::kExternalUnsignedShortArray:
11374       return 2;
11375       break;
11376     case v8::kExternalIntArray:
11377     case v8::kExternalUnsignedIntArray:
11378     case v8::kExternalFloatArray:
11379       return 4;
11380       break;
11381     default:
11382       UNREACHABLE();
11383       return -1;
11384   }
11385   UNREACHABLE();
11386   return -1;
11387 }
11388 
11389 
11390 template <class ExternalArrayClass, class ElementType>
ExternalArrayTestHelper(v8::ExternalArrayType array_type,int64_t low,int64_t high)11391 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
11392                                     int64_t low,
11393                                     int64_t high) {
11394   v8::HandleScope scope;
11395   LocalContext context;
11396   const int kElementCount = 40;
11397   int element_size = ExternalArrayElementSize(array_type);
11398   ElementType* array_data =
11399       static_cast<ElementType*>(malloc(kElementCount * element_size));
11400   i::Handle<ExternalArrayClass> array =
11401       i::Handle<ExternalArrayClass>::cast(
11402           FACTORY->NewExternalArray(kElementCount, array_type, array_data));
11403   HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11404   for (int i = 0; i < kElementCount; i++) {
11405     array->set(i, static_cast<ElementType>(i));
11406   }
11407   HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11408   for (int i = 0; i < kElementCount; i++) {
11409     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
11410     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
11411   }
11412 
11413   v8::Handle<v8::Object> obj = v8::Object::New();
11414   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11415   // Set the elements to be the external array.
11416   obj->SetIndexedPropertiesToExternalArrayData(array_data,
11417                                                array_type,
11418                                                kElementCount);
11419   CHECK_EQ(
11420       1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
11421   obj->Set(v8_str("field"), v8::Int32::New(1503));
11422   context->Global()->Set(v8_str("ext_array"), obj);
11423   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
11424   CHECK_EQ(1503, result->Int32Value());
11425   result = CompileRun("ext_array[1]");
11426   CHECK_EQ(1, result->Int32Value());
11427 
11428   // Check pass through of assigned smis
11429   result = CompileRun("var sum = 0;"
11430                       "for (var i = 0; i < 8; i++) {"
11431                       "  sum += ext_array[i] = ext_array[i] = -i;"
11432                       "}"
11433                       "sum;");
11434   CHECK_EQ(-28, result->Int32Value());
11435 
11436   // Check assigned smis
11437   result = CompileRun("for (var i = 0; i < 8; i++) {"
11438                       "  ext_array[i] = i;"
11439                       "}"
11440                       "var sum = 0;"
11441                       "for (var i = 0; i < 8; i++) {"
11442                       "  sum += ext_array[i];"
11443                       "}"
11444                       "sum;");
11445   CHECK_EQ(28, result->Int32Value());
11446 
11447   // Check assigned smis in reverse order
11448   result = CompileRun("for (var i = 8; --i >= 0; ) {"
11449                       "  ext_array[i] = i;"
11450                       "}"
11451                       "var sum = 0;"
11452                       "for (var i = 0; i < 8; i++) {"
11453                       "  sum += ext_array[i];"
11454                       "}"
11455                       "sum;");
11456   CHECK_EQ(28, result->Int32Value());
11457 
11458   // Check pass through of assigned HeapNumbers
11459   result = CompileRun("var sum = 0;"
11460                       "for (var i = 0; i < 16; i+=2) {"
11461                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
11462                       "}"
11463                       "sum;");
11464   CHECK_EQ(-28, result->Int32Value());
11465 
11466   // Check assigned HeapNumbers
11467   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
11468                       "  ext_array[i] = (i * 0.5);"
11469                       "}"
11470                       "var sum = 0;"
11471                       "for (var i = 0; i < 16; i+=2) {"
11472                       "  sum += ext_array[i];"
11473                       "}"
11474                       "sum;");
11475   CHECK_EQ(28, result->Int32Value());
11476 
11477   // Check assigned HeapNumbers in reverse order
11478   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
11479                       "  ext_array[i] = (i * 0.5);"
11480                       "}"
11481                       "var sum = 0;"
11482                       "for (var i = 0; i < 16; i+=2) {"
11483                       "  sum += ext_array[i];"
11484                       "}"
11485                       "sum;");
11486   CHECK_EQ(28, result->Int32Value());
11487 
11488   i::ScopedVector<char> test_buf(1024);
11489 
11490   // Check legal boundary conditions.
11491   // The repeated loads and stores ensure the ICs are exercised.
11492   const char* boundary_program =
11493       "var res = 0;"
11494       "for (var i = 0; i < 16; i++) {"
11495       "  ext_array[i] = %lld;"
11496       "  if (i > 8) {"
11497       "    res = ext_array[i];"
11498       "  }"
11499       "}"
11500       "res;";
11501   i::OS::SNPrintF(test_buf,
11502                   boundary_program,
11503                   low);
11504   result = CompileRun(test_buf.start());
11505   CHECK_EQ(low, result->IntegerValue());
11506 
11507   i::OS::SNPrintF(test_buf,
11508                   boundary_program,
11509                   high);
11510   result = CompileRun(test_buf.start());
11511   CHECK_EQ(high, result->IntegerValue());
11512 
11513   // Check misprediction of type in IC.
11514   result = CompileRun("var tmp_array = ext_array;"
11515                       "var sum = 0;"
11516                       "for (var i = 0; i < 8; i++) {"
11517                       "  tmp_array[i] = i;"
11518                       "  sum += tmp_array[i];"
11519                       "  if (i == 4) {"
11520                       "    tmp_array = {};"
11521                       "  }"
11522                       "}"
11523                       "sum;");
11524   HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11525   CHECK_EQ(28, result->Int32Value());
11526 
11527   // Make sure out-of-range loads do not throw.
11528   i::OS::SNPrintF(test_buf,
11529                   "var caught_exception = false;"
11530                   "try {"
11531                   "  ext_array[%d];"
11532                   "} catch (e) {"
11533                   "  caught_exception = true;"
11534                   "}"
11535                   "caught_exception;",
11536                   kElementCount);
11537   result = CompileRun(test_buf.start());
11538   CHECK_EQ(false, result->BooleanValue());
11539 
11540   // Make sure out-of-range stores do not throw.
11541   i::OS::SNPrintF(test_buf,
11542                   "var caught_exception = false;"
11543                   "try {"
11544                   "  ext_array[%d] = 1;"
11545                   "} catch (e) {"
11546                   "  caught_exception = true;"
11547                   "}"
11548                   "caught_exception;",
11549                   kElementCount);
11550   result = CompileRun(test_buf.start());
11551   CHECK_EQ(false, result->BooleanValue());
11552 
11553   // Check other boundary conditions, values and operations.
11554   result = CompileRun("for (var i = 0; i < 8; i++) {"
11555                       "  ext_array[7] = undefined;"
11556                       "}"
11557                       "ext_array[7];");
11558   CHECK_EQ(0, result->Int32Value());
11559   CHECK_EQ(
11560       0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
11561 
11562   result = CompileRun("for (var i = 0; i < 8; i++) {"
11563                       "  ext_array[6] = '2.3';"
11564                       "}"
11565                       "ext_array[6];");
11566   CHECK_EQ(2, result->Int32Value());
11567   CHECK_EQ(
11568       2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
11569 
11570   if (array_type != v8::kExternalFloatArray) {
11571     // Though the specification doesn't state it, be explicit about
11572     // converting NaNs and +/-Infinity to zero.
11573     result = CompileRun("for (var i = 0; i < 8; i++) {"
11574                         "  ext_array[i] = 5;"
11575                         "}"
11576                         "for (var i = 0; i < 8; i++) {"
11577                         "  ext_array[i] = NaN;"
11578                         "}"
11579                         "ext_array[5];");
11580     CHECK_EQ(0, result->Int32Value());
11581     CHECK_EQ(0,
11582              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11583 
11584     result = CompileRun("for (var i = 0; i < 8; i++) {"
11585                         "  ext_array[i] = 5;"
11586                         "}"
11587                         "for (var i = 0; i < 8; i++) {"
11588                         "  ext_array[i] = Infinity;"
11589                         "}"
11590                         "ext_array[5];");
11591     int expected_value =
11592         (array_type == v8::kExternalPixelArray) ? 255 : 0;
11593     CHECK_EQ(expected_value, result->Int32Value());
11594     CHECK_EQ(expected_value,
11595              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11596 
11597     result = CompileRun("for (var i = 0; i < 8; i++) {"
11598                         "  ext_array[i] = 5;"
11599                         "}"
11600                         "for (var i = 0; i < 8; i++) {"
11601                         "  ext_array[i] = -Infinity;"
11602                         "}"
11603                         "ext_array[5];");
11604     CHECK_EQ(0, result->Int32Value());
11605     CHECK_EQ(0,
11606              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11607 
11608     // Check truncation behavior of integral arrays.
11609     const char* unsigned_data =
11610         "var source_data = [0.6, 10.6];"
11611         "var expected_results = [0, 10];";
11612     const char* signed_data =
11613         "var source_data = [0.6, 10.6, -0.6, -10.6];"
11614         "var expected_results = [0, 10, 0, -10];";
11615     const char* pixel_data =
11616         "var source_data = [0.6, 10.6];"
11617         "var expected_results = [1, 11];";
11618     bool is_unsigned =
11619         (array_type == v8::kExternalUnsignedByteArray ||
11620          array_type == v8::kExternalUnsignedShortArray ||
11621          array_type == v8::kExternalUnsignedIntArray);
11622     bool is_pixel_data = array_type == v8::kExternalPixelArray;
11623 
11624     i::OS::SNPrintF(test_buf,
11625                     "%s"
11626                     "var all_passed = true;"
11627                     "for (var i = 0; i < source_data.length; i++) {"
11628                     "  for (var j = 0; j < 8; j++) {"
11629                     "    ext_array[j] = source_data[i];"
11630                     "  }"
11631                     "  all_passed = all_passed &&"
11632                     "               (ext_array[5] == expected_results[i]);"
11633                     "}"
11634                     "all_passed;",
11635                     (is_unsigned ?
11636                          unsigned_data :
11637                          (is_pixel_data ? pixel_data : signed_data)));
11638     result = CompileRun(test_buf.start());
11639     CHECK_EQ(true, result->BooleanValue());
11640   }
11641 
11642   // Test crankshaft external array loads
11643   for (int i = 0; i < kElementCount; i++) {
11644     array->set(i, static_cast<ElementType>(i));
11645   }
11646   result = CompileRun("function ee_load_test_func(sum) {"
11647                       " for (var i = 0; i < 40; ++i)"
11648                       "   sum += ext_array[i];"
11649                       " return sum;"
11650                       "}"
11651                       "sum=0;"
11652                       "for (var i=0;i<10000;++i) {"
11653                       "  sum=ee_load_test_func(sum);"
11654                       "}"
11655                       "sum;");
11656   CHECK_EQ(7800000, result->Int32Value());
11657 
11658   // Test crankshaft external array stores
11659   result = CompileRun("function ee_store_test_func(sum) {"
11660                       " for (var i = 0; i < 40; ++i)"
11661                       "   sum += ext_array[i] = i;"
11662                       " return sum;"
11663                       "}"
11664                       "sum=0;"
11665                       "for (var i=0;i<10000;++i) {"
11666                       "  sum=ee_store_test_func(sum);"
11667                       "}"
11668                       "sum;");
11669   CHECK_EQ(7800000, result->Int32Value());
11670 
11671   for (int i = 0; i < kElementCount; i++) {
11672     array->set(i, static_cast<ElementType>(i));
11673   }
11674   // Test complex assignments
11675   result = CompileRun("function ee_op_test_complex_func(sum) {"
11676                       " for (var i = 0; i < 40; ++i) {"
11677                       "   sum += (ext_array[i] += 1);"
11678                       "   sum += (ext_array[i] -= 1);"
11679                       " } "
11680                       " return sum;"
11681                       "}"
11682                       "sum=0;"
11683                       "for (var i=0;i<10000;++i) {"
11684                       "  sum=ee_op_test_complex_func(sum);"
11685                       "}"
11686                       "sum;");
11687   CHECK_EQ(16000000, result->Int32Value());
11688 
11689   // Test count operations
11690   result = CompileRun("function ee_op_test_count_func(sum) {"
11691                       " for (var i = 0; i < 40; ++i) {"
11692                       "   sum += (++ext_array[i]);"
11693                       "   sum += (--ext_array[i]);"
11694                       " } "
11695                       " return sum;"
11696                       "}"
11697                       "sum=0;"
11698                       "for (var i=0;i<10000;++i) {"
11699                       "  sum=ee_op_test_count_func(sum);"
11700                       "}"
11701                       "sum;");
11702   CHECK_EQ(16000000, result->Int32Value());
11703 
11704   result = CompileRun("ext_array[3] = 33;"
11705                       "delete ext_array[3];"
11706                       "ext_array[3];");
11707   CHECK_EQ(33, result->Int32Value());
11708 
11709   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
11710                       "ext_array[2] = 12; ext_array[3] = 13;"
11711                       "ext_array.__defineGetter__('2',"
11712                       "function() { return 120; });"
11713                       "ext_array[2];");
11714   CHECK_EQ(12, result->Int32Value());
11715 
11716   result = CompileRun("var js_array = new Array(40);"
11717                       "js_array[0] = 77;"
11718                       "js_array;");
11719   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11720 
11721   result = CompileRun("ext_array[1] = 23;"
11722                       "ext_array.__proto__ = [];"
11723                       "js_array.__proto__ = ext_array;"
11724                       "js_array.concat(ext_array);");
11725   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11726   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11727 
11728   result = CompileRun("ext_array[1] = 23;");
11729   CHECK_EQ(23, result->Int32Value());
11730 
11731   // Test more complex manipulations which cause eax to contain values
11732   // that won't be completely overwritten by loads from the arrays.
11733   // This catches bugs in the instructions used for the KeyedLoadIC
11734   // for byte and word types.
11735   {
11736     const int kXSize = 300;
11737     const int kYSize = 300;
11738     const int kLargeElementCount = kXSize * kYSize * 4;
11739     ElementType* large_array_data =
11740         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
11741     i::Handle<ExternalArrayClass> large_array =
11742         i::Handle<ExternalArrayClass>::cast(
11743             FACTORY->NewExternalArray(kLargeElementCount,
11744                                          array_type,
11745                                          array_data));
11746     v8::Handle<v8::Object> large_obj = v8::Object::New();
11747     // Set the elements to be the external array.
11748     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
11749                                                        array_type,
11750                                                        kLargeElementCount);
11751     context->Global()->Set(v8_str("large_array"), large_obj);
11752     // Initialize contents of a few rows.
11753     for (int x = 0; x < 300; x++) {
11754       int row = 0;
11755       int offset = row * 300 * 4;
11756       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11757       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11758       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11759       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11760       row = 150;
11761       offset = row * 300 * 4;
11762       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11763       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11764       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11765       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11766       row = 298;
11767       offset = row * 300 * 4;
11768       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11769       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11770       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11771       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11772     }
11773     // The goal of the code below is to make "offset" large enough
11774     // that the computation of the index (which goes into eax) has
11775     // high bits set which will not be overwritten by a byte or short
11776     // load.
11777     result = CompileRun("var failed = false;"
11778                         "var offset = 0;"
11779                         "for (var i = 0; i < 300; i++) {"
11780                         "  if (large_array[4 * i] != 127 ||"
11781                         "      large_array[4 * i + 1] != 0 ||"
11782                         "      large_array[4 * i + 2] != 0 ||"
11783                         "      large_array[4 * i + 3] != 127) {"
11784                         "    failed = true;"
11785                         "  }"
11786                         "}"
11787                         "offset = 150 * 300 * 4;"
11788                         "for (var i = 0; i < 300; i++) {"
11789                         "  if (large_array[offset + 4 * i] != 127 ||"
11790                         "      large_array[offset + 4 * i + 1] != 0 ||"
11791                         "      large_array[offset + 4 * i + 2] != 0 ||"
11792                         "      large_array[offset + 4 * i + 3] != 127) {"
11793                         "    failed = true;"
11794                         "  }"
11795                         "}"
11796                         "offset = 298 * 300 * 4;"
11797                         "for (var i = 0; i < 300; i++) {"
11798                         "  if (large_array[offset + 4 * i] != 127 ||"
11799                         "      large_array[offset + 4 * i + 1] != 0 ||"
11800                         "      large_array[offset + 4 * i + 2] != 0 ||"
11801                         "      large_array[offset + 4 * i + 3] != 127) {"
11802                         "    failed = true;"
11803                         "  }"
11804                         "}"
11805                         "!failed;");
11806     CHECK_EQ(true, result->BooleanValue());
11807     free(large_array_data);
11808   }
11809 
11810   // The "" property descriptor is overloaded to store information about
11811   // the external array. Ensure that setting and accessing the "" property
11812   // works (it should overwrite the information cached about the external
11813   // array in the DescriptorArray) in various situations.
11814   result = CompileRun("ext_array[''] = 23; ext_array['']");
11815   CHECK_EQ(23, result->Int32Value());
11816 
11817   // Property "" set after the external array is associated with the object.
11818   {
11819     v8::Handle<v8::Object> obj2 = v8::Object::New();
11820     obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
11821     obj2->Set(v8_str(""), v8::Int32::New(1503));
11822     // Set the elements to be the external array.
11823     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11824                                                   array_type,
11825                                                   kElementCount);
11826     context->Global()->Set(v8_str("ext_array"), obj2);
11827     result = CompileRun("ext_array['']");
11828     CHECK_EQ(1503, result->Int32Value());
11829   }
11830 
11831   // Property "" set after the external array is associated with the object.
11832   {
11833     v8::Handle<v8::Object> obj2 = v8::Object::New();
11834     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11835     // Set the elements to be the external array.
11836     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11837                                                   array_type,
11838                                                   kElementCount);
11839     obj2->Set(v8_str(""), v8::Int32::New(1503));
11840     context->Global()->Set(v8_str("ext_array"), obj2);
11841     result = CompileRun("ext_array['']");
11842     CHECK_EQ(1503, result->Int32Value());
11843   }
11844 
11845   // Should reuse the map from previous test.
11846   {
11847     v8::Handle<v8::Object> obj2 = v8::Object::New();
11848     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11849     // Set the elements to be the external array. Should re-use the map
11850     // from previous test.
11851     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11852                                                   array_type,
11853                                                   kElementCount);
11854     context->Global()->Set(v8_str("ext_array"), obj2);
11855     result = CompileRun("ext_array['']");
11856   }
11857 
11858   // Property "" is a constant function that shouldn't not be interfered with
11859   // when an external array is set.
11860   {
11861     v8::Handle<v8::Object> obj2 = v8::Object::New();
11862     // Start
11863     obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11864 
11865     // Add a constant function to an object.
11866     context->Global()->Set(v8_str("ext_array"), obj2);
11867     result = CompileRun("ext_array[''] = function() {return 1503;};"
11868                         "ext_array['']();");
11869 
11870     // Add an external array transition to the same map that
11871     // has the constant transition.
11872     v8::Handle<v8::Object> obj3 = v8::Object::New();
11873     obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11874     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11875                                                   array_type,
11876                                                   kElementCount);
11877     context->Global()->Set(v8_str("ext_array"), obj3);
11878   }
11879 
11880   // If a external array transition is in the map, it should get clobbered
11881   // by a constant function.
11882   {
11883     // Add an external array transition.
11884     v8::Handle<v8::Object> obj3 = v8::Object::New();
11885     obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11886     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11887                                                   array_type,
11888                                                   kElementCount);
11889 
11890     // Add a constant function to the same map that just got an external array
11891     // transition.
11892     v8::Handle<v8::Object> obj2 = v8::Object::New();
11893     obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11894     context->Global()->Set(v8_str("ext_array"), obj2);
11895     result = CompileRun("ext_array[''] = function() {return 1503;};"
11896                         "ext_array['']();");
11897   }
11898 
11899   free(array_data);
11900 }
11901 
11902 
THREADED_TEST(ExternalByteArray)11903 THREADED_TEST(ExternalByteArray) {
11904   ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
11905       v8::kExternalByteArray,
11906       -128,
11907       127);
11908 }
11909 
11910 
THREADED_TEST(ExternalUnsignedByteArray)11911 THREADED_TEST(ExternalUnsignedByteArray) {
11912   ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
11913       v8::kExternalUnsignedByteArray,
11914       0,
11915       255);
11916 }
11917 
11918 
THREADED_TEST(ExternalPixelArray)11919 THREADED_TEST(ExternalPixelArray) {
11920   ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
11921       v8::kExternalPixelArray,
11922       0,
11923       255);
11924 }
11925 
11926 
THREADED_TEST(ExternalShortArray)11927 THREADED_TEST(ExternalShortArray) {
11928   ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
11929       v8::kExternalShortArray,
11930       -32768,
11931       32767);
11932 }
11933 
11934 
THREADED_TEST(ExternalUnsignedShortArray)11935 THREADED_TEST(ExternalUnsignedShortArray) {
11936   ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
11937       v8::kExternalUnsignedShortArray,
11938       0,
11939       65535);
11940 }
11941 
11942 
THREADED_TEST(ExternalIntArray)11943 THREADED_TEST(ExternalIntArray) {
11944   ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
11945       v8::kExternalIntArray,
11946       INT_MIN,   // -2147483648
11947       INT_MAX);  //  2147483647
11948 }
11949 
11950 
THREADED_TEST(ExternalUnsignedIntArray)11951 THREADED_TEST(ExternalUnsignedIntArray) {
11952   ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
11953       v8::kExternalUnsignedIntArray,
11954       0,
11955       UINT_MAX);  // 4294967295
11956 }
11957 
11958 
THREADED_TEST(ExternalFloatArray)11959 THREADED_TEST(ExternalFloatArray) {
11960   ExternalArrayTestHelper<i::ExternalFloatArray, float>(
11961       v8::kExternalFloatArray,
11962       -500,
11963       500);
11964 }
11965 
11966 
THREADED_TEST(ExternalArrays)11967 THREADED_TEST(ExternalArrays) {
11968   TestExternalByteArray();
11969   TestExternalUnsignedByteArray();
11970   TestExternalShortArray();
11971   TestExternalUnsignedShortArray();
11972   TestExternalIntArray();
11973   TestExternalUnsignedIntArray();
11974   TestExternalFloatArray();
11975 }
11976 
11977 
ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type)11978 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
11979   v8::HandleScope scope;
11980   LocalContext context;
11981   for (int size = 0; size < 100; size += 10) {
11982     int element_size = ExternalArrayElementSize(array_type);
11983     void* external_data = malloc(size * element_size);
11984     v8::Handle<v8::Object> obj = v8::Object::New();
11985     obj->SetIndexedPropertiesToExternalArrayData(
11986         external_data, array_type, size);
11987     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
11988     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
11989     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
11990     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
11991     free(external_data);
11992   }
11993 }
11994 
11995 
THREADED_TEST(ExternalArrayInfo)11996 THREADED_TEST(ExternalArrayInfo) {
11997   ExternalArrayInfoTestHelper(v8::kExternalByteArray);
11998   ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
11999   ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12000   ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12001   ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12002   ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12003   ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
12004   ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
12005 }
12006 
12007 
THREADED_TEST(ScriptContextDependence)12008 THREADED_TEST(ScriptContextDependence) {
12009   v8::HandleScope scope;
12010   LocalContext c1;
12011   const char *source = "foo";
12012   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12013   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12014   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12015   CHECK_EQ(dep->Run()->Int32Value(), 100);
12016   CHECK_EQ(indep->Run()->Int32Value(), 100);
12017   LocalContext c2;
12018   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12019   CHECK_EQ(dep->Run()->Int32Value(), 100);
12020   CHECK_EQ(indep->Run()->Int32Value(), 101);
12021 }
12022 
12023 
THREADED_TEST(StackTrace)12024 THREADED_TEST(StackTrace) {
12025   v8::HandleScope scope;
12026   LocalContext context;
12027   v8::TryCatch try_catch;
12028   const char *source = "function foo() { FAIL.FAIL; }; foo();";
12029   v8::Handle<v8::String> src = v8::String::New(source);
12030   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12031   v8::Script::New(src, origin)->Run();
12032   CHECK(try_catch.HasCaught());
12033   v8::String::Utf8Value stack(try_catch.StackTrace());
12034   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12035 }
12036 
12037 
12038 // Checks that a StackFrame has certain expected values.
checkStackFrame(const char * expected_script_name,const char * expected_func_name,int expected_line_number,int expected_column,bool is_eval,bool is_constructor,v8::Handle<v8::StackFrame> frame)12039 void checkStackFrame(const char* expected_script_name,
12040     const char* expected_func_name, int expected_line_number,
12041     int expected_column, bool is_eval, bool is_constructor,
12042     v8::Handle<v8::StackFrame> frame) {
12043   v8::HandleScope scope;
12044   v8::String::Utf8Value func_name(frame->GetFunctionName());
12045   v8::String::Utf8Value script_name(frame->GetScriptName());
12046   if (*script_name == NULL) {
12047     // The situation where there is no associated script, like for evals.
12048     CHECK(expected_script_name == NULL);
12049   } else {
12050     CHECK(strstr(*script_name, expected_script_name) != NULL);
12051   }
12052   CHECK(strstr(*func_name, expected_func_name) != NULL);
12053   CHECK_EQ(expected_line_number, frame->GetLineNumber());
12054   CHECK_EQ(expected_column, frame->GetColumn());
12055   CHECK_EQ(is_eval, frame->IsEval());
12056   CHECK_EQ(is_constructor, frame->IsConstructor());
12057 }
12058 
12059 
AnalyzeStackInNativeCode(const v8::Arguments & args)12060 v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12061   v8::HandleScope scope;
12062   const char* origin = "capture-stack-trace-test";
12063   const int kOverviewTest = 1;
12064   const int kDetailedTest = 2;
12065 
12066   ASSERT(args.Length() == 1);
12067 
12068   int testGroup = args[0]->Int32Value();
12069   if (testGroup == kOverviewTest) {
12070     v8::Handle<v8::StackTrace> stackTrace =
12071         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12072     CHECK_EQ(4, stackTrace->GetFrameCount());
12073     checkStackFrame(origin, "bar", 2, 10, false, false,
12074                     stackTrace->GetFrame(0));
12075     checkStackFrame(origin, "foo", 6, 3, false, false,
12076                     stackTrace->GetFrame(1));
12077     checkStackFrame(NULL, "", 1, 1, false, false,
12078                     stackTrace->GetFrame(2));
12079     // The last frame is an anonymous function that has the initial call.
12080     checkStackFrame(origin, "", 8, 7, false, false,
12081                     stackTrace->GetFrame(3));
12082 
12083     CHECK(stackTrace->AsArray()->IsArray());
12084   } else if (testGroup == kDetailedTest) {
12085     v8::Handle<v8::StackTrace> stackTrace =
12086         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12087     CHECK_EQ(4, stackTrace->GetFrameCount());
12088     checkStackFrame(origin, "bat", 4, 22, false, false,
12089                     stackTrace->GetFrame(0));
12090     checkStackFrame(origin, "baz", 8, 3, false, true,
12091                     stackTrace->GetFrame(1));
12092 #ifdef ENABLE_DEBUGGER_SUPPORT
12093     bool is_eval = true;
12094 #else  // ENABLE_DEBUGGER_SUPPORT
12095     bool is_eval = false;
12096 #endif  // ENABLE_DEBUGGER_SUPPORT
12097 
12098     checkStackFrame(NULL, "", 1, 1, is_eval, false,
12099                     stackTrace->GetFrame(2));
12100     // The last frame is an anonymous function that has the initial call to foo.
12101     checkStackFrame(origin, "", 10, 1, false, false,
12102                     stackTrace->GetFrame(3));
12103 
12104     CHECK(stackTrace->AsArray()->IsArray());
12105   }
12106   return v8::Undefined();
12107 }
12108 
12109 
12110 // Tests the C++ StackTrace API.
12111 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12112 // THREADED_TEST(CaptureStackTrace) {
TEST(CaptureStackTrace)12113 TEST(CaptureStackTrace) {
12114   v8::HandleScope scope;
12115   v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12116   Local<ObjectTemplate> templ = ObjectTemplate::New();
12117   templ->Set(v8_str("AnalyzeStackInNativeCode"),
12118              v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12119   LocalContext context(0, templ);
12120 
12121   // Test getting OVERVIEW information. Should ignore information that is not
12122   // script name, function name, line number, and column offset.
12123   const char *overview_source =
12124     "function bar() {\n"
12125     "  var y; AnalyzeStackInNativeCode(1);\n"
12126     "}\n"
12127     "function foo() {\n"
12128     "\n"
12129     "  bar();\n"
12130     "}\n"
12131     "var x;eval('new foo();');";
12132   v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12133   v8::Handle<Value> overview_result =
12134       v8::Script::New(overview_src, origin)->Run();
12135   ASSERT(!overview_result.IsEmpty());
12136   ASSERT(overview_result->IsObject());
12137 
12138   // Test getting DETAILED information.
12139   const char *detailed_source =
12140     "function bat() {AnalyzeStackInNativeCode(2);\n"
12141     "}\n"
12142     "\n"
12143     "function baz() {\n"
12144     "  bat();\n"
12145     "}\n"
12146     "eval('new baz();');";
12147   v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12148   // Make the script using a non-zero line and column offset.
12149   v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12150   v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12151   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12152   v8::Handle<v8::Script> detailed_script(
12153       v8::Script::New(detailed_src, &detailed_origin));
12154   v8::Handle<Value> detailed_result = detailed_script->Run();
12155   ASSERT(!detailed_result.IsEmpty());
12156   ASSERT(detailed_result->IsObject());
12157 }
12158 
12159 
StackTraceForUncaughtExceptionListener(v8::Handle<v8::Message> message,v8::Handle<Value>)12160 static void StackTraceForUncaughtExceptionListener(
12161     v8::Handle<v8::Message> message,
12162     v8::Handle<Value>) {
12163   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12164   CHECK_EQ(2, stack_trace->GetFrameCount());
12165   checkStackFrame("origin", "foo", 2, 3, false, false,
12166                   stack_trace->GetFrame(0));
12167   checkStackFrame("origin", "bar", 5, 3, false, false,
12168                   stack_trace->GetFrame(1));
12169 }
12170 
TEST(CaptureStackTraceForUncaughtException)12171 TEST(CaptureStackTraceForUncaughtException) {
12172   report_count = 0;
12173   v8::HandleScope scope;
12174   LocalContext env;
12175   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12176   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12177 
12178   Script::Compile(v8_str("function foo() {\n"
12179                          "  throw 1;\n"
12180                          "};\n"
12181                          "function bar() {\n"
12182                          "  foo();\n"
12183                          "};"),
12184                   v8_str("origin"))->Run();
12185   v8::Local<v8::Object> global = env->Global();
12186   Local<Value> trouble = global->Get(v8_str("bar"));
12187   CHECK(trouble->IsFunction());
12188   Function::Cast(*trouble)->Call(global, 0, NULL);
12189   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12190   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12191 }
12192 
12193 
TEST(CaptureStackTraceForUncaughtExceptionAndSetters)12194 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12195   v8::HandleScope scope;
12196   LocalContext env;
12197   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12198                                                     1024,
12199                                                     v8::StackTrace::kDetailed);
12200 
12201   CompileRun(
12202       "var setters = ['column', 'lineNumber', 'scriptName',\n"
12203       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12204       "    'isConstructor'];\n"
12205       "for (var i = 0; i < setters.length; i++) {\n"
12206       "  var prop = setters[i];\n"
12207       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12208       "}\n");
12209   CompileRun("throw 'exception';");
12210   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12211 }
12212 
12213 
AnalyzeStackOfEvalWithSourceURL(const v8::Arguments & args)12214 v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12215   v8::HandleScope scope;
12216   v8::Handle<v8::StackTrace> stackTrace =
12217       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12218   CHECK_EQ(5, stackTrace->GetFrameCount());
12219   v8::Handle<v8::String> url = v8_str("eval_url");
12220   for (int i = 0; i < 3; i++) {
12221     v8::Handle<v8::String> name =
12222         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12223     CHECK(!name.IsEmpty());
12224     CHECK_EQ(url, name);
12225   }
12226   return v8::Undefined();
12227 }
12228 
12229 
TEST(SourceURLInStackTrace)12230 TEST(SourceURLInStackTrace) {
12231   v8::HandleScope scope;
12232   Local<ObjectTemplate> templ = ObjectTemplate::New();
12233   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12234              v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12235   LocalContext context(0, templ);
12236 
12237   const char *source =
12238     "function outer() {\n"
12239     "function bar() {\n"
12240     "  AnalyzeStackOfEvalWithSourceURL();\n"
12241     "}\n"
12242     "function foo() {\n"
12243     "\n"
12244     "  bar();\n"
12245     "}\n"
12246     "foo();\n"
12247     "}\n"
12248     "eval('(' + outer +')()//@ sourceURL=eval_url');";
12249   CHECK(CompileRun(source)->IsUndefined());
12250 }
12251 
12252 
12253 // Test that idle notification can be handled and eventually returns true.
THREADED_TEST(IdleNotification)12254 THREADED_TEST(IdleNotification) {
12255   bool rv = false;
12256   for (int i = 0; i < 100; i++) {
12257     rv = v8::V8::IdleNotification();
12258     if (rv)
12259       break;
12260   }
12261   CHECK(rv == true);
12262 }
12263 
12264 
12265 static uint32_t* stack_limit;
12266 
GetStackLimitCallback(const v8::Arguments & args)12267 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
12268   stack_limit = reinterpret_cast<uint32_t*>(
12269       i::Isolate::Current()->stack_guard()->real_climit());
12270   return v8::Undefined();
12271 }
12272 
12273 
12274 // Uses the address of a local variable to determine the stack top now.
12275 // Given a size, returns an address that is that far from the current
12276 // top of stack.
ComputeStackLimit(uint32_t size)12277 static uint32_t* ComputeStackLimit(uint32_t size) {
12278   uint32_t* answer = &size - (size / sizeof(size));
12279   // If the size is very large and the stack is very near the bottom of
12280   // memory then the calculation above may wrap around and give an address
12281   // that is above the (downwards-growing) stack.  In that case we return
12282   // a very low address.
12283   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12284   return answer;
12285 }
12286 
12287 
TEST(SetResourceConstraints)12288 TEST(SetResourceConstraints) {
12289   static const int K = 1024;
12290   uint32_t* set_limit = ComputeStackLimit(128 * K);
12291 
12292   // Set stack limit.
12293   v8::ResourceConstraints constraints;
12294   constraints.set_stack_limit(set_limit);
12295   CHECK(v8::SetResourceConstraints(&constraints));
12296 
12297   // Execute a script.
12298   v8::HandleScope scope;
12299   LocalContext env;
12300   Local<v8::FunctionTemplate> fun_templ =
12301       v8::FunctionTemplate::New(GetStackLimitCallback);
12302   Local<Function> fun = fun_templ->GetFunction();
12303   env->Global()->Set(v8_str("get_stack_limit"), fun);
12304   CompileRun("get_stack_limit();");
12305 
12306   CHECK(stack_limit == set_limit);
12307 }
12308 
12309 
TEST(SetResourceConstraintsInThread)12310 TEST(SetResourceConstraintsInThread) {
12311   uint32_t* set_limit;
12312   {
12313     v8::Locker locker;
12314     static const int K = 1024;
12315     set_limit = ComputeStackLimit(128 * K);
12316 
12317     // Set stack limit.
12318     v8::ResourceConstraints constraints;
12319     constraints.set_stack_limit(set_limit);
12320     CHECK(v8::SetResourceConstraints(&constraints));
12321 
12322     // Execute a script.
12323     v8::HandleScope scope;
12324     LocalContext env;
12325     Local<v8::FunctionTemplate> fun_templ =
12326         v8::FunctionTemplate::New(GetStackLimitCallback);
12327     Local<Function> fun = fun_templ->GetFunction();
12328     env->Global()->Set(v8_str("get_stack_limit"), fun);
12329     CompileRun("get_stack_limit();");
12330 
12331     CHECK(stack_limit == set_limit);
12332   }
12333   {
12334     v8::Locker locker;
12335     CHECK(stack_limit == set_limit);
12336   }
12337 }
12338 
12339 
THREADED_TEST(GetHeapStatistics)12340 THREADED_TEST(GetHeapStatistics) {
12341   v8::HandleScope scope;
12342   LocalContext c1;
12343   v8::HeapStatistics heap_statistics;
12344   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
12345   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
12346   v8::V8::GetHeapStatistics(&heap_statistics);
12347   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
12348   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
12349 }
12350 
12351 
DoubleFromBits(uint64_t value)12352 static double DoubleFromBits(uint64_t value) {
12353   double target;
12354   memcpy(&target, &value, sizeof(target));
12355   return target;
12356 }
12357 
12358 
DoubleToBits(double value)12359 static uint64_t DoubleToBits(double value) {
12360   uint64_t target;
12361   memcpy(&target, &value, sizeof(target));
12362   return target;
12363 }
12364 
12365 
DoubleToDateTime(double input)12366 static double DoubleToDateTime(double input) {
12367   double date_limit = 864e13;
12368   if (IsNaN(input) || input < -date_limit || input > date_limit) {
12369     return i::OS::nan_value();
12370   }
12371   return (input < 0) ? -(floor(-input)) : floor(input);
12372 }
12373 
12374 // We don't have a consistent way to write 64-bit constants syntactically, so we
12375 // split them into two 32-bit constants and combine them programmatically.
DoubleFromBits(uint32_t high_bits,uint32_t low_bits)12376 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
12377   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
12378 }
12379 
12380 
THREADED_TEST(QuietSignalingNaNs)12381 THREADED_TEST(QuietSignalingNaNs) {
12382   v8::HandleScope scope;
12383   LocalContext context;
12384   v8::TryCatch try_catch;
12385 
12386   // Special double values.
12387   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
12388   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
12389   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
12390   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
12391   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
12392   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
12393   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
12394 
12395   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
12396   // on either side of the epoch.
12397   double date_limit = 864e13;
12398 
12399   double test_values[] = {
12400       snan,
12401       qnan,
12402       infinity,
12403       max_normal,
12404       date_limit + 1,
12405       date_limit,
12406       min_normal,
12407       max_denormal,
12408       min_denormal,
12409       0,
12410       -0,
12411       -min_denormal,
12412       -max_denormal,
12413       -min_normal,
12414       -date_limit,
12415       -date_limit - 1,
12416       -max_normal,
12417       -infinity,
12418       -qnan,
12419       -snan
12420   };
12421   int num_test_values = 20;
12422 
12423   for (int i = 0; i < num_test_values; i++) {
12424     double test_value = test_values[i];
12425 
12426     // Check that Number::New preserves non-NaNs and quiets SNaNs.
12427     v8::Handle<v8::Value> number = v8::Number::New(test_value);
12428     double stored_number = number->NumberValue();
12429     if (!IsNaN(test_value)) {
12430       CHECK_EQ(test_value, stored_number);
12431     } else {
12432       uint64_t stored_bits = DoubleToBits(stored_number);
12433       // Check if quiet nan (bits 51..62 all set).
12434       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12435     }
12436 
12437     // Check that Date::New preserves non-NaNs in the date range and
12438     // quiets SNaNs.
12439     v8::Handle<v8::Value> date = v8::Date::New(test_value);
12440     double expected_stored_date = DoubleToDateTime(test_value);
12441     double stored_date = date->NumberValue();
12442     if (!IsNaN(expected_stored_date)) {
12443       CHECK_EQ(expected_stored_date, stored_date);
12444     } else {
12445       uint64_t stored_bits = DoubleToBits(stored_date);
12446       // Check if quiet nan (bits 51..62 all set).
12447       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12448     }
12449   }
12450 }
12451 
12452 
SpaghettiIncident(const v8::Arguments & args)12453 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
12454   v8::HandleScope scope;
12455   v8::TryCatch tc;
12456   v8::Handle<v8::String> str = args[0]->ToString();
12457   if (tc.HasCaught())
12458     return tc.ReThrow();
12459   return v8::Undefined();
12460 }
12461 
12462 
12463 // Test that an exception can be propagated down through a spaghetti
12464 // stack using ReThrow.
THREADED_TEST(SpaghettiStackReThrow)12465 THREADED_TEST(SpaghettiStackReThrow) {
12466   v8::HandleScope scope;
12467   LocalContext context;
12468   context->Global()->Set(
12469       v8::String::New("s"),
12470       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
12471   v8::TryCatch try_catch;
12472   CompileRun(
12473       "var i = 0;"
12474       "var o = {"
12475       "  toString: function () {"
12476       "    if (i == 10) {"
12477       "      throw 'Hey!';"
12478       "    } else {"
12479       "      i++;"
12480       "      return s(o);"
12481       "    }"
12482       "  }"
12483       "};"
12484       "s(o);");
12485   CHECK(try_catch.HasCaught());
12486   v8::String::Utf8Value value(try_catch.Exception());
12487   CHECK_EQ(0, strcmp(*value, "Hey!"));
12488 }
12489 
12490 
TEST(Regress528)12491 TEST(Regress528) {
12492   v8::V8::Initialize();
12493 
12494   v8::HandleScope scope;
12495   v8::Persistent<Context> context;
12496   v8::Persistent<Context> other_context;
12497   int gc_count;
12498 
12499   // Create a context used to keep the code from aging in the compilation
12500   // cache.
12501   other_context = Context::New();
12502 
12503   // Context-dependent context data creates reference from the compilation
12504   // cache to the global object.
12505   const char* source_simple = "1";
12506   context = Context::New();
12507   {
12508     v8::HandleScope scope;
12509 
12510     context->Enter();
12511     Local<v8::String> obj = v8::String::New("");
12512     context->SetData(obj);
12513     CompileRun(source_simple);
12514     context->Exit();
12515   }
12516   context.Dispose();
12517   for (gc_count = 1; gc_count < 10; gc_count++) {
12518     other_context->Enter();
12519     CompileRun(source_simple);
12520     other_context->Exit();
12521     HEAP->CollectAllGarbage(false);
12522     if (GetGlobalObjectsCount() == 1) break;
12523   }
12524   CHECK_GE(2, gc_count);
12525   CHECK_EQ(1, GetGlobalObjectsCount());
12526 
12527   // Eval in a function creates reference from the compilation cache to the
12528   // global object.
12529   const char* source_eval = "function f(){eval('1')}; f()";
12530   context = Context::New();
12531   {
12532     v8::HandleScope scope;
12533 
12534     context->Enter();
12535     CompileRun(source_eval);
12536     context->Exit();
12537   }
12538   context.Dispose();
12539   for (gc_count = 1; gc_count < 10; gc_count++) {
12540     other_context->Enter();
12541     CompileRun(source_eval);
12542     other_context->Exit();
12543     HEAP->CollectAllGarbage(false);
12544     if (GetGlobalObjectsCount() == 1) break;
12545   }
12546   CHECK_GE(2, gc_count);
12547   CHECK_EQ(1, GetGlobalObjectsCount());
12548 
12549   // Looking up the line number for an exception creates reference from the
12550   // compilation cache to the global object.
12551   const char* source_exception = "function f(){throw 1;} f()";
12552   context = Context::New();
12553   {
12554     v8::HandleScope scope;
12555 
12556     context->Enter();
12557     v8::TryCatch try_catch;
12558     CompileRun(source_exception);
12559     CHECK(try_catch.HasCaught());
12560     v8::Handle<v8::Message> message = try_catch.Message();
12561     CHECK(!message.IsEmpty());
12562     CHECK_EQ(1, message->GetLineNumber());
12563     context->Exit();
12564   }
12565   context.Dispose();
12566   for (gc_count = 1; gc_count < 10; gc_count++) {
12567     other_context->Enter();
12568     CompileRun(source_exception);
12569     other_context->Exit();
12570     HEAP->CollectAllGarbage(false);
12571     if (GetGlobalObjectsCount() == 1) break;
12572   }
12573   CHECK_GE(2, gc_count);
12574   CHECK_EQ(1, GetGlobalObjectsCount());
12575 
12576   other_context.Dispose();
12577 }
12578 
12579 
THREADED_TEST(ScriptOrigin)12580 THREADED_TEST(ScriptOrigin) {
12581   v8::HandleScope scope;
12582   LocalContext env;
12583   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12584   v8::Handle<v8::String> script = v8::String::New(
12585       "function f() {}\n\nfunction g() {}");
12586   v8::Script::Compile(script, &origin)->Run();
12587   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12588       env->Global()->Get(v8::String::New("f")));
12589   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12590       env->Global()->Get(v8::String::New("g")));
12591 
12592   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
12593   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
12594   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
12595 
12596   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
12597   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
12598   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
12599 }
12600 
12601 
THREADED_TEST(ScriptLineNumber)12602 THREADED_TEST(ScriptLineNumber) {
12603   v8::HandleScope scope;
12604   LocalContext env;
12605   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12606   v8::Handle<v8::String> script = v8::String::New(
12607       "function f() {}\n\nfunction g() {}");
12608   v8::Script::Compile(script, &origin)->Run();
12609   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12610       env->Global()->Get(v8::String::New("f")));
12611   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12612       env->Global()->Get(v8::String::New("g")));
12613   CHECK_EQ(0, f->GetScriptLineNumber());
12614   CHECK_EQ(2, g->GetScriptLineNumber());
12615 }
12616 
12617 
GetterWhichReturns42(Local<String> name,const AccessorInfo & info)12618 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
12619                                               const AccessorInfo& info) {
12620   return v8_num(42);
12621 }
12622 
12623 
SetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const AccessorInfo & info)12624 static void SetterWhichSetsYOnThisTo23(Local<String> name,
12625                                        Local<Value> value,
12626                                        const AccessorInfo& info) {
12627   info.This()->Set(v8_str("y"), v8_num(23));
12628 }
12629 
12630 
TEST(SetterOnConstructorPrototype)12631 TEST(SetterOnConstructorPrototype) {
12632   v8::HandleScope scope;
12633   Local<ObjectTemplate> templ = ObjectTemplate::New();
12634   templ->SetAccessor(v8_str("x"),
12635                      GetterWhichReturns42,
12636                      SetterWhichSetsYOnThisTo23);
12637   LocalContext context;
12638   context->Global()->Set(v8_str("P"), templ->NewInstance());
12639   CompileRun("function C1() {"
12640              "  this.x = 23;"
12641              "};"
12642              "C1.prototype = P;"
12643              "function C2() {"
12644              "  this.x = 23"
12645              "};"
12646              "C2.prototype = { };"
12647              "C2.prototype.__proto__ = P;");
12648 
12649   v8::Local<v8::Script> script;
12650   script = v8::Script::Compile(v8_str("new C1();"));
12651   for (int i = 0; i < 10; i++) {
12652     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12653     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12654     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12655   }
12656 
12657   script = v8::Script::Compile(v8_str("new C2();"));
12658   for (int i = 0; i < 10; i++) {
12659     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12660     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
12661     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
12662   }
12663 }
12664 
12665 
NamedPropertyGetterWhichReturns42(Local<String> name,const AccessorInfo & info)12666 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
12667     Local<String> name, const AccessorInfo& info) {
12668   return v8_num(42);
12669 }
12670 
12671 
NamedPropertySetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const AccessorInfo & info)12672 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
12673     Local<String> name, Local<Value> value, const AccessorInfo& info) {
12674   if (name->Equals(v8_str("x"))) {
12675     info.This()->Set(v8_str("y"), v8_num(23));
12676   }
12677   return v8::Handle<Value>();
12678 }
12679 
12680 
THREADED_TEST(InterceptorOnConstructorPrototype)12681 THREADED_TEST(InterceptorOnConstructorPrototype) {
12682   v8::HandleScope scope;
12683   Local<ObjectTemplate> templ = ObjectTemplate::New();
12684   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
12685                                  NamedPropertySetterWhichSetsYOnThisTo23);
12686   LocalContext context;
12687   context->Global()->Set(v8_str("P"), templ->NewInstance());
12688   CompileRun("function C1() {"
12689              "  this.x = 23;"
12690              "};"
12691              "C1.prototype = P;"
12692              "function C2() {"
12693              "  this.x = 23"
12694              "};"
12695              "C2.prototype = { };"
12696              "C2.prototype.__proto__ = P;");
12697 
12698   v8::Local<v8::Script> script;
12699   script = v8::Script::Compile(v8_str("new C1();"));
12700   for (int i = 0; i < 10; i++) {
12701     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12702     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12703     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12704   }
12705 
12706   script = v8::Script::Compile(v8_str("new C2();"));
12707   for (int i = 0; i < 10; i++) {
12708     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12709     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
12710     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
12711   }
12712 }
12713 
12714 
TEST(Bug618)12715 TEST(Bug618) {
12716   const char* source = "function C1() {"
12717                        "  this.x = 23;"
12718                        "};"
12719                        "C1.prototype = P;";
12720 
12721   v8::HandleScope scope;
12722   LocalContext context;
12723   v8::Local<v8::Script> script;
12724 
12725   // Use a simple object as prototype.
12726   v8::Local<v8::Object> prototype = v8::Object::New();
12727   prototype->Set(v8_str("y"), v8_num(42));
12728   context->Global()->Set(v8_str("P"), prototype);
12729 
12730   // This compile will add the code to the compilation cache.
12731   CompileRun(source);
12732 
12733   script = v8::Script::Compile(v8_str("new C1();"));
12734   // Allow enough iterations for the inobject slack tracking logic
12735   // to finalize instance size and install the fast construct stub.
12736   for (int i = 0; i < 256; i++) {
12737     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12738     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12739     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12740   }
12741 
12742   // Use an API object with accessors as prototype.
12743   Local<ObjectTemplate> templ = ObjectTemplate::New();
12744   templ->SetAccessor(v8_str("x"),
12745                      GetterWhichReturns42,
12746                      SetterWhichSetsYOnThisTo23);
12747   context->Global()->Set(v8_str("P"), templ->NewInstance());
12748 
12749   // This compile will get the code from the compilation cache.
12750   CompileRun(source);
12751 
12752   script = v8::Script::Compile(v8_str("new C1();"));
12753   for (int i = 0; i < 10; i++) {
12754     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12755     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12756     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12757   }
12758 }
12759 
12760 int prologue_call_count = 0;
12761 int epilogue_call_count = 0;
12762 int prologue_call_count_second = 0;
12763 int epilogue_call_count_second = 0;
12764 
PrologueCallback(v8::GCType,v8::GCCallbackFlags)12765 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
12766   ++prologue_call_count;
12767 }
12768 
EpilogueCallback(v8::GCType,v8::GCCallbackFlags)12769 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
12770   ++epilogue_call_count;
12771 }
12772 
PrologueCallbackSecond(v8::GCType,v8::GCCallbackFlags)12773 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12774   ++prologue_call_count_second;
12775 }
12776 
EpilogueCallbackSecond(v8::GCType,v8::GCCallbackFlags)12777 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12778   ++epilogue_call_count_second;
12779 }
12780 
TEST(GCCallbacks)12781 TEST(GCCallbacks) {
12782   LocalContext context;
12783 
12784   v8::V8::AddGCPrologueCallback(PrologueCallback);
12785   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
12786   CHECK_EQ(0, prologue_call_count);
12787   CHECK_EQ(0, epilogue_call_count);
12788   HEAP->CollectAllGarbage(false);
12789   CHECK_EQ(1, prologue_call_count);
12790   CHECK_EQ(1, epilogue_call_count);
12791   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
12792   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
12793   HEAP->CollectAllGarbage(false);
12794   CHECK_EQ(2, prologue_call_count);
12795   CHECK_EQ(2, epilogue_call_count);
12796   CHECK_EQ(1, prologue_call_count_second);
12797   CHECK_EQ(1, epilogue_call_count_second);
12798   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
12799   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
12800   HEAP->CollectAllGarbage(false);
12801   CHECK_EQ(2, prologue_call_count);
12802   CHECK_EQ(2, epilogue_call_count);
12803   CHECK_EQ(2, prologue_call_count_second);
12804   CHECK_EQ(2, epilogue_call_count_second);
12805   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
12806   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
12807   HEAP->CollectAllGarbage(false);
12808   CHECK_EQ(2, prologue_call_count);
12809   CHECK_EQ(2, epilogue_call_count);
12810   CHECK_EQ(2, prologue_call_count_second);
12811   CHECK_EQ(2, epilogue_call_count_second);
12812 }
12813 
12814 
THREADED_TEST(AddToJSFunctionResultCache)12815 THREADED_TEST(AddToJSFunctionResultCache) {
12816   i::FLAG_allow_natives_syntax = true;
12817   v8::HandleScope scope;
12818 
12819   LocalContext context;
12820 
12821   const char* code =
12822       "(function() {"
12823       "  var key0 = 'a';"
12824       "  var key1 = 'b';"
12825       "  var r0 = %_GetFromCache(0, key0);"
12826       "  var r1 = %_GetFromCache(0, key1);"
12827       "  var r0_ = %_GetFromCache(0, key0);"
12828       "  if (r0 !== r0_)"
12829       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
12830       "  var r1_ = %_GetFromCache(0, key1);"
12831       "  if (r1 !== r1_)"
12832       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
12833       "  return 'PASSED';"
12834       "})()";
12835   HEAP->ClearJSFunctionResultCaches();
12836   ExpectString(code, "PASSED");
12837 }
12838 
12839 
12840 static const int k0CacheSize = 16;
12841 
THREADED_TEST(FillJSFunctionResultCache)12842 THREADED_TEST(FillJSFunctionResultCache) {
12843   i::FLAG_allow_natives_syntax = true;
12844   v8::HandleScope scope;
12845 
12846   LocalContext context;
12847 
12848   const char* code =
12849       "(function() {"
12850       "  var k = 'a';"
12851       "  var r = %_GetFromCache(0, k);"
12852       "  for (var i = 0; i < 16; i++) {"
12853       "    %_GetFromCache(0, 'a' + i);"
12854       "  };"
12855       "  if (r === %_GetFromCache(0, k))"
12856       "    return 'FAILED: k0CacheSize is too small';"
12857       "  return 'PASSED';"
12858       "})()";
12859   HEAP->ClearJSFunctionResultCaches();
12860   ExpectString(code, "PASSED");
12861 }
12862 
12863 
THREADED_TEST(RoundRobinGetFromCache)12864 THREADED_TEST(RoundRobinGetFromCache) {
12865   i::FLAG_allow_natives_syntax = true;
12866   v8::HandleScope scope;
12867 
12868   LocalContext context;
12869 
12870   const char* code =
12871       "(function() {"
12872       "  var keys = [];"
12873       "  for (var i = 0; i < 16; i++) keys.push(i);"
12874       "  var values = [];"
12875       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12876       "  for (var i = 0; i < 16; i++) {"
12877       "    var v = %_GetFromCache(0, keys[i]);"
12878       "    if (v !== values[i])"
12879       "      return 'Wrong value for ' + "
12880       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
12881       "  };"
12882       "  return 'PASSED';"
12883       "})()";
12884   HEAP->ClearJSFunctionResultCaches();
12885   ExpectString(code, "PASSED");
12886 }
12887 
12888 
THREADED_TEST(ReverseGetFromCache)12889 THREADED_TEST(ReverseGetFromCache) {
12890   i::FLAG_allow_natives_syntax = true;
12891   v8::HandleScope scope;
12892 
12893   LocalContext context;
12894 
12895   const char* code =
12896       "(function() {"
12897       "  var keys = [];"
12898       "  for (var i = 0; i < 16; i++) keys.push(i);"
12899       "  var values = [];"
12900       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12901       "  for (var i = 15; i >= 16; i--) {"
12902       "    var v = %_GetFromCache(0, keys[i]);"
12903       "    if (v !== values[i])"
12904       "      return 'Wrong value for ' + "
12905       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
12906       "  };"
12907       "  return 'PASSED';"
12908       "})()";
12909   HEAP->ClearJSFunctionResultCaches();
12910   ExpectString(code, "PASSED");
12911 }
12912 
12913 
THREADED_TEST(TestEviction)12914 THREADED_TEST(TestEviction) {
12915   i::FLAG_allow_natives_syntax = true;
12916   v8::HandleScope scope;
12917 
12918   LocalContext context;
12919 
12920   const char* code =
12921       "(function() {"
12922       "  for (var i = 0; i < 2*16; i++) {"
12923       "    %_GetFromCache(0, 'a' + i);"
12924       "  };"
12925       "  return 'PASSED';"
12926       "})()";
12927   HEAP->ClearJSFunctionResultCaches();
12928   ExpectString(code, "PASSED");
12929 }
12930 
12931 
THREADED_TEST(TwoByteStringInAsciiCons)12932 THREADED_TEST(TwoByteStringInAsciiCons) {
12933   // See Chromium issue 47824.
12934   v8::HandleScope scope;
12935 
12936   LocalContext context;
12937   const char* init_code =
12938       "var str1 = 'abelspendabel';"
12939       "var str2 = str1 + str1 + str1;"
12940       "str2;";
12941   Local<Value> result = CompileRun(init_code);
12942 
12943   CHECK(result->IsString());
12944   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
12945   int length = string->length();
12946   CHECK(string->IsAsciiRepresentation());
12947 
12948   FlattenString(string);
12949   i::Handle<i::String> flat_string = FlattenGetString(string);
12950 
12951   CHECK(string->IsAsciiRepresentation());
12952   CHECK(flat_string->IsAsciiRepresentation());
12953 
12954   // Create external resource.
12955   uint16_t* uc16_buffer = new uint16_t[length + 1];
12956 
12957   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
12958   uc16_buffer[length] = 0;
12959 
12960   TestResource resource(uc16_buffer);
12961 
12962   flat_string->MakeExternal(&resource);
12963 
12964   CHECK(flat_string->IsTwoByteRepresentation());
12965 
12966   // At this point, we should have a Cons string which is flat and ASCII,
12967   // with a first half that is a two-byte string (although it only contains
12968   // ASCII characters). This is a valid sequence of steps, and it can happen
12969   // in real pages.
12970 
12971   CHECK(string->IsAsciiRepresentation());
12972   i::ConsString* cons = i::ConsString::cast(*string);
12973   CHECK_EQ(0, cons->second()->length());
12974   CHECK(cons->first()->IsTwoByteRepresentation());
12975 
12976   // Check that some string operations work.
12977 
12978   // Atom RegExp.
12979   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
12980   CHECK_EQ(6, reresult->Int32Value());
12981 
12982   // Nonatom RegExp.
12983   reresult = CompileRun("str2.match(/abe./g).length;");
12984   CHECK_EQ(6, reresult->Int32Value());
12985 
12986   reresult = CompileRun("str2.search(/bel/g);");
12987   CHECK_EQ(1, reresult->Int32Value());
12988 
12989   reresult = CompileRun("str2.search(/be./g);");
12990   CHECK_EQ(1, reresult->Int32Value());
12991 
12992   ExpectTrue("/bel/g.test(str2);");
12993 
12994   ExpectTrue("/be./g.test(str2);");
12995 
12996   reresult = CompileRun("/bel/g.exec(str2);");
12997   CHECK(!reresult->IsNull());
12998 
12999   reresult = CompileRun("/be./g.exec(str2);");
13000   CHECK(!reresult->IsNull());
13001 
13002   ExpectString("str2.substring(2, 10);", "elspenda");
13003 
13004   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13005 
13006   ExpectString("str2.charAt(2);", "e");
13007 
13008   reresult = CompileRun("str2.charCodeAt(2);");
13009   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13010 }
13011 
13012 
13013 // Failed access check callback that performs a GC on each invocation.
FailedAccessCheckCallbackGC(Local<v8::Object> target,v8::AccessType type,Local<v8::Value> data)13014 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13015                                  v8::AccessType type,
13016                                  Local<v8::Value> data) {
13017   HEAP->CollectAllGarbage(true);
13018 }
13019 
13020 
TEST(GCInFailedAccessCheckCallback)13021 TEST(GCInFailedAccessCheckCallback) {
13022   // Install a failed access check callback that performs a GC on each
13023   // invocation. Then force the callback to be called from va
13024 
13025   v8::V8::Initialize();
13026   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13027 
13028   v8::HandleScope scope;
13029 
13030   // Create an ObjectTemplate for global objects and install access
13031   // check callbacks that will block access.
13032   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13033   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13034                                            IndexedGetAccessBlocker,
13035                                            v8::Handle<v8::Value>(),
13036                                            false);
13037 
13038   // Create a context and set an x property on it's global object.
13039   LocalContext context0(NULL, global_template);
13040   context0->Global()->Set(v8_str("x"), v8_num(42));
13041   v8::Handle<v8::Object> global0 = context0->Global();
13042 
13043   // Create a context with a different security token so that the
13044   // failed access check callback will be called on each access.
13045   LocalContext context1(NULL, global_template);
13046   context1->Global()->Set(v8_str("other"), global0);
13047 
13048   // Get property with failed access check.
13049   ExpectUndefined("other.x");
13050 
13051   // Get element with failed access check.
13052   ExpectUndefined("other[0]");
13053 
13054   // Set property with failed access check.
13055   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13056   CHECK(result->IsObject());
13057 
13058   // Set element with failed access check.
13059   result = CompileRun("other[0] = new Object()");
13060   CHECK(result->IsObject());
13061 
13062   // Get property attribute with failed access check.
13063   ExpectFalse("\'x\' in other");
13064 
13065   // Get property attribute for element with failed access check.
13066   ExpectFalse("0 in other");
13067 
13068   // Delete property.
13069   ExpectFalse("delete other.x");
13070 
13071   // Delete element.
13072   CHECK_EQ(false, global0->Delete(0));
13073 
13074   // DefineAccessor.
13075   CHECK_EQ(false,
13076            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13077 
13078   // Define JavaScript accessor.
13079   ExpectUndefined("Object.prototype.__defineGetter__.call("
13080                   "    other, \'x\', function() { return 42; })");
13081 
13082   // LookupAccessor.
13083   ExpectUndefined("Object.prototype.__lookupGetter__.call("
13084                   "    other, \'x\')");
13085 
13086   // HasLocalElement.
13087   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13088 
13089   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13090   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13091   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13092 
13093   // Reset the failed access check callback so it does not influence
13094   // the other tests.
13095   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13096 }
13097 
TEST(DefaultIsolateGetCurrent)13098 TEST(DefaultIsolateGetCurrent) {
13099   CHECK(v8::Isolate::GetCurrent() != NULL);
13100   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13101   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13102   printf("*** %s\n", "DefaultIsolateGetCurrent success");
13103 }
13104 
TEST(IsolateNewDispose)13105 TEST(IsolateNewDispose) {
13106   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13107   v8::Isolate* isolate = v8::Isolate::New();
13108   CHECK(isolate != NULL);
13109   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13110   CHECK(current_isolate != isolate);
13111   CHECK(current_isolate == v8::Isolate::GetCurrent());
13112 
13113   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13114   last_location = last_message = NULL;
13115   isolate->Dispose();
13116   CHECK_EQ(last_location, NULL);
13117   CHECK_EQ(last_message, NULL);
13118 }
13119 
TEST(IsolateEnterExitDefault)13120 TEST(IsolateEnterExitDefault) {
13121   v8::HandleScope scope;
13122   LocalContext context;
13123   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13124   CHECK(current_isolate != NULL);  // Default isolate.
13125   ExpectString("'hello'", "hello");
13126   current_isolate->Enter();
13127   ExpectString("'still working'", "still working");
13128   current_isolate->Exit();
13129   ExpectString("'still working 2'", "still working 2");
13130   current_isolate->Exit();
13131   // Default isolate is always, well, 'default current'.
13132   CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13133   // Still working since default isolate is auto-entering any thread
13134   // that has no isolate and attempts to execute V8 APIs.
13135   ExpectString("'still working 3'", "still working 3");
13136 }
13137 
TEST(DisposeDefaultIsolate)13138 TEST(DisposeDefaultIsolate) {
13139   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13140 
13141   // Run some V8 code to trigger default isolate to become 'current'.
13142   v8::HandleScope scope;
13143   LocalContext context;
13144   ExpectString("'run some V8'", "run some V8");
13145 
13146   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13147   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13148   last_location = last_message = NULL;
13149   isolate->Dispose();
13150   // It is not possible to dispose default isolate via Isolate API.
13151   CHECK_NE(last_location, NULL);
13152   CHECK_NE(last_message, NULL);
13153 }
13154 
TEST(RunDefaultAndAnotherIsolate)13155 TEST(RunDefaultAndAnotherIsolate) {
13156   v8::HandleScope scope;
13157   LocalContext context;
13158 
13159   // Enter new isolate.
13160   v8::Isolate* isolate = v8::Isolate::New();
13161   CHECK(isolate);
13162   isolate->Enter();
13163   { // Need this block because subsequent Exit() will deallocate Heap,
13164     // so we need all scope objects to be deconstructed when it happens.
13165     v8::HandleScope scope_new;
13166     LocalContext context_new;
13167 
13168     // Run something in new isolate.
13169     CompileRun("var foo = 153;");
13170     ExpectTrue("function f() { return foo == 153; }; f()");
13171   }
13172   isolate->Exit();
13173 
13174   // This runs automatically in default isolate.
13175   // Variables in another isolate should be not available.
13176   ExpectTrue("function f() {"
13177              "  try {"
13178              "    foo;"
13179              "    return false;"
13180              "  } catch(e) {"
13181              "    return true;"
13182              "  }"
13183              "};"
13184              "var bar = 371;"
13185              "f()");
13186 
13187   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13188   last_location = last_message = NULL;
13189   isolate->Dispose();
13190   CHECK_EQ(last_location, NULL);
13191   CHECK_EQ(last_message, NULL);
13192 
13193   // Check that default isolate still runs.
13194   ExpectTrue("function f() { return bar == 371; }; f()");
13195 }
13196 
TEST(DisposeIsolateWhenInUse)13197 TEST(DisposeIsolateWhenInUse) {
13198   v8::Isolate* isolate = v8::Isolate::New();
13199   CHECK(isolate);
13200   isolate->Enter();
13201   v8::HandleScope scope;
13202   LocalContext context;
13203   // Run something in this isolate.
13204   ExpectTrue("true");
13205   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13206   last_location = last_message = NULL;
13207   // Still entered, should fail.
13208   isolate->Dispose();
13209   CHECK_NE(last_location, NULL);
13210   CHECK_NE(last_message, NULL);
13211 }
13212 
TEST(RunTwoIsolatesOnSingleThread)13213 TEST(RunTwoIsolatesOnSingleThread) {
13214   // Run isolate 1.
13215   v8::Isolate* isolate1 = v8::Isolate::New();
13216   isolate1->Enter();
13217   v8::Persistent<v8::Context> context1 = v8::Context::New();
13218 
13219   {
13220     v8::Context::Scope cscope(context1);
13221     v8::HandleScope scope;
13222     // Run something in new isolate.
13223     CompileRun("var foo = 'isolate 1';");
13224     ExpectString("function f() { return foo; }; f()", "isolate 1");
13225   }
13226 
13227   // Run isolate 2.
13228   v8::Isolate* isolate2 = v8::Isolate::New();
13229   v8::Persistent<v8::Context> context2;
13230 
13231   {
13232     v8::Isolate::Scope iscope(isolate2);
13233     context2 = v8::Context::New();
13234     v8::Context::Scope cscope(context2);
13235     v8::HandleScope scope;
13236 
13237     // Run something in new isolate.
13238     CompileRun("var foo = 'isolate 2';");
13239     ExpectString("function f() { return foo; }; f()", "isolate 2");
13240   }
13241 
13242   {
13243     v8::Context::Scope cscope(context1);
13244     v8::HandleScope scope;
13245     // Now again in isolate 1
13246     ExpectString("function f() { return foo; }; f()", "isolate 1");
13247   }
13248 
13249   isolate1->Exit();
13250 
13251   // Run some stuff in default isolate.
13252   v8::Persistent<v8::Context> context_default = v8::Context::New();
13253 
13254   {
13255     v8::Context::Scope cscope(context_default);
13256     v8::HandleScope scope;
13257     // Variables in other isolates should be not available, verify there
13258     // is an exception.
13259     ExpectTrue("function f() {"
13260                "  try {"
13261                "    foo;"
13262                "    return false;"
13263                "  } catch(e) {"
13264                "    return true;"
13265                "  }"
13266                "};"
13267                "var isDefaultIsolate = true;"
13268                "f()");
13269   }
13270 
13271   isolate1->Enter();
13272 
13273   {
13274     v8::Isolate::Scope iscope(isolate2);
13275     v8::Context::Scope cscope(context2);
13276     v8::HandleScope scope;
13277     ExpectString("function f() { return foo; }; f()", "isolate 2");
13278   }
13279 
13280   {
13281     v8::Context::Scope cscope(context1);
13282     v8::HandleScope scope;
13283     ExpectString("function f() { return foo; }; f()", "isolate 1");
13284   }
13285 
13286   {
13287     v8::Isolate::Scope iscope(isolate2);
13288     context2.Dispose();
13289   }
13290 
13291   context1.Dispose();
13292   isolate1->Exit();
13293 
13294   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13295   last_location = last_message = NULL;
13296 
13297   isolate1->Dispose();
13298   CHECK_EQ(last_location, NULL);
13299   CHECK_EQ(last_message, NULL);
13300 
13301   isolate2->Dispose();
13302   CHECK_EQ(last_location, NULL);
13303   CHECK_EQ(last_message, NULL);
13304 
13305   // Check that default isolate still runs.
13306   {
13307     v8::Context::Scope cscope(context_default);
13308     v8::HandleScope scope;
13309     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
13310   }
13311 }
13312 
CalcFibonacci(v8::Isolate * isolate,int limit)13313 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
13314   v8::Isolate::Scope isolate_scope(isolate);
13315   v8::HandleScope scope;
13316   LocalContext context;
13317   i::ScopedVector<char> code(1024);
13318   i::OS::SNPrintF(code, "function fib(n) {"
13319                         "  if (n <= 2) return 1;"
13320                         "  return fib(n-1) + fib(n-2);"
13321                         "}"
13322                         "fib(%d)", limit);
13323   Local<Value> value = CompileRun(code.start());
13324   CHECK(value->IsNumber());
13325   return static_cast<int>(value->NumberValue());
13326 }
13327 
13328 class IsolateThread : public v8::internal::Thread {
13329  public:
IsolateThread(v8::Isolate * isolate,int fib_limit)13330   explicit IsolateThread(v8::Isolate* isolate, int fib_limit)
13331       : Thread(NULL, "IsolateThread"),
13332         isolate_(isolate),
13333         fib_limit_(fib_limit),
13334         result_(0) { }
13335 
Run()13336   void Run() {
13337     result_ = CalcFibonacci(isolate_, fib_limit_);
13338   }
13339 
result()13340   int result() { return result_; }
13341 
13342  private:
13343   v8::Isolate* isolate_;
13344   int fib_limit_;
13345   int result_;
13346 };
13347 
TEST(MultipleIsolatesOnIndividualThreads)13348 TEST(MultipleIsolatesOnIndividualThreads) {
13349   v8::Isolate* isolate1 = v8::Isolate::New();
13350   v8::Isolate* isolate2 = v8::Isolate::New();
13351 
13352   IsolateThread thread1(isolate1, 21);
13353   IsolateThread thread2(isolate2, 12);
13354 
13355   // Compute some fibonacci numbers on 3 threads in 3 isolates.
13356   thread1.Start();
13357   thread2.Start();
13358 
13359   int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
13360   int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
13361 
13362   thread1.Join();
13363   thread2.Join();
13364 
13365   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
13366   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
13367   CHECK_EQ(result1, 10946);
13368   CHECK_EQ(result2, 144);
13369   CHECK_EQ(result1, thread1.result());
13370   CHECK_EQ(result2, thread2.result());
13371 
13372   isolate1->Dispose();
13373   isolate2->Dispose();
13374 }
13375 
13376 
13377 class InitDefaultIsolateThread : public v8::internal::Thread {
13378  public:
13379   enum TestCase {
13380     IgnoreOOM,
13381     SetResourceConstraints,
13382     SetFatalHandler,
13383     SetCounterFunction,
13384     SetCreateHistogramFunction,
13385     SetAddHistogramSampleFunction
13386   };
13387 
InitDefaultIsolateThread(TestCase testCase)13388   explicit InitDefaultIsolateThread(TestCase testCase)
13389       : Thread(NULL, "InitDefaultIsolateThread"),
13390         testCase_(testCase),
13391         result_(false) { }
13392 
Run()13393   void Run() {
13394     switch (testCase_) {
13395     case IgnoreOOM:
13396       v8::V8::IgnoreOutOfMemoryException();
13397       break;
13398 
13399     case SetResourceConstraints: {
13400       static const int K = 1024;
13401       v8::ResourceConstraints constraints;
13402       constraints.set_max_young_space_size(256 * K);
13403       constraints.set_max_old_space_size(4 * K * K);
13404       v8::SetResourceConstraints(&constraints);
13405       break;
13406     }
13407 
13408     case SetFatalHandler:
13409       v8::V8::SetFatalErrorHandler(NULL);
13410       break;
13411 
13412     case SetCounterFunction:
13413       v8::V8::SetCounterFunction(NULL);
13414       break;
13415 
13416     case SetCreateHistogramFunction:
13417       v8::V8::SetCreateHistogramFunction(NULL);
13418       break;
13419 
13420     case SetAddHistogramSampleFunction:
13421       v8::V8::SetAddHistogramSampleFunction(NULL);
13422       break;
13423     }
13424     result_ = true;
13425   }
13426 
result()13427   bool result() { return result_; }
13428 
13429  private:
13430   TestCase testCase_;
13431   bool result_;
13432 };
13433 
13434 
InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase)13435 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
13436   InitDefaultIsolateThread thread(testCase);
13437   thread.Start();
13438   thread.Join();
13439   CHECK_EQ(thread.result(), true);
13440 }
13441 
TEST(InitializeDefaultIsolateOnSecondaryThread1)13442 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
13443   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
13444 }
13445 
TEST(InitializeDefaultIsolateOnSecondaryThread2)13446 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
13447   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
13448 }
13449 
TEST(InitializeDefaultIsolateOnSecondaryThread3)13450 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
13451   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
13452 }
13453 
TEST(InitializeDefaultIsolateOnSecondaryThread4)13454 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
13455   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
13456 }
13457 
TEST(InitializeDefaultIsolateOnSecondaryThread5)13458 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
13459   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
13460 }
13461 
TEST(InitializeDefaultIsolateOnSecondaryThread6)13462 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
13463   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
13464 }
13465 
13466 
TEST(StringCheckMultipleContexts)13467 TEST(StringCheckMultipleContexts) {
13468   const char* code =
13469       "(function() { return \"a\".charAt(0); })()";
13470 
13471   {
13472     // Run the code twice in the first context to initialize the call IC.
13473     v8::HandleScope scope;
13474     LocalContext context1;
13475     ExpectString(code, "a");
13476     ExpectString(code, "a");
13477   }
13478 
13479   {
13480     // Change the String.prototype in the second context and check
13481     // that the right function gets called.
13482     v8::HandleScope scope;
13483     LocalContext context2;
13484     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
13485     ExpectString(code, "not a");
13486   }
13487 }
13488 
13489 
TEST(NumberCheckMultipleContexts)13490 TEST(NumberCheckMultipleContexts) {
13491   const char* code =
13492       "(function() { return (42).toString(); })()";
13493 
13494   {
13495     // Run the code twice in the first context to initialize the call IC.
13496     v8::HandleScope scope;
13497     LocalContext context1;
13498     ExpectString(code, "42");
13499     ExpectString(code, "42");
13500   }
13501 
13502   {
13503     // Change the Number.prototype in the second context and check
13504     // that the right function gets called.
13505     v8::HandleScope scope;
13506     LocalContext context2;
13507     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
13508     ExpectString(code, "not 42");
13509   }
13510 }
13511 
13512 
TEST(BooleanCheckMultipleContexts)13513 TEST(BooleanCheckMultipleContexts) {
13514   const char* code =
13515       "(function() { return true.toString(); })()";
13516 
13517   {
13518     // Run the code twice in the first context to initialize the call IC.
13519     v8::HandleScope scope;
13520     LocalContext context1;
13521     ExpectString(code, "true");
13522     ExpectString(code, "true");
13523   }
13524 
13525   {
13526     // Change the Boolean.prototype in the second context and check
13527     // that the right function gets called.
13528     v8::HandleScope scope;
13529     LocalContext context2;
13530     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
13531     ExpectString(code, "");
13532   }
13533 }
13534 
13535 
TEST(DontDeleteCellLoadIC)13536 TEST(DontDeleteCellLoadIC) {
13537   const char* function_code =
13538       "function readCell() { while (true) { return cell; } }";
13539 
13540   {
13541     // Run the code twice in the first context to initialize the load
13542     // IC for a don't delete cell.
13543     v8::HandleScope scope;
13544     LocalContext context1;
13545     CompileRun("var cell = \"first\";");
13546     ExpectBoolean("delete cell", false);
13547     CompileRun(function_code);
13548     ExpectString("readCell()", "first");
13549     ExpectString("readCell()", "first");
13550   }
13551 
13552   {
13553     // Use a deletable cell in the second context.
13554     v8::HandleScope scope;
13555     LocalContext context2;
13556     CompileRun("cell = \"second\";");
13557     CompileRun(function_code);
13558     ExpectString("readCell()", "second");
13559     ExpectBoolean("delete cell", true);
13560     ExpectString("(function() {"
13561                  "  try {"
13562                  "    return readCell();"
13563                  "  } catch(e) {"
13564                  "    return e.toString();"
13565                  "  }"
13566                  "})()",
13567                  "ReferenceError: cell is not defined");
13568     CompileRun("cell = \"new_second\";");
13569     HEAP->CollectAllGarbage(true);
13570     ExpectString("readCell()", "new_second");
13571     ExpectString("readCell()", "new_second");
13572   }
13573 }
13574 
13575 
TEST(DontDeleteCellLoadICForceDelete)13576 TEST(DontDeleteCellLoadICForceDelete) {
13577   const char* function_code =
13578       "function readCell() { while (true) { return cell; } }";
13579 
13580   // Run the code twice to initialize the load IC for a don't delete
13581   // cell.
13582   v8::HandleScope scope;
13583   LocalContext context;
13584   CompileRun("var cell = \"value\";");
13585   ExpectBoolean("delete cell", false);
13586   CompileRun(function_code);
13587   ExpectString("readCell()", "value");
13588   ExpectString("readCell()", "value");
13589 
13590   // Delete the cell using the API and check the inlined code works
13591   // correctly.
13592   CHECK(context->Global()->ForceDelete(v8_str("cell")));
13593   ExpectString("(function() {"
13594                "  try {"
13595                "    return readCell();"
13596                "  } catch(e) {"
13597                "    return e.toString();"
13598                "  }"
13599                "})()",
13600                "ReferenceError: cell is not defined");
13601 }
13602 
13603 
TEST(DontDeleteCellLoadICAPI)13604 TEST(DontDeleteCellLoadICAPI) {
13605   const char* function_code =
13606       "function readCell() { while (true) { return cell; } }";
13607 
13608   // Run the code twice to initialize the load IC for a don't delete
13609   // cell created using the API.
13610   v8::HandleScope scope;
13611   LocalContext context;
13612   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
13613   ExpectBoolean("delete cell", false);
13614   CompileRun(function_code);
13615   ExpectString("readCell()", "value");
13616   ExpectString("readCell()", "value");
13617 
13618   // Delete the cell using the API and check the inlined code works
13619   // correctly.
13620   CHECK(context->Global()->ForceDelete(v8_str("cell")));
13621   ExpectString("(function() {"
13622                "  try {"
13623                "    return readCell();"
13624                "  } catch(e) {"
13625                "    return e.toString();"
13626                "  }"
13627                "})()",
13628                "ReferenceError: cell is not defined");
13629 }
13630 
13631 
TEST(GlobalLoadICGC)13632 TEST(GlobalLoadICGC) {
13633   const char* function_code =
13634       "function readCell() { while (true) { return cell; } }";
13635 
13636   // Check inline load code for a don't delete cell is cleared during
13637   // GC.
13638   {
13639     v8::HandleScope scope;
13640     LocalContext context;
13641     CompileRun("var cell = \"value\";");
13642     ExpectBoolean("delete cell", false);
13643     CompileRun(function_code);
13644     ExpectString("readCell()", "value");
13645     ExpectString("readCell()", "value");
13646   }
13647   {
13648     v8::HandleScope scope;
13649     LocalContext context2;
13650     // Hold the code object in the second context.
13651     CompileRun(function_code);
13652     CheckSurvivingGlobalObjectsCount(1);
13653   }
13654 
13655   // Check inline load code for a deletable cell is cleared during GC.
13656   {
13657     v8::HandleScope scope;
13658     LocalContext context;
13659     CompileRun("cell = \"value\";");
13660     CompileRun(function_code);
13661     ExpectString("readCell()", "value");
13662     ExpectString("readCell()", "value");
13663   }
13664   {
13665     v8::HandleScope scope;
13666     LocalContext context2;
13667     // Hold the code object in the second context.
13668     CompileRun(function_code);
13669     CheckSurvivingGlobalObjectsCount(1);
13670   }
13671 }
13672 
13673 
TEST(RegExp)13674 TEST(RegExp) {
13675   v8::HandleScope scope;
13676   LocalContext context;
13677 
13678   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
13679   CHECK(re->IsRegExp());
13680   CHECK(re->GetSource()->Equals(v8_str("foo")));
13681   CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13682 
13683   re = v8::RegExp::New(v8_str("bar"),
13684                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13685                                                       v8::RegExp::kGlobal));
13686   CHECK(re->IsRegExp());
13687   CHECK(re->GetSource()->Equals(v8_str("bar")));
13688   CHECK_EQ(static_cast<int>(re->GetFlags()),
13689            v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
13690 
13691   re = v8::RegExp::New(v8_str("baz"),
13692                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13693                                                       v8::RegExp::kMultiline));
13694   CHECK(re->IsRegExp());
13695   CHECK(re->GetSource()->Equals(v8_str("baz")));
13696   CHECK_EQ(static_cast<int>(re->GetFlags()),
13697            v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13698 
13699   re = CompileRun("/quux/").As<v8::RegExp>();
13700   CHECK(re->IsRegExp());
13701   CHECK(re->GetSource()->Equals(v8_str("quux")));
13702   CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13703 
13704   re = CompileRun("/quux/gm").As<v8::RegExp>();
13705   CHECK(re->IsRegExp());
13706   CHECK(re->GetSource()->Equals(v8_str("quux")));
13707   CHECK_EQ(static_cast<int>(re->GetFlags()),
13708            v8::RegExp::kGlobal | v8::RegExp::kMultiline);
13709 
13710   // Override the RegExp constructor and check the API constructor
13711   // still works.
13712   CompileRun("RegExp = function() {}");
13713 
13714   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
13715   CHECK(re->IsRegExp());
13716   CHECK(re->GetSource()->Equals(v8_str("foobar")));
13717   CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13718 
13719   re = v8::RegExp::New(v8_str("foobarbaz"),
13720                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13721                                                       v8::RegExp::kMultiline));
13722   CHECK(re->IsRegExp());
13723   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
13724   CHECK_EQ(static_cast<int>(re->GetFlags()),
13725            v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13726 
13727   context->Global()->Set(v8_str("re"), re);
13728   ExpectTrue("re.test('FoobarbaZ')");
13729 
13730   v8::TryCatch try_catch;
13731   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
13732   CHECK(re.IsEmpty());
13733   CHECK(try_catch.HasCaught());
13734   context->Global()->Set(v8_str("ex"), try_catch.Exception());
13735   ExpectTrue("ex instanceof SyntaxError");
13736 }
13737 
13738 
THREADED_TEST(Equals)13739 THREADED_TEST(Equals) {
13740   v8::HandleScope handleScope;
13741   LocalContext localContext;
13742 
13743   v8::Handle<v8::Object> globalProxy = localContext->Global();
13744   v8::Handle<Value> global = globalProxy->GetPrototype();
13745 
13746   CHECK(global->StrictEquals(global));
13747   CHECK(!global->StrictEquals(globalProxy));
13748   CHECK(!globalProxy->StrictEquals(global));
13749   CHECK(globalProxy->StrictEquals(globalProxy));
13750 
13751   CHECK(global->Equals(global));
13752   CHECK(!global->Equals(globalProxy));
13753   CHECK(!globalProxy->Equals(global));
13754   CHECK(globalProxy->Equals(globalProxy));
13755 }
13756 
13757 
Getter(v8::Local<v8::String> property,const v8::AccessorInfo & info)13758 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
13759                                     const v8::AccessorInfo& info ) {
13760   return v8_str("42!");
13761 }
13762 
13763 
Enumerator(const v8::AccessorInfo & info)13764 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
13765   v8::Handle<v8::Array> result = v8::Array::New();
13766   result->Set(0, v8_str("universalAnswer"));
13767   return result;
13768 }
13769 
13770 
TEST(NamedEnumeratorAndForIn)13771 TEST(NamedEnumeratorAndForIn) {
13772   v8::HandleScope handle_scope;
13773   LocalContext context;
13774   v8::Context::Scope context_scope(context.local());
13775 
13776   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
13777   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
13778   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
13779   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
13780         "var result = []; for (var k in o) result.push(k); result"));
13781   CHECK_EQ(1, result->Length());
13782   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
13783 }
13784 
13785 
TEST(DefinePropertyPostDetach)13786 TEST(DefinePropertyPostDetach) {
13787   v8::HandleScope scope;
13788   LocalContext context;
13789   v8::Handle<v8::Object> proxy = context->Global();
13790   v8::Handle<v8::Function> define_property =
13791       CompileRun("(function() {"
13792                  "  Object.defineProperty("
13793                  "    this,"
13794                  "    1,"
13795                  "    { configurable: true, enumerable: true, value: 3 });"
13796                  "})").As<Function>();
13797   context->DetachGlobal();
13798   define_property->Call(proxy, 0, NULL);
13799 }
13800 
13801 
InstallContextId(v8::Handle<Context> context,int id)13802 static void InstallContextId(v8::Handle<Context> context, int id) {
13803   Context::Scope scope(context);
13804   CompileRun("Object.prototype").As<Object>()->
13805       Set(v8_str("context_id"), v8::Integer::New(id));
13806 }
13807 
13808 
CheckContextId(v8::Handle<Object> object,int expected)13809 static void CheckContextId(v8::Handle<Object> object, int expected) {
13810   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
13811 }
13812 
13813 
THREADED_TEST(CreationContext)13814 THREADED_TEST(CreationContext) {
13815   HandleScope handle_scope;
13816   Persistent<Context> context1 = Context::New();
13817   InstallContextId(context1, 1);
13818   Persistent<Context> context2 = Context::New();
13819   InstallContextId(context2, 2);
13820   Persistent<Context> context3 = Context::New();
13821   InstallContextId(context3, 3);
13822 
13823   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
13824 
13825   Local<Object> object1;
13826   Local<Function> func1;
13827   {
13828     Context::Scope scope(context1);
13829     object1 = Object::New();
13830     func1 = tmpl->GetFunction();
13831   }
13832 
13833   Local<Object> object2;
13834   Local<Function> func2;
13835   {
13836     Context::Scope scope(context2);
13837     object2 = Object::New();
13838     func2 = tmpl->GetFunction();
13839   }
13840 
13841   Local<Object> instance1;
13842   Local<Object> instance2;
13843 
13844   {
13845     Context::Scope scope(context3);
13846     instance1 = func1->NewInstance();
13847     instance2 = func2->NewInstance();
13848   }
13849 
13850   CHECK(object1->CreationContext() == context1);
13851   CheckContextId(object1, 1);
13852   CHECK(func1->CreationContext() == context1);
13853   CheckContextId(func1, 1);
13854   CHECK(instance1->CreationContext() == context1);
13855   CheckContextId(instance1, 1);
13856   CHECK(object2->CreationContext() == context2);
13857   CheckContextId(object2, 2);
13858   CHECK(func2->CreationContext() == context2);
13859   CheckContextId(func2, 2);
13860   CHECK(instance2->CreationContext() == context2);
13861   CheckContextId(instance2, 2);
13862 
13863   {
13864     Context::Scope scope(context1);
13865     CHECK(object1->CreationContext() == context1);
13866     CheckContextId(object1, 1);
13867     CHECK(func1->CreationContext() == context1);
13868     CheckContextId(func1, 1);
13869     CHECK(instance1->CreationContext() == context1);
13870     CheckContextId(instance1, 1);
13871     CHECK(object2->CreationContext() == context2);
13872     CheckContextId(object2, 2);
13873     CHECK(func2->CreationContext() == context2);
13874     CheckContextId(func2, 2);
13875     CHECK(instance2->CreationContext() == context2);
13876     CheckContextId(instance2, 2);
13877   }
13878 
13879   {
13880     Context::Scope scope(context2);
13881     CHECK(object1->CreationContext() == context1);
13882     CheckContextId(object1, 1);
13883     CHECK(func1->CreationContext() == context1);
13884     CheckContextId(func1, 1);
13885     CHECK(instance1->CreationContext() == context1);
13886     CheckContextId(instance1, 1);
13887     CHECK(object2->CreationContext() == context2);
13888     CheckContextId(object2, 2);
13889     CHECK(func2->CreationContext() == context2);
13890     CheckContextId(func2, 2);
13891     CHECK(instance2->CreationContext() == context2);
13892     CheckContextId(instance2, 2);
13893   }
13894 
13895   context1.Dispose();
13896   context2.Dispose();
13897   context3.Dispose();
13898 }
13899