v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-api.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <limits.h>
29 
30 #ifndef WIN32
31 #include <signal.h> // kill
32 #include <unistd.h> // getpid
33 #endif // WIN32
34 
35 #include "v8.h"
36 
37 #include "api.h"
38 #include "isolate.h"
39 #include "compilation-cache.h"
40 #include "execution.h"
41 #include "objects.h"
42 #include "snapshot.h"
43 #include "platform.h"
44 #include "utils.h"
45 #include "cctest.h"
46 #include "parser.h"
47 #include "unicode-inl.h"
48 
49 static const bool kLogThreading = false;
50 
51 static bool IsNaN(double x) {
52 #ifdef WIN32
53  return _isnan(x);
54 #else
55  return isnan(x);
56 #endif
57 }
58 
59 using ::v8::AccessorInfo;
60 using ::v8::Arguments;
61 using ::v8::Context;
62 using ::v8::Extension;
63 using ::v8::Function;
64 using ::v8::FunctionTemplate;
65 using ::v8::Handle;
66 using ::v8::HandleScope;
67 using ::v8::Local;
68 using ::v8::Message;
71 using ::v8::ObjectTemplate;
72 using ::v8::Persistent;
73 using ::v8::Script;
74 using ::v8::StackTrace;
75 using ::v8::String;
76 using ::v8::TryCatch;
78 using ::v8::V8;
79 using ::v8::Value;
80 
81 
82 static void ExpectString(const char* code, const char* expected) {
83  Local<Value> result = CompileRun(code);
84  CHECK(result->IsString());
85  String::AsciiValue ascii(result);
86  CHECK_EQ(expected, *ascii);
87 }
88 
89 static void ExpectInt32(const char* code, int expected) {
90  Local<Value> result = CompileRun(code);
91  CHECK(result->IsInt32());
92  CHECK_EQ(expected, result->Int32Value());
93 }
94 
95 static void ExpectBoolean(const char* code, bool expected) {
96  Local<Value> result = CompileRun(code);
97  CHECK(result->IsBoolean());
98  CHECK_EQ(expected, result->BooleanValue());
99 }
100 
101 
102 static void ExpectTrue(const char* code) {
103  ExpectBoolean(code, true);
104 }
105 
106 
107 static void ExpectFalse(const char* code) {
108  ExpectBoolean(code, false);
109 }
110 
111 
112 static void ExpectObject(const char* code, Local<Value> expected) {
113  Local<Value> result = CompileRun(code);
114  CHECK(result->Equals(expected));
115 }
116 
117 
118 static void ExpectUndefined(const char* code) {
119  Local<Value> result = CompileRun(code);
120  CHECK(result->IsUndefined());
121 }
122 
123 
124 static int signature_callback_count;
125 static v8::Handle<Value> IncrementingSignatureCallback(
126  const v8::Arguments& args) {
128  signature_callback_count++;
130  for (int i = 0; i < args.Length(); i++)
131  result->Set(v8::Integer::New(i), args[i]);
132  return result;
133 }
134 
135 
136 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
139  for (int i = 0; i < args.Length(); i++) {
140  result->Set(v8::Integer::New(i), args[i]);
141  }
142  return result;
143 }
144 
145 
146 THREADED_TEST(Handles) {
147  v8::HandleScope scope;
148  Local<Context> local_env;
149  {
150  LocalContext env;
151  local_env = env.local();
152  }
153 
154  // Local context should still be live.
155  CHECK(!local_env.IsEmpty());
156  local_env->Enter();
157 
159  CHECK(!undef.IsEmpty());
160  CHECK(undef->IsUndefined());
161 
162  const char* c_source = "1 + 2 + 3";
163  Local<String> source = String::New(c_source);
164  Local<Script> script = Script::Compile(source);
165  CHECK_EQ(6, script->Run()->Int32Value());
166 
167  local_env->Exit();
168 }
169 
170 
171 THREADED_TEST(ReceiverSignature) {
172  v8::HandleScope scope;
173  LocalContext env;
176  fun->PrototypeTemplate()->Set(
177  v8_str("m"),
178  v8::FunctionTemplate::New(IncrementingSignatureCallback,
180  sig));
181  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
182  signature_callback_count = 0;
183  CompileRun(
184  "var o = new Fun();"
185  "o.m();");
186  CHECK_EQ(1, signature_callback_count);
188  sub_fun->Inherit(fun);
189  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
190  CompileRun(
191  "var o = new SubFun();"
192  "o.m();");
193  CHECK_EQ(2, signature_callback_count);
194 
195  v8::TryCatch try_catch;
196  CompileRun(
197  "var o = { };"
198  "o.m = Fun.prototype.m;"
199  "o.m();");
200  CHECK_EQ(2, signature_callback_count);
201  CHECK(try_catch.HasCaught());
202  try_catch.Reset();
204  sub_fun->Inherit(fun);
205  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
206  CompileRun(
207  "var o = new UnrelFun();"
208  "o.m = Fun.prototype.m;"
209  "o.m();");
210  CHECK_EQ(2, signature_callback_count);
211  CHECK(try_catch.HasCaught());
212 }
213 
214 
215 THREADED_TEST(ArgumentSignature) {
216  v8::HandleScope scope;
217  LocalContext env;
219  cons->SetClassName(v8_str("Cons"));
223  v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
224  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
225  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
226 
227  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
228  CHECK(value1->IsTrue());
229 
230  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
231  CHECK(value2->IsTrue());
232 
233  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
234  CHECK(value3->IsTrue());
235 
237  cons1->SetClassName(v8_str("Cons1"));
239  cons2->SetClassName(v8_str("Cons2"));
241  cons3->SetClassName(v8_str("Cons3"));
242 
243  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
247  v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
248 
249  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
250  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
251  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
252  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
253  v8::Handle<Value> value4 = CompileRun(
254  "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
255  "'[object Cons1],[object Cons2],[object Cons3]'");
256  CHECK(value4->IsTrue());
257 
258  v8::Handle<Value> value5 = CompileRun(
259  "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
260  CHECK(value5->IsTrue());
261 
262  v8::Handle<Value> value6 = CompileRun(
263  "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
264  CHECK(value6->IsTrue());
265 
266  v8::Handle<Value> value7 = CompileRun(
267  "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
268  "'[object Cons1],[object Cons2],[object Cons3],d';");
269  CHECK(value7->IsTrue());
270 
271  v8::Handle<Value> value8 = CompileRun(
272  "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
273  CHECK(value8->IsTrue());
274 }
275 
276 
277 THREADED_TEST(HulIgennem) {
278  v8::HandleScope scope;
279  LocalContext env;
281  Local<String> undef_str = undef->ToString();
282  char* value = i::NewArray<char>(undef_str->Length() + 1);
283  undef_str->WriteAscii(value);
284  CHECK_EQ(0, strcmp(value, "undefined"));
285  i::DeleteArray(value);
286 }
287 
288 
289 THREADED_TEST(Access) {
290  v8::HandleScope scope;
291  LocalContext env;
292  Local<v8::Object> obj = v8::Object::New();
293  Local<Value> foo_before = obj->Get(v8_str("foo"));
294  CHECK(foo_before->IsUndefined());
295  Local<String> bar_str = v8_str("bar");
296  obj->Set(v8_str("foo"), bar_str);
297  Local<Value> foo_after = obj->Get(v8_str("foo"));
298  CHECK(!foo_after->IsUndefined());
299  CHECK(foo_after->IsString());
300  CHECK_EQ(bar_str, foo_after);
301 }
302 
303 
304 THREADED_TEST(AccessElement) {
305  v8::HandleScope scope;
306  LocalContext env;
307  Local<v8::Object> obj = v8::Object::New();
308  Local<Value> before = obj->Get(1);
309  CHECK(before->IsUndefined());
310  Local<String> bar_str = v8_str("bar");
311  obj->Set(1, bar_str);
312  Local<Value> after = obj->Get(1);
313  CHECK(!after->IsUndefined());
314  CHECK(after->IsString());
315  CHECK_EQ(bar_str, after);
316 
317  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
318  CHECK_EQ(v8_str("a"), value->Get(0));
319  CHECK_EQ(v8_str("b"), value->Get(1));
320 }
321 
322 
323 THREADED_TEST(Script) {
324  v8::HandleScope scope;
325  LocalContext env;
326  const char* c_source = "1 + 2 + 3";
327  Local<String> source = String::New(c_source);
328  Local<Script> script = Script::Compile(source);
329  CHECK_EQ(6, script->Run()->Int32Value());
330 }
331 
332 
333 static uint16_t* AsciiToTwoByteString(const char* source) {
334  int array_length = i::StrLength(source) + 1;
335  uint16_t* converted = i::NewArray<uint16_t>(array_length);
336  for (int i = 0; i < array_length; i++) converted[i] = source[i];
337  return converted;
338 }
339 
340 
341 class TestResource: public String::ExternalStringResource {
342  public:
343  explicit TestResource(uint16_t* data, int* counter = NULL)
344  : data_(data), length_(0), counter_(counter) {
345  while (data[length_]) ++length_;
346  }
347 
349  i::DeleteArray(data_);
350  if (counter_ != NULL) ++*counter_;
351  }
352 
353  const uint16_t* data() const {
354  return data_;
355  }
356 
357  size_t length() const {
358  return length_;
359  }
360  private:
361  uint16_t* data_;
362  size_t length_;
363  int* counter_;
364 };
365 
366 
367 class TestAsciiResource: public String::ExternalAsciiStringResource {
368  public:
369  explicit TestAsciiResource(const char* data, int* counter = NULL)
370  : data_(data), length_(strlen(data)), counter_(counter) { }
371 
373  i::DeleteArray(data_);
374  if (counter_ != NULL) ++*counter_;
375  }
376 
377  const char* data() const {
378  return data_;
379  }
380 
381  size_t length() const {
382  return length_;
383  }
384  private:
385  const char* data_;
386  size_t length_;
387  int* counter_;
388 };
389 
390 
391 THREADED_TEST(ScriptUsingStringResource) {
392  int dispose_count = 0;
393  const char* c_source = "1 + 2 * 3";
394  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
395  {
396  v8::HandleScope scope;
397  LocalContext env;
398  TestResource* resource = new TestResource(two_byte_source, &dispose_count);
399  Local<String> source = String::NewExternal(resource);
400  Local<Script> script = Script::Compile(source);
401  Local<Value> value = script->Run();
402  CHECK(value->IsNumber());
403  CHECK_EQ(7, value->Int32Value());
404  CHECK(source->IsExternal());
405  CHECK_EQ(resource,
406  static_cast<TestResource*>(source->GetExternalStringResource()));
407  String::Encoding encoding = String::UNKNOWN_ENCODING;
408  CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
409  source->GetExternalStringResourceBase(&encoding));
410  CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
411  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
412  CHECK_EQ(0, dispose_count);
413  }
414  v8::internal::Isolate::Current()->compilation_cache()->Clear();
415  HEAP->CollectAllAvailableGarbage();
416  CHECK_EQ(1, dispose_count);
417 }
418 
419 
420 THREADED_TEST(ScriptUsingAsciiStringResource) {
421  int dispose_count = 0;
422  const char* c_source = "1 + 2 * 3";
423  {
424  v8::HandleScope scope;
425  LocalContext env;
426  TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
427  &dispose_count);
428  Local<String> source = String::NewExternal(resource);
429  CHECK(source->IsExternalAscii());
430  CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
431  source->GetExternalAsciiStringResource());
432  String::Encoding encoding = String::UNKNOWN_ENCODING;
433  CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
434  source->GetExternalStringResourceBase(&encoding));
435  CHECK_EQ(String::ASCII_ENCODING, encoding);
436  Local<Script> script = Script::Compile(source);
437  Local<Value> value = script->Run();
438  CHECK(value->IsNumber());
439  CHECK_EQ(7, value->Int32Value());
440  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
441  CHECK_EQ(0, dispose_count);
442  }
443  i::Isolate::Current()->compilation_cache()->Clear();
444  HEAP->CollectAllAvailableGarbage();
445  CHECK_EQ(1, dispose_count);
446 }
447 
448 
449 THREADED_TEST(ScriptMakingExternalString) {
450  int dispose_count = 0;
451  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
452  {
453  v8::HandleScope scope;
454  LocalContext env;
455  Local<String> source = String::New(two_byte_source);
456  // Trigger GCs so that the newly allocated string moves to old gen.
457  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
458  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
459  CHECK_EQ(source->IsExternal(), false);
460  CHECK_EQ(source->IsExternalAscii(), false);
461  String::Encoding encoding = String::UNKNOWN_ENCODING;
462  CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
463  CHECK_EQ(String::ASCII_ENCODING, encoding);
464  bool success = source->MakeExternal(new TestResource(two_byte_source,
465  &dispose_count));
466  CHECK(success);
467  Local<Script> script = Script::Compile(source);
468  Local<Value> value = script->Run();
469  CHECK(value->IsNumber());
470  CHECK_EQ(7, value->Int32Value());
471  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
472  CHECK_EQ(0, dispose_count);
473  }
474  i::Isolate::Current()->compilation_cache()->Clear();
475  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
476  CHECK_EQ(1, dispose_count);
477 }
478 
479 
480 THREADED_TEST(ScriptMakingExternalAsciiString) {
481  int dispose_count = 0;
482  const char* c_source = "1 + 2 * 3";
483  {
484  v8::HandleScope scope;
485  LocalContext env;
486  Local<String> source = v8_str(c_source);
487  // Trigger GCs so that the newly allocated string moves to old gen.
488  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
489  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
490  bool success = source->MakeExternal(
491  new TestAsciiResource(i::StrDup(c_source), &dispose_count));
492  CHECK(success);
493  Local<Script> script = Script::Compile(source);
494  Local<Value> value = script->Run();
495  CHECK(value->IsNumber());
496  CHECK_EQ(7, value->Int32Value());
497  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
498  CHECK_EQ(0, dispose_count);
499  }
500  i::Isolate::Current()->compilation_cache()->Clear();
501  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
502  CHECK_EQ(1, dispose_count);
503 }
504 
505 
506 TEST(MakingExternalStringConditions) {
507  v8::HandleScope scope;
508  LocalContext env;
509 
510  // Free some space in the new space so that we can check freshness.
511  HEAP->CollectGarbage(i::NEW_SPACE);
512  HEAP->CollectGarbage(i::NEW_SPACE);
513 
514  uint16_t* two_byte_string = AsciiToTwoByteString("s1");
515  Local<String> small_string = String::New(two_byte_string);
516  i::DeleteArray(two_byte_string);
517 
518  // We should refuse to externalize newly created small string.
519  CHECK(!small_string->CanMakeExternal());
520  // Trigger GCs so that the newly allocated string moves to old gen.
521  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
522  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
523  // Old space strings should be accepted.
524  CHECK(small_string->CanMakeExternal());
525 
526  two_byte_string = AsciiToTwoByteString("small string 2");
527  small_string = String::New(two_byte_string);
528  i::DeleteArray(two_byte_string);
529 
530  // We should refuse externalizing newly created small string.
531  CHECK(!small_string->CanMakeExternal());
532  for (int i = 0; i < 100; i++) {
533  String::Value value(small_string);
534  }
535  // Frequently used strings should be accepted.
536  CHECK(small_string->CanMakeExternal());
537 
538  const int buf_size = 10 * 1024;
539  char* buf = i::NewArray<char>(buf_size);
540  memset(buf, 'a', buf_size);
541  buf[buf_size - 1] = '\0';
542 
543  two_byte_string = AsciiToTwoByteString(buf);
544  Local<String> large_string = String::New(two_byte_string);
545  i::DeleteArray(buf);
546  i::DeleteArray(two_byte_string);
547  // Large strings should be immediately accepted.
548  CHECK(large_string->CanMakeExternal());
549 }
550 
551 
552 TEST(MakingExternalAsciiStringConditions) {
553  v8::HandleScope scope;
554  LocalContext env;
555 
556  // Free some space in the new space so that we can check freshness.
557  HEAP->CollectGarbage(i::NEW_SPACE);
558  HEAP->CollectGarbage(i::NEW_SPACE);
559 
560  Local<String> small_string = String::New("s1");
561  // We should refuse to externalize newly created small string.
562  CHECK(!small_string->CanMakeExternal());
563  // Trigger GCs so that the newly allocated string moves to old gen.
564  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
565  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
566  // Old space strings should be accepted.
567  CHECK(small_string->CanMakeExternal());
568 
569  small_string = String::New("small string 2");
570  // We should refuse externalizing newly created small string.
571  CHECK(!small_string->CanMakeExternal());
572  for (int i = 0; i < 100; i++) {
573  String::Value value(small_string);
574  }
575  // Frequently used strings should be accepted.
576  CHECK(small_string->CanMakeExternal());
577 
578  const int buf_size = 10 * 1024;
579  char* buf = i::NewArray<char>(buf_size);
580  memset(buf, 'a', buf_size);
581  buf[buf_size - 1] = '\0';
582  Local<String> large_string = String::New(buf);
583  i::DeleteArray(buf);
584  // Large strings should be immediately accepted.
585  CHECK(large_string->CanMakeExternal());
586 }
587 
588 
589 THREADED_TEST(UsingExternalString) {
590  {
591  v8::HandleScope scope;
592  uint16_t* two_byte_string = AsciiToTwoByteString("test string");
593  Local<String> string =
594  String::NewExternal(new TestResource(two_byte_string));
595  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596  // Trigger GCs so that the newly allocated string moves to old gen.
597  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
598  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
599  i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
600  CHECK(isymbol->IsSymbol());
601  }
602  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
603  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
604 }
605 
606 
607 THREADED_TEST(UsingExternalAsciiString) {
608  {
609  v8::HandleScope scope;
610  const char* one_byte_string = "test string";
611  Local<String> string = String::NewExternal(
612  new TestAsciiResource(i::StrDup(one_byte_string)));
613  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
614  // Trigger GCs so that the newly allocated string moves to old gen.
615  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
616  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
617  i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
618  CHECK(isymbol->IsSymbol());
619  }
620  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
621  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
622 }
623 
624 
625 THREADED_TEST(ScavengeExternalString) {
626  int dispose_count = 0;
627  bool in_new_space = false;
628  {
629  v8::HandleScope scope;
630  uint16_t* two_byte_string = AsciiToTwoByteString("test string");
631  Local<String> string =
632  String::NewExternal(new TestResource(two_byte_string,
633  &dispose_count));
634  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
635  HEAP->CollectGarbage(i::NEW_SPACE);
636  in_new_space = HEAP->InNewSpace(*istring);
637  CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
638  CHECK_EQ(0, dispose_count);
639  }
640  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
641  CHECK_EQ(1, dispose_count);
642 }
643 
644 
645 THREADED_TEST(ScavengeExternalAsciiString) {
646  int dispose_count = 0;
647  bool in_new_space = false;
648  {
649  v8::HandleScope scope;
650  const char* one_byte_string = "test string";
651  Local<String> string = String::NewExternal(
652  new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
653  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
654  HEAP->CollectGarbage(i::NEW_SPACE);
655  in_new_space = HEAP->InNewSpace(*istring);
656  CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
657  CHECK_EQ(0, dispose_count);
658  }
659  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
660  CHECK_EQ(1, dispose_count);
661 }
662 
663 
665  public:
666  // Only used by non-threaded tests, so it can use static fields.
667  static int dispose_calls;
668  static int dispose_count;
669 
670  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
672  dispose_(dispose) { }
673 
674  void Dispose() {
675  ++dispose_calls;
676  if (dispose_) delete this;
677  }
678  private:
679  bool dispose_;
680 };
681 
682 
685 
686 
687 TEST(ExternalStringWithDisposeHandling) {
688  const char* c_source = "1 + 2 * 3";
689 
690  // Use a stack allocated external string resource allocated object.
691  TestAsciiResourceWithDisposeControl::dispose_count = 0;
692  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
694  {
695  v8::HandleScope scope;
696  LocalContext env;
697  Local<String> source = String::NewExternal(&res_stack);
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->CollectAllAvailableGarbage();
703  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
704  }
705  i::Isolate::Current()->compilation_cache()->Clear();
706  HEAP->CollectAllAvailableGarbage();
707  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
708  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
709 
710  // Use a heap allocated external string resource allocated object.
711  TestAsciiResourceWithDisposeControl::dispose_count = 0;
712  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
713  TestAsciiResource* res_heap =
714  new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
715  {
716  v8::HandleScope scope;
717  LocalContext env;
718  Local<String> source = String::NewExternal(res_heap);
719  Local<Script> script = Script::Compile(source);
720  Local<Value> value = script->Run();
721  CHECK(value->IsNumber());
722  CHECK_EQ(7, value->Int32Value());
723  HEAP->CollectAllAvailableGarbage();
724  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
725  }
726  i::Isolate::Current()->compilation_cache()->Clear();
727  HEAP->CollectAllAvailableGarbage();
728  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
729  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
730 }
731 
732 
733 THREADED_TEST(StringConcat) {
734  {
735  v8::HandleScope scope;
736  LocalContext env;
737  const char* one_byte_string_1 = "function a_times_t";
738  const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
739  const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
740  const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
741  const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
742  const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
743  const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
744  Local<String> left = v8_str(one_byte_string_1);
745 
746  uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
747  Local<String> right = String::New(two_byte_source);
748  i::DeleteArray(two_byte_source);
749 
750  Local<String> source = String::Concat(left, right);
751  right = String::NewExternal(
752  new TestAsciiResource(i::StrDup(one_byte_extern_1)));
753  source = String::Concat(source, right);
754  right = String::NewExternal(
755  new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
756  source = String::Concat(source, right);
757  right = v8_str(one_byte_string_2);
758  source = String::Concat(source, right);
759 
760  two_byte_source = AsciiToTwoByteString(two_byte_string_2);
761  right = String::New(two_byte_source);
762  i::DeleteArray(two_byte_source);
763 
764  source = String::Concat(source, right);
765  right = String::NewExternal(
766  new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
767  source = String::Concat(source, right);
768  Local<Script> script = Script::Compile(source);
769  Local<Value> value = script->Run();
770  CHECK(value->IsNumber());
771  CHECK_EQ(68, value->Int32Value());
772  }
773  i::Isolate::Current()->compilation_cache()->Clear();
774  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
775  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
776 }
777 
778 
779 THREADED_TEST(GlobalProperties) {
780  v8::HandleScope scope;
781  LocalContext env;
782  v8::Handle<v8::Object> global = env->Global();
783  global->Set(v8_str("pi"), v8_num(3.1415926));
784  Local<Value> pi = global->Get(v8_str("pi"));
785  CHECK_EQ(3.1415926, pi->NumberValue());
786 }
787 
788 
789 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
791  return v8_num(102);
792 }
793 
794 
795 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
797  args.This()->Set(v8_str("x"), v8_num(1));
798  args.This()->Set(v8_str("y"), v8_num(2));
799  return args.This();
800 }
801 
802 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
804  return v8_num(239);
805 }
806 
807 
808 THREADED_TEST(FunctionTemplate) {
809  v8::HandleScope scope;
810  LocalContext env;
811  {
812  Local<v8::FunctionTemplate> fun_templ =
813  v8::FunctionTemplate::New(handle_call);
814  Local<Function> fun = fun_templ->GetFunction();
815  env->Global()->Set(v8_str("obj"), fun);
816  Local<Script> script = v8_compile("obj()");
817  CHECK_EQ(102, script->Run()->Int32Value());
818  }
819  // Use SetCallHandler to initialize a function template, should work like the
820  // previous one.
821  {
822  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
823  fun_templ->SetCallHandler(handle_call);
824  Local<Function> fun = fun_templ->GetFunction();
825  env->Global()->Set(v8_str("obj"), fun);
826  Local<Script> script = v8_compile("obj()");
827  CHECK_EQ(102, script->Run()->Int32Value());
828  }
829  // Test constructor calls.
830  {
831  Local<v8::FunctionTemplate> fun_templ =
832  v8::FunctionTemplate::New(construct_call);
833  fun_templ->SetClassName(v8_str("funky"));
834  fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
835  Local<Function> fun = fun_templ->GetFunction();
836  env->Global()->Set(v8_str("obj"), fun);
837  Local<Script> script = v8_compile("var s = new obj(); s.x");
838  CHECK_EQ(1, script->Run()->Int32Value());
839 
840  Local<Value> result = v8_compile("(new obj()).toString()")->Run();
841  CHECK_EQ(v8_str("[object funky]"), result);
842 
843  result = v8_compile("(new obj()).m")->Run();
844  CHECK_EQ(239, result->Int32Value());
845  }
846 }
847 
848 
849 static void* expected_ptr;
850 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
851  void* ptr = v8::External::Unwrap(args.Data());
852  CHECK_EQ(expected_ptr, ptr);
853  return v8::True();
854 }
855 
856 
857 static void TestExternalPointerWrapping() {
858  v8::HandleScope scope;
859  LocalContext env;
860 
861  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
862 
864  obj->Set(v8_str("func"),
865  v8::FunctionTemplate::New(callback, data)->GetFunction());
866  env->Global()->Set(v8_str("obj"), obj);
867 
868  CHECK(CompileRun(
869  "function foo() {\n"
870  " for (var i = 0; i < 13; i++) obj.func();\n"
871  "}\n"
872  "foo(), true")->BooleanValue());
873 }
874 
875 
876 THREADED_TEST(ExternalWrap) {
877  // Check heap allocated object.
878  int* ptr = new int;
879  expected_ptr = ptr;
880  TestExternalPointerWrapping();
881  delete ptr;
882 
883  // Check stack allocated object.
884  int foo;
885  expected_ptr = &foo;
886  TestExternalPointerWrapping();
887 
888  // Check not aligned addresses.
889  const int n = 100;
890  char* s = new char[n];
891  for (int i = 0; i < n; i++) {
892  expected_ptr = s + i;
893  TestExternalPointerWrapping();
894  }
895 
896  delete[] s;
897 
898  // Check several invalid addresses.
899  expected_ptr = reinterpret_cast<void*>(1);
900  TestExternalPointerWrapping();
901 
902  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
903  TestExternalPointerWrapping();
904 
905  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
906  TestExternalPointerWrapping();
907 
908 #if defined(V8_HOST_ARCH_X64)
909  // Check a value with a leading 1 bit in x64 Smi encoding.
910  expected_ptr = reinterpret_cast<void*>(0x400000000);
911  TestExternalPointerWrapping();
912 
913  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
914  TestExternalPointerWrapping();
915 
916  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
917  TestExternalPointerWrapping();
918 #endif
919 }
920 
921 
922 THREADED_TEST(FindInstanceInPrototypeChain) {
923  v8::HandleScope scope;
924  LocalContext env;
925 
926  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
927  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
928  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
929  derived->Inherit(base);
930 
931  Local<v8::Function> base_function = base->GetFunction();
932  Local<v8::Function> derived_function = derived->GetFunction();
933  Local<v8::Function> other_function = other->GetFunction();
934 
935  Local<v8::Object> base_instance = base_function->NewInstance();
936  Local<v8::Object> derived_instance = derived_function->NewInstance();
937  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
938  Local<v8::Object> other_instance = other_function->NewInstance();
939  derived_instance2->Set(v8_str("__proto__"), derived_instance);
940  other_instance->Set(v8_str("__proto__"), derived_instance2);
941 
942  // base_instance is only an instance of base.
943  CHECK_EQ(base_instance,
944  base_instance->FindInstanceInPrototypeChain(base));
945  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
946  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
947 
948  // derived_instance is an instance of base and derived.
949  CHECK_EQ(derived_instance,
950  derived_instance->FindInstanceInPrototypeChain(base));
951  CHECK_EQ(derived_instance,
952  derived_instance->FindInstanceInPrototypeChain(derived));
953  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
954 
955  // other_instance is an instance of other and its immediate
956  // prototype derived_instance2 is an instance of base and derived.
957  // Note, derived_instance is an instance of base and derived too,
958  // but it comes after derived_instance2 in the prototype chain of
959  // other_instance.
960  CHECK_EQ(derived_instance2,
961  other_instance->FindInstanceInPrototypeChain(base));
962  CHECK_EQ(derived_instance2,
963  other_instance->FindInstanceInPrototypeChain(derived));
964  CHECK_EQ(other_instance,
965  other_instance->FindInstanceInPrototypeChain(other));
966 }
967 
968 
969 THREADED_TEST(TinyInteger) {
970  v8::HandleScope scope;
971  LocalContext env;
973 
974  int32_t value = 239;
975  Local<v8::Integer> value_obj = v8::Integer::New(value);
976  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
977 
978  value_obj = v8::Integer::New(value, isolate);
979  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
980 }
981 
982 
983 THREADED_TEST(BigSmiInteger) {
984  v8::HandleScope scope;
985  LocalContext env;
987 
988  int32_t value = i::Smi::kMaxValue;
989  // We cannot add one to a Smi::kMaxValue without wrapping.
990  if (i::kSmiValueSize < 32) {
991  CHECK(i::Smi::IsValid(value));
992  CHECK(!i::Smi::IsValid(value + 1));
993 
994  Local<v8::Integer> value_obj = v8::Integer::New(value);
995  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
996 
997  value_obj = v8::Integer::New(value, isolate);
998  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
999  }
1000 }
1001 
1002 
1003 THREADED_TEST(BigInteger) {
1004  v8::HandleScope scope;
1005  LocalContext env;
1006  v8::Isolate* isolate = v8::Isolate::GetCurrent();
1007 
1008  // We cannot add one to a Smi::kMaxValue without wrapping.
1009  if (i::kSmiValueSize < 32) {
1010  // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1011  // The code will not be run in that case, due to the "if" guard.
1012  int32_t value =
1013  static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1014  CHECK(value > i::Smi::kMaxValue);
1015  CHECK(!i::Smi::IsValid(value));
1016 
1017  Local<v8::Integer> value_obj = v8::Integer::New(value);
1018  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1019 
1020  value_obj = v8::Integer::New(value, isolate);
1021  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1022  }
1023 }
1024 
1025 
1026 THREADED_TEST(TinyUnsignedInteger) {
1027  v8::HandleScope scope;
1028  LocalContext env;
1029  v8::Isolate* isolate = v8::Isolate::GetCurrent();
1030 
1031  uint32_t value = 239;
1032 
1033  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1034  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1035 
1036  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1037  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1038 }
1039 
1040 
1041 THREADED_TEST(BigUnsignedSmiInteger) {
1042  v8::HandleScope scope;
1043  LocalContext env;
1044  v8::Isolate* isolate = v8::Isolate::GetCurrent();
1045 
1046  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1047  CHECK(i::Smi::IsValid(value));
1048  CHECK(!i::Smi::IsValid(value + 1));
1049 
1050  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1051  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1052 
1053  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1054  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1055 }
1056 
1057 
1058 THREADED_TEST(BigUnsignedInteger) {
1059  v8::HandleScope scope;
1060  LocalContext env;
1061  v8::Isolate* isolate = v8::Isolate::GetCurrent();
1062 
1063  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1064  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1065  CHECK(!i::Smi::IsValid(value));
1066 
1067  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1068  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1069 
1070  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1071  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1072 }
1073 
1074 
1075 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1076  v8::HandleScope scope;
1077  LocalContext env;
1078  v8::Isolate* isolate = v8::Isolate::GetCurrent();
1079 
1080  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1081  uint32_t value = INT32_MAX_AS_UINT + 1;
1082  CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1083 
1084  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1085  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1086 
1087  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1088  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1089 }
1090 
1091 
1092 THREADED_TEST(IsNativeError) {
1093  v8::HandleScope scope;
1094  LocalContext env;
1095  v8::Handle<Value> syntax_error = CompileRun(
1096  "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1097  CHECK(syntax_error->IsNativeError());
1098  v8::Handle<Value> not_error = CompileRun("{a:42}");
1099  CHECK(!not_error->IsNativeError());
1100  v8::Handle<Value> not_object = CompileRun("42");
1101  CHECK(!not_object->IsNativeError());
1102 }
1103 
1104 
1105 THREADED_TEST(StringObject) {
1106  v8::HandleScope scope;
1107  LocalContext env;
1108  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1109  CHECK(boxed_string->IsStringObject());
1110  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1111  CHECK(!unboxed_string->IsStringObject());
1112  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1113  CHECK(!boxed_not_string->IsStringObject());
1114  v8::Handle<Value> not_object = CompileRun("0");
1115  CHECK(!not_object->IsStringObject());
1116  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1117  CHECK(!as_boxed.IsEmpty());
1118  Local<v8::String> the_string = as_boxed->StringValue();
1119  CHECK(!the_string.IsEmpty());
1120  ExpectObject("\"test\"", the_string);
1121  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1122  CHECK(new_boxed_string->IsStringObject());
1123  as_boxed = new_boxed_string.As<v8::StringObject>();
1124  the_string = as_boxed->StringValue();
1125  CHECK(!the_string.IsEmpty());
1126  ExpectObject("\"test\"", the_string);
1127 }
1128 
1129 
1130 THREADED_TEST(NumberObject) {
1131  v8::HandleScope scope;
1132  LocalContext env;
1133  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1134  CHECK(boxed_number->IsNumberObject());
1135  v8::Handle<Value> unboxed_number = CompileRun("42");
1136  CHECK(!unboxed_number->IsNumberObject());
1137  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1138  CHECK(!boxed_not_number->IsNumberObject());
1139  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1140  CHECK(!as_boxed.IsEmpty());
1141  double the_number = as_boxed->NumberValue();
1142  CHECK_EQ(42.0, the_number);
1143  v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1144  CHECK(new_boxed_number->IsNumberObject());
1145  as_boxed = new_boxed_number.As<v8::NumberObject>();
1146  the_number = as_boxed->NumberValue();
1147  CHECK_EQ(43.0, the_number);
1148 }
1149 
1150 
1151 THREADED_TEST(BooleanObject) {
1152  v8::HandleScope scope;
1153  LocalContext env;
1154  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1155  CHECK(boxed_boolean->IsBooleanObject());
1156  v8::Handle<Value> unboxed_boolean = CompileRun("true");
1157  CHECK(!unboxed_boolean->IsBooleanObject());
1158  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1159  CHECK(!boxed_not_boolean->IsBooleanObject());
1161  boxed_boolean.As<v8::BooleanObject>();
1162  CHECK(!as_boxed.IsEmpty());
1163  bool the_boolean = as_boxed->BooleanValue();
1164  CHECK_EQ(true, the_boolean);
1165  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1166  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1167  CHECK(boxed_true->IsBooleanObject());
1168  CHECK(boxed_false->IsBooleanObject());
1169  as_boxed = boxed_true.As<v8::BooleanObject>();
1170  CHECK_EQ(true, as_boxed->BooleanValue());
1171  as_boxed = boxed_false.As<v8::BooleanObject>();
1172  CHECK_EQ(false, as_boxed->BooleanValue());
1173 }
1174 
1175 
1176 THREADED_TEST(Number) {
1177  v8::HandleScope scope;
1178  LocalContext env;
1179  double PI = 3.1415926;
1180  Local<v8::Number> pi_obj = v8::Number::New(PI);
1181  CHECK_EQ(PI, pi_obj->NumberValue());
1182 }
1183 
1184 
1186  v8::HandleScope scope;
1187  LocalContext env;
1188  Local<String> str = v8_str("3.1415926");
1189  CHECK_EQ(3.1415926, str->NumberValue());
1191  CHECK_EQ(1.0, t->NumberValue());
1193  CHECK_EQ(0.0, f->NumberValue());
1194 }
1195 
1196 
1198  v8::HandleScope scope;
1199  LocalContext env;
1200  double PI = 3.1415926;
1201  Local<Value> date = v8::Date::New(PI);
1202  CHECK_EQ(3.0, date->NumberValue());
1203  date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1204  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1205 }
1206 
1207 
1208 THREADED_TEST(Boolean) {
1209  v8::HandleScope scope;
1210  LocalContext env;
1212  CHECK(t->Value());
1214  CHECK(!f->Value());
1216  CHECK(!u->BooleanValue());
1218  CHECK(!n->BooleanValue());
1219  v8::Handle<String> str1 = v8_str("");
1220  CHECK(!str1->BooleanValue());
1221  v8::Handle<String> str2 = v8_str("x");
1222  CHECK(str2->BooleanValue());
1223  CHECK(!v8::Number::New(0)->BooleanValue());
1224  CHECK(v8::Number::New(-1)->BooleanValue());
1225  CHECK(v8::Number::New(1)->BooleanValue());
1226  CHECK(v8::Number::New(42)->BooleanValue());
1227  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1228 }
1229 
1230 
1231 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1233  return v8_num(13.4);
1234 }
1235 
1236 
1237 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1239  return v8_num(876);
1240 }
1241 
1242 
1243 THREADED_TEST(GlobalPrototype) {
1244  v8::HandleScope scope;
1246  func_templ->PrototypeTemplate()->Set(
1247  "dummy",
1248  v8::FunctionTemplate::New(DummyCallHandler));
1249  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1250  templ->Set("x", v8_num(200));
1251  templ->SetAccessor(v8_str("m"), GetM);
1252  LocalContext env(0, templ);
1253  v8::Handle<Script> script(v8_compile("dummy()"));
1254  v8::Handle<Value> result(script->Run());
1255  CHECK_EQ(13.4, result->NumberValue());
1256  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1257  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1258 }
1259 
1260 
1261 THREADED_TEST(ObjectTemplate) {
1262  v8::HandleScope scope;
1263  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1264  templ1->Set("x", v8_num(10));
1265  templ1->Set("y", v8_num(13));
1266  LocalContext env;
1267  Local<v8::Object> instance1 = templ1->NewInstance();
1268  env->Global()->Set(v8_str("p"), instance1);
1269  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1270  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1271  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1272  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1273  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1274  templ2->Set("a", v8_num(12));
1275  templ2->Set("b", templ1);
1276  Local<v8::Object> instance2 = templ2->NewInstance();
1277  env->Global()->Set(v8_str("q"), instance2);
1278  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1279  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1280  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1281  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1282 }
1283 
1284 
1285 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1287  return v8_num(17.2);
1288 }
1289 
1290 
1291 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1293  return v8_num(15.2);
1294 }
1295 
1296 
1297 THREADED_TEST(DescriptorInheritance) {
1298  v8::HandleScope scope;
1300  super->PrototypeTemplate()->Set("flabby",
1301  v8::FunctionTemplate::New(GetFlabby));
1302  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1303 
1304  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1305 
1307  base1->Inherit(super);
1308  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1309 
1311  base2->Inherit(super);
1312  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1313 
1314  LocalContext env;
1315 
1316  env->Global()->Set(v8_str("s"), super->GetFunction());
1317  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1318  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1319 
1320  // Checks right __proto__ chain.
1321  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1322  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1323 
1324  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1325 
1326  // Instance accessor should not be visible on function object or its prototype
1327  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1328  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1329  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1330 
1331  env->Global()->Set(v8_str("obj"),
1332  base1->GetFunction()->NewInstance());
1333  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1334  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1335  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1336  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1337  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1338 
1339  env->Global()->Set(v8_str("obj2"),
1340  base2->GetFunction()->NewInstance());
1341  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1342  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1343  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1344  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1345  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1346 
1347  // base1 and base2 cannot cross reference to each's prototype
1348  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1349  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1350 }
1351 
1352 
1354 
1355 
1356 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1357  const AccessorInfo& info) {
1359  CHECK_EQ(v8_str("data"), info.Data());
1360  echo_named_call_count++;
1361  return name;
1362 }
1363 
1364 // Helper functions for Interceptor/Accessor interaction tests
1365 
1366 Handle<Value> SimpleAccessorGetter(Local<String> name,
1367  const AccessorInfo& info) {
1368  Handle<Object> self = info.This();
1369  return self->Get(String::Concat(v8_str("accessor_"), name));
1370 }
1371 
1372 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1373  const AccessorInfo& info) {
1374  Handle<Object> self = info.This();
1375  self->Set(String::Concat(v8_str("accessor_"), name), value);
1376 }
1377 
1378 Handle<Value> EmptyInterceptorGetter(Local<String> name,
1379  const AccessorInfo& info) {
1380  return Handle<Value>();
1381 }
1382 
1383 Handle<Value> EmptyInterceptorSetter(Local<String> name,
1384  Local<Value> value,
1385  const AccessorInfo& info) {
1386  return Handle<Value>();
1387 }
1388 
1389 Handle<Value> InterceptorGetter(Local<String> name,
1390  const AccessorInfo& info) {
1391  // Intercept names that start with 'interceptor_'.
1392  String::AsciiValue ascii(name);
1393  char* name_str = *ascii;
1394  char prefix[] = "interceptor_";
1395  int i;
1396  for (i = 0; name_str[i] && prefix[i]; ++i) {
1397  if (name_str[i] != prefix[i]) return Handle<Value>();
1398  }
1399  Handle<Object> self = info.This();
1400  return self->GetHiddenValue(v8_str(name_str + i));
1401 }
1402 
1403 Handle<Value> InterceptorSetter(Local<String> name,
1404  Local<Value> value,
1405  const AccessorInfo& info) {
1406  // Intercept accesses that set certain integer values.
1407  if (value->IsInt32() && value->Int32Value() < 10000) {
1408  Handle<Object> self = info.This();
1409  self->SetHiddenValue(name, value);
1410  return value;
1411  }
1412  return Handle<Value>();
1413 }
1414 
1415 void AddAccessor(Handle<FunctionTemplate> templ,
1416  Handle<String> name,
1417  v8::AccessorGetter getter,
1418  v8::AccessorSetter setter) {
1419  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1420 }
1421 
1422 void AddInterceptor(Handle<FunctionTemplate> templ,
1423  v8::NamedPropertyGetter getter,
1424  v8::NamedPropertySetter setter) {
1425  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1426 }
1427 
1428 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1429  v8::HandleScope scope;
1430  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1431  Handle<FunctionTemplate> child = FunctionTemplate::New();
1432  child->Inherit(parent);
1433  AddAccessor(parent, v8_str("age"),
1436  LocalContext env;
1437  env->Global()->Set(v8_str("Child"), child->GetFunction());
1438  CompileRun("var child = new Child;"
1439  "child.age = 10;");
1440  ExpectBoolean("child.hasOwnProperty('age')", false);
1441  ExpectInt32("child.age", 10);
1442  ExpectInt32("child.accessor_age", 10);
1443 }
1444 
1445 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1446  v8::HandleScope scope;
1447  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1448  Handle<FunctionTemplate> child = FunctionTemplate::New();
1449  child->Inherit(parent);
1451  LocalContext env;
1452  env->Global()->Set(v8_str("Child"), child->GetFunction());
1453  CompileRun("var child = new Child;"
1454  "var parent = child.__proto__;"
1455  "Object.defineProperty(parent, 'age', "
1456  " {get: function(){ return this.accessor_age; }, "
1457  " set: function(v){ this.accessor_age = v; }, "
1458  " enumerable: true, configurable: true});"
1459  "child.age = 10;");
1460  ExpectBoolean("child.hasOwnProperty('age')", false);
1461  ExpectInt32("child.age", 10);
1462  ExpectInt32("child.accessor_age", 10);
1463 }
1464 
1465 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1466  v8::HandleScope scope;
1467  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1468  Handle<FunctionTemplate> child = FunctionTemplate::New();
1469  child->Inherit(parent);
1471  LocalContext env;
1472  env->Global()->Set(v8_str("Child"), child->GetFunction());
1473  CompileRun("var child = new Child;"
1474  "var parent = child.__proto__;"
1475  "parent.name = 'Alice';");
1476  ExpectBoolean("child.hasOwnProperty('name')", false);
1477  ExpectString("child.name", "Alice");
1478  CompileRun("child.name = 'Bob';");
1479  ExpectString("child.name", "Bob");
1480  ExpectBoolean("child.hasOwnProperty('name')", true);
1481  ExpectString("parent.name", "Alice");
1482 }
1483 
1484 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1485  v8::HandleScope scope;
1486  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1487  AddAccessor(templ, v8_str("age"),
1490  LocalContext env;
1491  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1492  CompileRun("var obj = new Obj;"
1493  "function setAge(i){ obj.age = i; };"
1494  "for(var i = 0; i <= 10000; i++) setAge(i);");
1495  // All i < 10000 go to the interceptor.
1496  ExpectInt32("obj.interceptor_age", 9999);
1497  // The last i goes to the accessor.
1498  ExpectInt32("obj.accessor_age", 10000);
1499 }
1500 
1501 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1502  v8::HandleScope scope;
1503  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1504  AddAccessor(templ, v8_str("age"),
1507  LocalContext env;
1508  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1509  CompileRun("var obj = new Obj;"
1510  "function setAge(i){ obj.age = i; };"
1511  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1512  // All i >= 10000 go to the accessor.
1513  ExpectInt32("obj.accessor_age", 10000);
1514  // The last i goes to the interceptor.
1515  ExpectInt32("obj.interceptor_age", 9999);
1516 }
1517 
1518 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1519  v8::HandleScope scope;
1520  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1521  Handle<FunctionTemplate> child = FunctionTemplate::New();
1522  child->Inherit(parent);
1523  AddAccessor(parent, v8_str("age"),
1526  LocalContext env;
1527  env->Global()->Set(v8_str("Child"), child->GetFunction());
1528  CompileRun("var child = new Child;"
1529  "function setAge(i){ child.age = i; };"
1530  "for(var i = 0; i <= 10000; i++) setAge(i);");
1531  // All i < 10000 go to the interceptor.
1532  ExpectInt32("child.interceptor_age", 9999);
1533  // The last i goes to the accessor.
1534  ExpectInt32("child.accessor_age", 10000);
1535 }
1536 
1537 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1538  v8::HandleScope scope;
1539  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1540  Handle<FunctionTemplate> child = FunctionTemplate::New();
1541  child->Inherit(parent);
1542  AddAccessor(parent, v8_str("age"),
1545  LocalContext env;
1546  env->Global()->Set(v8_str("Child"), child->GetFunction());
1547  CompileRun("var child = new Child;"
1548  "function setAge(i){ child.age = i; };"
1549  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1550  // All i >= 10000 go to the accessor.
1551  ExpectInt32("child.accessor_age", 10000);
1552  // The last i goes to the interceptor.
1553  ExpectInt32("child.interceptor_age", 9999);
1554 }
1555 
1556 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1557  v8::HandleScope scope;
1558  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1560  LocalContext env;
1561  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1562  CompileRun("var obj = new Obj;"
1563  "function setter(i) { this.accessor_age = i; };"
1564  "function getter() { return this.accessor_age; };"
1565  "function setAge(i) { obj.age = i; };"
1566  "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1567  "for(var i = 0; i <= 10000; i++) setAge(i);");
1568  // All i < 10000 go to the interceptor.
1569  ExpectInt32("obj.interceptor_age", 9999);
1570  // The last i goes to the JavaScript accessor.
1571  ExpectInt32("obj.accessor_age", 10000);
1572  // The installed JavaScript getter is still intact.
1573  // This last part is a regression test for issue 1651 and relies on the fact
1574  // that both interceptor and accessor are being installed on the same object.
1575  ExpectInt32("obj.age", 10000);
1576  ExpectBoolean("obj.hasOwnProperty('age')", true);
1577  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1578 }
1579 
1580 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1581  v8::HandleScope scope;
1582  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1584  LocalContext env;
1585  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1586  CompileRun("var obj = new Obj;"
1587  "function setter(i) { this.accessor_age = i; };"
1588  "function getter() { return this.accessor_age; };"
1589  "function setAge(i) { obj.age = i; };"
1590  "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1591  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1592  // All i >= 10000 go to the accessor.
1593  ExpectInt32("obj.accessor_age", 10000);
1594  // The last i goes to the interceptor.
1595  ExpectInt32("obj.interceptor_age", 9999);
1596  // The installed JavaScript getter is still intact.
1597  // This last part is a regression test for issue 1651 and relies on the fact
1598  // that both interceptor and accessor are being installed on the same object.
1599  ExpectInt32("obj.age", 10000);
1600  ExpectBoolean("obj.hasOwnProperty('age')", true);
1601  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1602 }
1603 
1604 THREADED_TEST(SwitchFromInterceptorToProperty) {
1605  v8::HandleScope scope;
1606  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1607  Handle<FunctionTemplate> child = FunctionTemplate::New();
1608  child->Inherit(parent);
1610  LocalContext env;
1611  env->Global()->Set(v8_str("Child"), child->GetFunction());
1612  CompileRun("var child = new Child;"
1613  "function setAge(i){ child.age = i; };"
1614  "for(var i = 0; i <= 10000; i++) setAge(i);");
1615  // All i < 10000 go to the interceptor.
1616  ExpectInt32("child.interceptor_age", 9999);
1617  // The last i goes to child's own property.
1618  ExpectInt32("child.age", 10000);
1619 }
1620 
1621 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1622  v8::HandleScope scope;
1623  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1624  Handle<FunctionTemplate> child = FunctionTemplate::New();
1625  child->Inherit(parent);
1627  LocalContext env;
1628  env->Global()->Set(v8_str("Child"), child->GetFunction());
1629  CompileRun("var child = new Child;"
1630  "function setAge(i){ child.age = i; };"
1631  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1632  // All i >= 10000 go to child's own property.
1633  ExpectInt32("child.age", 10000);
1634  // The last i goes to the interceptor.
1635  ExpectInt32("child.interceptor_age", 9999);
1636 }
1637 
1638 THREADED_TEST(NamedPropertyHandlerGetter) {
1639  echo_named_call_count = 0;
1640  v8::HandleScope scope;
1642  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1643  0, 0, 0, 0,
1644  v8_str("data"));
1645  LocalContext env;
1646  env->Global()->Set(v8_str("obj"),
1647  templ->GetFunction()->NewInstance());
1648  CHECK_EQ(echo_named_call_count, 0);
1649  v8_compile("obj.x")->Run();
1650  CHECK_EQ(echo_named_call_count, 1);
1651  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1652  v8::Handle<Value> str = CompileRun(code);
1653  String::AsciiValue value(str);
1654  CHECK_EQ(*value, "oddlepoddle");
1655  // Check default behavior
1656  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1657  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1658  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1659 }
1660 
1661 
1663 
1664 
1665 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1666  const AccessorInfo& info) {
1668  CHECK_EQ(v8_num(637), info.Data());
1669  echo_indexed_call_count++;
1670  return v8_num(index);
1671 }
1672 
1673 
1674 THREADED_TEST(IndexedPropertyHandlerGetter) {
1675  v8::HandleScope scope;
1677  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1678  0, 0, 0, 0,
1679  v8_num(637));
1680  LocalContext env;
1681  env->Global()->Set(v8_str("obj"),
1682  templ->GetFunction()->NewInstance());
1683  Local<Script> script = v8_compile("obj[900]");
1684  CHECK_EQ(script->Run()->Int32Value(), 900);
1685 }
1686 
1687 
1689 
1690 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1691  uint32_t index,
1692  const AccessorInfo& info) {
1694  CHECK(info.This()->Equals(bottom));
1695  return v8::Handle<Value>();
1696 }
1697 
1698 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1699  Local<String> name,
1700  const AccessorInfo& info) {
1702  CHECK(info.This()->Equals(bottom));
1703  return v8::Handle<Value>();
1704 }
1705 
1706 
1708  Local<Value> value,
1709  const AccessorInfo& info) {
1711  CHECK(info.This()->Equals(bottom));
1712  return v8::Handle<Value>();
1713 }
1714 
1715 
1717  Local<Value> value,
1718  const AccessorInfo& info) {
1720  CHECK(info.This()->Equals(bottom));
1721  return v8::Handle<Value>();
1722 }
1723 
1725  uint32_t index,
1726  const AccessorInfo& info) {
1728  CHECK(info.This()->Equals(bottom));
1729  return v8::Handle<v8::Integer>();
1730 }
1731 
1732 
1734  const AccessorInfo& info) {
1736  CHECK(info.This()->Equals(bottom));
1737  return v8::Handle<v8::Integer>();
1738 }
1739 
1740 
1742  uint32_t index,
1743  const AccessorInfo& info) {
1745  CHECK(info.This()->Equals(bottom));
1746  return v8::Handle<v8::Boolean>();
1747 }
1748 
1749 
1751  Local<String> property,
1752  const AccessorInfo& info) {
1754  CHECK(info.This()->Equals(bottom));
1755  return v8::Handle<v8::Boolean>();
1756 }
1757 
1758 
1760  const AccessorInfo& info) {
1762  CHECK(info.This()->Equals(bottom));
1763  return v8::Handle<v8::Array>();
1764 }
1765 
1766 
1768  const AccessorInfo& info) {
1770  CHECK(info.This()->Equals(bottom));
1771  return v8::Handle<v8::Array>();
1772 }
1773 
1774 
1775 THREADED_TEST(PropertyHandlerInPrototype) {
1776  v8::HandleScope scope;
1777  LocalContext env;
1778 
1779  // Set up a prototype chain with three interceptors.
1781  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1782  CheckThisIndexedPropertyHandler,
1787 
1788  templ->InstanceTemplate()->SetNamedPropertyHandler(
1789  CheckThisNamedPropertyHandler,
1794 
1795  bottom = templ->GetFunction()->NewInstance();
1796  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1797  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1798 
1799  bottom->Set(v8_str("__proto__"), middle);
1800  middle->Set(v8_str("__proto__"), top);
1801  env->Global()->Set(v8_str("obj"), bottom);
1802 
1803  // Indexed and named get.
1804  Script::Compile(v8_str("obj[0]"))->Run();
1805  Script::Compile(v8_str("obj.x"))->Run();
1806 
1807  // Indexed and named set.
1808  Script::Compile(v8_str("obj[1] = 42"))->Run();
1809  Script::Compile(v8_str("obj.y = 42"))->Run();
1810 
1811  // Indexed and named query.
1812  Script::Compile(v8_str("0 in obj"))->Run();
1813  Script::Compile(v8_str("'x' in obj"))->Run();
1814 
1815  // Indexed and named deleter.
1816  Script::Compile(v8_str("delete obj[0]"))->Run();
1817  Script::Compile(v8_str("delete obj.x"))->Run();
1818 
1819  // Enumerators.
1820  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1821 }
1822 
1823 
1824 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1825  const AccessorInfo& info) {
1827  if (v8_str("pre")->Equals(key)) {
1828  return v8_str("PrePropertyHandler: pre");
1829  }
1830  return v8::Handle<String>();
1831 }
1832 
1833 
1834 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1835  const AccessorInfo&) {
1836  if (v8_str("pre")->Equals(key)) {
1837  return v8::Integer::New(v8::None);
1838  }
1839 
1840  return v8::Handle<v8::Integer>(); // do not intercept the call
1841 }
1842 
1843 
1844 THREADED_TEST(PrePropertyHandler) {
1845  v8::HandleScope scope;
1847  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1848  0,
1849  PrePropertyHandlerQuery);
1850  LocalContext env(NULL, desc->InstanceTemplate());
1851  Script::Compile(v8_str(
1852  "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1853  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1854  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1855  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1856  CHECK_EQ(v8_str("Object: on"), result_on);
1857  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1858  CHECK(result_post.IsEmpty());
1859 }
1860 
1861 
1862 THREADED_TEST(UndefinedIsNotEnumerable) {
1863  v8::HandleScope scope;
1864  LocalContext env;
1865  v8::Handle<Value> result = Script::Compile(v8_str(
1866  "this.propertyIsEnumerable(undefined)"))->Run();
1867  CHECK(result->IsFalse());
1868 }
1869 
1870 
1872 static const int kTargetRecursionDepth = 200; // near maximum
1873 
1874 
1875 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1877  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1878  if (depth == kTargetRecursionDepth) return v8::Undefined();
1879  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1880  return call_recursively_script->Run();
1881 }
1882 
1883 
1884 static v8::Handle<Value> CallFunctionRecursivelyCall(
1885  const v8::Arguments& args) {
1887  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1888  if (depth == kTargetRecursionDepth) {
1889  printf("[depth = %d]\n", depth);
1890  return v8::Undefined();
1891  }
1892  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1893  v8::Handle<Value> function =
1894  args.This()->Get(v8_str("callFunctionRecursively"));
1895  return function.As<Function>()->Call(args.This(), 0, NULL);
1896 }
1897 
1898 
1899 THREADED_TEST(DeepCrossLanguageRecursion) {
1900  v8::HandleScope scope;
1901  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1902  global->Set(v8_str("callScriptRecursively"),
1903  v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1904  global->Set(v8_str("callFunctionRecursively"),
1905  v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1906  LocalContext env(NULL, global);
1907 
1908  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1909  call_recursively_script = v8_compile("callScriptRecursively()");
1910  call_recursively_script->Run();
1911  call_recursively_script = v8::Handle<Script>();
1912 
1913  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1914  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1915 }
1916 
1917 
1918 static v8::Handle<Value>
1919  ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1921  return v8::ThrowException(key);
1922 }
1923 
1924 
1925 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1926  Local<Value>,
1927  const AccessorInfo&) {
1928  v8::ThrowException(key);
1929  return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1930 }
1931 
1932 
1933 THREADED_TEST(CallbackExceptionRegression) {
1934  v8::HandleScope scope;
1935  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1936  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1937  ThrowingPropertyHandlerSet);
1938  LocalContext env;
1939  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1940  v8::Handle<Value> otto = Script::Compile(v8_str(
1941  "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1942  CHECK_EQ(v8_str("otto"), otto);
1943  v8::Handle<Value> netto = Script::Compile(v8_str(
1944  "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1945  CHECK_EQ(v8_str("netto"), netto);
1946 }
1947 
1948 
1949 THREADED_TEST(FunctionPrototype) {
1950  v8::HandleScope scope;
1951  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1952  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1953  LocalContext env;
1954  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1955  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1956  CHECK_EQ(script->Run()->Int32Value(), 321);
1957 }
1958 
1959 
1960 THREADED_TEST(InternalFields) {
1961  v8::HandleScope scope;
1962  LocalContext env;
1963 
1964  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1965  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1966  instance_templ->SetInternalFieldCount(1);
1967  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1968  CHECK_EQ(1, obj->InternalFieldCount());
1969  CHECK(obj->GetInternalField(0)->IsUndefined());
1970  obj->SetInternalField(0, v8_num(17));
1971  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1972 }
1973 
1974 
1975 THREADED_TEST(GlobalObjectInternalFields) {
1976  v8::HandleScope scope;
1977  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1978  global_template->SetInternalFieldCount(1);
1979  LocalContext env(NULL, global_template);
1980  v8::Handle<v8::Object> global_proxy = env->Global();
1981  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1982  CHECK_EQ(1, global->InternalFieldCount());
1983  CHECK(global->GetInternalField(0)->IsUndefined());
1984  global->SetInternalField(0, v8_num(17));
1985  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1986 }
1987 
1988 
1989 THREADED_TEST(InternalFieldsNativePointers) {
1990  v8::HandleScope scope;
1991  LocalContext env;
1992 
1993  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1994  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1995  instance_templ->SetInternalFieldCount(1);
1996  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1997  CHECK_EQ(1, obj->InternalFieldCount());
1998  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1999 
2000  char* data = new char[100];
2001 
2002  void* aligned = data;
2003  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
2004  void* unaligned = data + 1;
2005  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
2006 
2007  // Check reading and writing aligned pointers.
2008  obj->SetPointerInInternalField(0, aligned);
2009  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2010  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2011 
2012  // Check reading and writing unaligned pointers.
2013  obj->SetPointerInInternalField(0, unaligned);
2014  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2015  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2016 
2017  delete[] data;
2018 }
2019 
2020 
2021 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2022  v8::HandleScope scope;
2023  LocalContext env;
2024 
2025  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2026  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2027  instance_templ->SetInternalFieldCount(1);
2028  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2029  CHECK_EQ(1, obj->InternalFieldCount());
2030  CHECK(obj->GetPointerFromInternalField(0) == NULL);
2031 
2032  char* data = new char[100];
2033 
2034  void* aligned = data;
2035  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
2036  void* unaligned = data + 1;
2037  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
2038 
2039  obj->SetPointerInInternalField(0, aligned);
2040  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2041  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2042 
2043  obj->SetPointerInInternalField(0, unaligned);
2044  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2045  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2046 
2047  obj->SetInternalField(0, v8::External::Wrap(aligned));
2048  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2049  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2050 
2051  obj->SetInternalField(0, v8::External::Wrap(unaligned));
2052  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2053  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2054 
2055  delete[] data;
2056 }
2057 
2058 
2059 THREADED_TEST(IdentityHash) {
2060  v8::HandleScope scope;
2061  LocalContext env;
2062 
2063  // Ensure that the test starts with an fresh heap to test whether the hash
2064  // code is based on the address.
2065  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2066  Local<v8::Object> obj = v8::Object::New();
2067  int hash = obj->GetIdentityHash();
2068  int hash1 = obj->GetIdentityHash();
2069  CHECK_EQ(hash, hash1);
2070  int hash2 = v8::Object::New()->GetIdentityHash();
2071  // Since the identity hash is essentially a random number two consecutive
2072  // objects should not be assigned the same hash code. If the test below fails
2073  // the random number generator should be evaluated.
2074  CHECK_NE(hash, hash2);
2075  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2076  int hash3 = v8::Object::New()->GetIdentityHash();
2077  // Make sure that the identity hash is not based on the initial address of
2078  // the object alone. If the test below fails the random number generator
2079  // should be evaluated.
2080  CHECK_NE(hash, hash3);
2081  int hash4 = obj->GetIdentityHash();
2082  CHECK_EQ(hash, hash4);
2083 
2084  // Check identity hashes behaviour in the presence of JS accessors.
2085  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2086  {
2087  CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2088  Local<v8::Object> o1 = v8::Object::New();
2089  Local<v8::Object> o2 = v8::Object::New();
2090  CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2091  }
2092  {
2093  CompileRun(
2094  "function cnst() { return 42; };\n"
2095  "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2096  Local<v8::Object> o1 = v8::Object::New();
2097  Local<v8::Object> o2 = v8::Object::New();
2098  CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2099  }
2100 }
2101 
2102 
2103 THREADED_TEST(HiddenProperties) {
2104  v8::HandleScope scope;
2105  LocalContext env;
2106 
2108  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2109  v8::Local<v8::String> empty = v8_str("");
2110  v8::Local<v8::String> prop_name = v8_str("prop_name");
2111 
2112  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2113 
2114  // Make sure delete of a non-existent hidden value works
2115  CHECK(obj->DeleteHiddenValue(key));
2116 
2117  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2118  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2119  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2120  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2121 
2122  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2123 
2124  // Make sure we do not find the hidden property.
2125  CHECK(!obj->Has(empty));
2126  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2127  CHECK(obj->Get(empty)->IsUndefined());
2128  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2129  CHECK(obj->Set(empty, v8::Integer::New(2003)));
2130  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2131  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2132 
2133  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2134 
2135  // Add another property and delete it afterwards to force the object in
2136  // slow case.
2137  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2138  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2139  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2140  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2141  CHECK(obj->Delete(prop_name));
2142  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2143 
2144  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2145 
2146  CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2147  CHECK(obj->GetHiddenValue(key).IsEmpty());
2148 
2149  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2150  CHECK(obj->DeleteHiddenValue(key));
2151  CHECK(obj->GetHiddenValue(key).IsEmpty());
2152 }
2153 
2154 
2155 THREADED_TEST(Regress97784) {
2156  // Regression test for crbug.com/97784
2157  // Messing with the Object.prototype should not have effect on
2158  // hidden properties.
2159  v8::HandleScope scope;
2160  LocalContext env;
2161 
2163  v8::Local<v8::String> key = v8_str("hidden");
2164 
2165  CompileRun(
2166  "set_called = false;"
2167  "Object.defineProperty("
2168  " Object.prototype,"
2169  " 'hidden',"
2170  " {get: function() { return 45; },"
2171  " set: function() { set_called = true; }})");
2172 
2173  CHECK(obj->GetHiddenValue(key).IsEmpty());
2174  // Make sure that the getter and setter from Object.prototype is not invoked.
2175  // If it did we would have full access to the hidden properties in
2176  // the accessor.
2177  CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2178  ExpectFalse("set_called");
2179  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2180 }
2181 
2182 
2183 static bool interceptor_for_hidden_properties_called;
2184 static v8::Handle<Value> InterceptorForHiddenProperties(
2185  Local<String> name, const AccessorInfo& info) {
2186  interceptor_for_hidden_properties_called = true;
2187  return v8::Handle<Value>();
2188 }
2189 
2190 
2191 THREADED_TEST(HiddenPropertiesWithInterceptors) {
2192  v8::HandleScope scope;
2193  LocalContext context;
2194 
2195  interceptor_for_hidden_properties_called = false;
2196 
2197  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2198 
2199  // Associate an interceptor with an object and start setting hidden values.
2200  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2201  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2202  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2203  Local<v8::Function> function = fun_templ->GetFunction();
2204  Local<v8::Object> obj = function->NewInstance();
2205  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2206  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2207  CHECK(!interceptor_for_hidden_properties_called);
2208 }
2209 
2210 
2211 THREADED_TEST(External) {
2212  v8::HandleScope scope;
2213  int x = 3;
2214  Local<v8::External> ext = v8::External::New(&x);
2215  LocalContext env;
2216  env->Global()->Set(v8_str("ext"), ext);
2217  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2218  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2219  int* ptr = static_cast<int*>(reext->Value());
2220  CHECK_EQ(x, 3);
2221  *ptr = 10;
2222  CHECK_EQ(x, 10);
2223 
2224  // Make sure unaligned pointers are wrapped properly.
2225  char* data = i::StrDup("0123456789");
2226  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2227  Local<v8::Value> one = v8::External::Wrap(&data[1]);
2228  Local<v8::Value> two = v8::External::Wrap(&data[2]);
2229  Local<v8::Value> three = v8::External::Wrap(&data[3]);
2230 
2231  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2232  CHECK_EQ('0', *char_ptr);
2233  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2234  CHECK_EQ('1', *char_ptr);
2235  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2236  CHECK_EQ('2', *char_ptr);
2237  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2238  CHECK_EQ('3', *char_ptr);
2239  i::DeleteArray(data);
2240 }
2241 
2242 
2243 THREADED_TEST(GlobalHandle) {
2244  v8::Persistent<String> global;
2245  {
2246  v8::HandleScope scope;
2247  Local<String> str = v8_str("str");
2248  global = v8::Persistent<String>::New(str);
2249  }
2250  CHECK_EQ(global->Length(), 3);
2251  global.Dispose();
2252 }
2253 
2254 
2256  public:
2257  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2258  int id() { return id_; }
2259  void increment() { number_of_weak_calls_++; }
2260  int NumberOfWeakCalls() { return number_of_weak_calls_; }
2261  private:
2262  int id_;
2263  int number_of_weak_calls_;
2264 };
2265 
2266 
2267 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2268  WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2269  CHECK_EQ(1234, counter->id());
2270  counter->increment();
2271  handle.Dispose();
2272 }
2273 
2274 
2275 THREADED_TEST(ApiObjectGroups) {
2276  HandleScope scope;
2277  LocalContext env;
2278 
2279  Persistent<Object> g1s1;
2280  Persistent<Object> g1s2;
2281  Persistent<Object> g1c1;
2282  Persistent<Object> g2s1;
2283  Persistent<Object> g2s2;
2284  Persistent<Object> g2c1;
2285 
2286  WeakCallCounter counter(1234);
2287 
2288  {
2289  HandleScope scope;
2290  g1s1 = Persistent<Object>::New(Object::New());
2291  g1s2 = Persistent<Object>::New(Object::New());
2292  g1c1 = Persistent<Object>::New(Object::New());
2293  g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2294  g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2295  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2296 
2297  g2s1 = Persistent<Object>::New(Object::New());
2298  g2s2 = Persistent<Object>::New(Object::New());
2299  g2c1 = Persistent<Object>::New(Object::New());
2300  g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2301  g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2302  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2303  }
2304 
2305  Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2306 
2307  // Connect group 1 and 2, make a cycle.
2308  CHECK(g1s2->Set(0, g2s2));
2309  CHECK(g2s1->Set(0, g1s1));
2310 
2311  {
2312  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2313  Persistent<Value> g1_children[] = { g1c1 };
2314  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2315  Persistent<Value> g2_children[] = { g2c1 };
2316  V8::AddObjectGroup(g1_objects, 2);
2317  V8::AddImplicitReferences(g1s1, g1_children, 1);
2318  V8::AddObjectGroup(g2_objects, 2);
2319  V8::AddImplicitReferences(g2s2, g2_children, 1);
2320  }
2321  // Do a single full GC, ensure incremental marking is stopped.
2322  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2323 
2324  // All object should be alive.
2325  CHECK_EQ(0, counter.NumberOfWeakCalls());
2326 
2327  // Weaken the root.
2328  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2329  // But make children strong roots---all the objects (except for children)
2330  // should be collectable now.
2331  g1c1.ClearWeak();
2332  g2c1.ClearWeak();
2333 
2334  // Groups are deleted, rebuild groups.
2335  {
2336  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2337  Persistent<Value> g1_children[] = { g1c1 };
2338  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2339  Persistent<Value> g2_children[] = { g2c1 };
2340  V8::AddObjectGroup(g1_objects, 2);
2341  V8::AddImplicitReferences(g1s1, g1_children, 1);
2342  V8::AddObjectGroup(g2_objects, 2);
2343  V8::AddImplicitReferences(g2s2, g2_children, 1);
2344  }
2345 
2346  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2347 
2348  // All objects should be gone. 5 global handles in total.
2349  CHECK_EQ(5, counter.NumberOfWeakCalls());
2350 
2351  // And now make children weak again and collect them.
2352  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2353  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2354 
2355  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2356  CHECK_EQ(7, counter.NumberOfWeakCalls());
2357 }
2358 
2359 
2360 THREADED_TEST(ApiObjectGroupsCycle) {
2361  HandleScope scope;
2362  LocalContext env;
2363 
2364  WeakCallCounter counter(1234);
2365 
2366  Persistent<Object> g1s1;
2367  Persistent<Object> g1s2;
2368  Persistent<Object> g2s1;
2369  Persistent<Object> g2s2;
2370  Persistent<Object> g3s1;
2371  Persistent<Object> g3s2;
2372 
2373  {
2374  HandleScope scope;
2375  g1s1 = Persistent<Object>::New(Object::New());
2376  g1s2 = Persistent<Object>::New(Object::New());
2377  g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2378  g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2379 
2380  g2s1 = Persistent<Object>::New(Object::New());
2381  g2s2 = Persistent<Object>::New(Object::New());
2382  g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2383  g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2384 
2385  g3s1 = Persistent<Object>::New(Object::New());
2386  g3s2 = Persistent<Object>::New(Object::New());
2387  g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2388  g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2389  }
2390 
2391  Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2392 
2393  // Connect groups. We're building the following cycle:
2394  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2395  // groups.
2396  {
2397  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2398  Persistent<Value> g1_children[] = { g2s1 };
2399  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2400  Persistent<Value> g2_children[] = { g3s1 };
2401  Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2402  Persistent<Value> g3_children[] = { g1s1 };
2403  V8::AddObjectGroup(g1_objects, 2);
2404  V8::AddImplicitReferences(g1s1, g1_children, 1);
2405  V8::AddObjectGroup(g2_objects, 2);
2406  V8::AddImplicitReferences(g2s1, g2_children, 1);
2407  V8::AddObjectGroup(g3_objects, 2);
2408  V8::AddImplicitReferences(g3s1, g3_children, 1);
2409  }
2410  // Do a single full GC
2411  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2412 
2413  // All object should be alive.
2414  CHECK_EQ(0, counter.NumberOfWeakCalls());
2415 
2416  // Weaken the root.
2417  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2418 
2419  // Groups are deleted, rebuild groups.
2420  {
2421  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2422  Persistent<Value> g1_children[] = { g2s1 };
2423  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2424  Persistent<Value> g2_children[] = { g3s1 };
2425  Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2426  Persistent<Value> g3_children[] = { g1s1 };
2427  V8::AddObjectGroup(g1_objects, 2);
2428  V8::AddImplicitReferences(g1s1, g1_children, 1);
2429  V8::AddObjectGroup(g2_objects, 2);
2430  V8::AddImplicitReferences(g2s1, g2_children, 1);
2431  V8::AddObjectGroup(g3_objects, 2);
2432  V8::AddImplicitReferences(g3s1, g3_children, 1);
2433  }
2434 
2435  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2436 
2437  // All objects should be gone. 7 global handles in total.
2438  CHECK_EQ(7, counter.NumberOfWeakCalls());
2439 }
2440 
2441 
2442 THREADED_TEST(ScriptException) {
2443  v8::HandleScope scope;
2444  LocalContext env;
2445  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2446  v8::TryCatch try_catch;
2447  Local<Value> result = script->Run();
2448  CHECK(result.IsEmpty());
2449  CHECK(try_catch.HasCaught());
2450  String::AsciiValue exception_value(try_catch.Exception());
2451  CHECK_EQ(*exception_value, "panama!");
2452 }
2453 
2454 
2456 
2457 
2458 static void check_message_0(v8::Handle<v8::Message> message,
2459  v8::Handle<Value> data) {
2460  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2461  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2462  message_received = true;
2463 }
2464 
2465 
2466 THREADED_TEST(MessageHandler0) {
2467  message_received = false;
2468  v8::HandleScope scope;
2469  CHECK(!message_received);
2470  v8::V8::AddMessageListener(check_message_0);
2471  LocalContext context;
2472  v8::ScriptOrigin origin =
2473  v8::ScriptOrigin(v8_str("6.75"));
2474  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2475  &origin);
2476  script->SetData(v8_str("7.56"));
2477  script->Run();
2478  CHECK(message_received);
2479  // clear out the message listener
2480  v8::V8::RemoveMessageListeners(check_message_0);
2481 }
2482 
2483 
2484 static void check_message_1(v8::Handle<v8::Message> message,
2485  v8::Handle<Value> data) {
2486  CHECK(data->IsNumber());
2487  CHECK_EQ(1337, data->Int32Value());
2488  message_received = true;
2489 }
2490 
2491 
2492 TEST(MessageHandler1) {
2493  message_received = false;
2494  v8::HandleScope scope;
2495  CHECK(!message_received);
2496  v8::V8::AddMessageListener(check_message_1);
2497  LocalContext context;
2498  CompileRun("throw 1337;");
2499  CHECK(message_received);
2500  // clear out the message listener
2501  v8::V8::RemoveMessageListeners(check_message_1);
2502 }
2503 
2504 
2505 static void check_message_2(v8::Handle<v8::Message> message,
2506  v8::Handle<Value> data) {
2507  LocalContext context;
2508  CHECK(data->IsObject());
2509  v8::Local<v8::Value> hidden_property =
2510  v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2511  CHECK(v8_str("hidden value")->Equals(hidden_property));
2512  message_received = true;
2513 }
2514 
2515 
2516 TEST(MessageHandler2) {
2517  message_received = false;
2518  v8::HandleScope scope;
2519  CHECK(!message_received);
2520  v8::V8::AddMessageListener(check_message_2);
2521  LocalContext context;
2522  v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2523  v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2524  v8_str("hidden value"));
2525  context->Global()->Set(v8_str("error"), error);
2526  CompileRun("throw error;");
2527  CHECK(message_received);
2528  // clear out the message listener
2529  v8::V8::RemoveMessageListeners(check_message_2);
2530 }
2531 
2532 
2533 THREADED_TEST(GetSetProperty) {
2534  v8::HandleScope scope;
2535  LocalContext context;
2536  context->Global()->Set(v8_str("foo"), v8_num(14));
2537  context->Global()->Set(v8_str("12"), v8_num(92));
2538  context->Global()->Set(v8::Integer::New(16), v8_num(32));
2539  context->Global()->Set(v8_num(13), v8_num(56));
2540  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2541  CHECK_EQ(14, foo->Int32Value());
2542  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2543  CHECK_EQ(92, twelve->Int32Value());
2544  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2545  CHECK_EQ(32, sixteen->Int32Value());
2546  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2547  CHECK_EQ(56, thirteen->Int32Value());
2548  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2549  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2550  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2551  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2552  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2553  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2554  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2555  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2556  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2557 }
2558 
2559 
2561  v8::HandleScope scope;
2562  LocalContext context;
2563  // none
2564  Local<String> prop = v8_str("none");
2565  context->Global()->Set(prop, v8_num(7));
2566  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2567  // read-only
2568  prop = v8_str("read_only");
2569  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2570  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2571  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2572  Script::Compile(v8_str("read_only = 9"))->Run();
2573  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2574  context->Global()->Set(prop, v8_num(10));
2575  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2576  // dont-delete
2577  prop = v8_str("dont_delete");
2578  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2579  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2580  Script::Compile(v8_str("delete dont_delete"))->Run();
2581  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2582  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2583  // dont-enum
2584  prop = v8_str("dont_enum");
2585  context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2586  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2587  // absent
2588  prop = v8_str("absent");
2589  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2590  Local<Value> fake_prop = v8_num(1);
2591  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2592  // exception
2593  TryCatch try_catch;
2594  Local<Value> exception =
2595  CompileRun("({ toString: function() { throw 'exception';} })");
2596  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2597  CHECK(try_catch.HasCaught());
2598  String::AsciiValue exception_value(try_catch.Exception());
2599  CHECK_EQ("exception", *exception_value);
2600  try_catch.Reset();
2601 }
2602 
2603 
2605  v8::HandleScope scope;
2606  LocalContext context;
2607  Local<v8::Array> array = v8::Array::New();
2608  CHECK_EQ(0, array->Length());
2609  CHECK(array->Get(0)->IsUndefined());
2610  CHECK(!array->Has(0));
2611  CHECK(array->Get(100)->IsUndefined());
2612  CHECK(!array->Has(100));
2613  array->Set(2, v8_num(7));
2614  CHECK_EQ(3, array->Length());
2615  CHECK(!array->Has(0));
2616  CHECK(!array->Has(1));
2617  CHECK(array->Has(2));
2618  CHECK_EQ(7, array->Get(2)->Int32Value());
2619  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2620  Local<v8::Array> arr = obj.As<v8::Array>();
2621  CHECK_EQ(3, arr->Length());
2622  CHECK_EQ(1, arr->Get(0)->Int32Value());
2623  CHECK_EQ(2, arr->Get(1)->Int32Value());
2624  CHECK_EQ(3, arr->Get(2)->Int32Value());
2625  array = v8::Array::New(27);
2626  CHECK_EQ(27, array->Length());
2627  array = v8::Array::New(-27);
2628  CHECK_EQ(0, array->Length());
2629 }
2630 
2631 
2633  v8::HandleScope scope;
2635  Local<v8::Array> result = v8::Array::New(args.Length());
2636  for (int i = 0; i < args.Length(); i++)
2637  result->Set(i, args[i]);
2638  return scope.Close(result);
2639 }
2640 
2641 
2642 THREADED_TEST(Vector) {
2643  v8::HandleScope scope;
2644  Local<ObjectTemplate> global = ObjectTemplate::New();
2645  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2646  LocalContext context(0, global);
2647 
2648  const char* fun = "f()";
2649  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2650  CHECK_EQ(0, a0->Length());
2651 
2652  const char* fun2 = "f(11)";
2653  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2654  CHECK_EQ(1, a1->Length());
2655  CHECK_EQ(11, a1->Get(0)->Int32Value());
2656 
2657  const char* fun3 = "f(12, 13)";
2658  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2659  CHECK_EQ(2, a2->Length());
2660  CHECK_EQ(12, a2->Get(0)->Int32Value());
2661  CHECK_EQ(13, a2->Get(1)->Int32Value());
2662 
2663  const char* fun4 = "f(14, 15, 16)";
2664  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2665  CHECK_EQ(3, a3->Length());
2666  CHECK_EQ(14, a3->Get(0)->Int32Value());
2667  CHECK_EQ(15, a3->Get(1)->Int32Value());
2668  CHECK_EQ(16, a3->Get(2)->Int32Value());
2669 
2670  const char* fun5 = "f(17, 18, 19, 20)";
2671  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2672  CHECK_EQ(4, a4->Length());
2673  CHECK_EQ(17, a4->Get(0)->Int32Value());
2674  CHECK_EQ(18, a4->Get(1)->Int32Value());
2675  CHECK_EQ(19, a4->Get(2)->Int32Value());
2676  CHECK_EQ(20, a4->Get(3)->Int32Value());
2677 }
2678 
2679 
2680 THREADED_TEST(FunctionCall) {
2681  v8::HandleScope scope;
2682  LocalContext context;
2683  CompileRun(
2684  "function Foo() {"
2685  " var result = [];"
2686  " for (var i = 0; i < arguments.length; i++) {"
2687  " result.push(arguments[i]);"
2688  " }"
2689  " return result;"
2690  "}");
2691  Local<Function> Foo =
2692  Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2693 
2694  v8::Handle<Value>* args0 = NULL;
2695  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2696  CHECK_EQ(0, a0->Length());
2697 
2698  v8::Handle<Value> args1[] = { v8_num(1.1) };
2699  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2700  CHECK_EQ(1, a1->Length());
2701  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2702 
2703  v8::Handle<Value> args2[] = { v8_num(2.2),
2704  v8_num(3.3) };
2705  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2706  CHECK_EQ(2, a2->Length());
2707  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2708  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2709 
2710  v8::Handle<Value> args3[] = { v8_num(4.4),
2711  v8_num(5.5),
2712  v8_num(6.6) };
2713  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2714  CHECK_EQ(3, a3->Length());
2715  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2716  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2717  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2718 
2719  v8::Handle<Value> args4[] = { v8_num(7.7),
2720  v8_num(8.8),
2721  v8_num(9.9),
2722  v8_num(10.11) };
2723  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2724  CHECK_EQ(4, a4->Length());
2725  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2726  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2727  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2728  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2729 }
2730 
2731 
2732 static const char* js_code_causing_out_of_memory =
2733  "var a = new Array(); while(true) a.push(a);";
2734 
2735 
2736 // These tests run for a long time and prevent us from running tests
2737 // that come after them so they cannot run in parallel.
2738 TEST(OutOfMemory) {
2739  // It's not possible to read a snapshot into a heap with different dimensions.
2740  if (i::Snapshot::IsEnabled()) return;
2741  // Set heap limits.
2742  static const int K = 1024;
2743  v8::ResourceConstraints constraints;
2744  constraints.set_max_young_space_size(256 * K);
2745  constraints.set_max_old_space_size(4 * K * K);
2746  v8::SetResourceConstraints(&constraints);
2747 
2748  // Execute a script that causes out of memory.
2749  v8::HandleScope scope;
2750  LocalContext context;
2752  Local<Script> script =
2753  Script::Compile(String::New(js_code_causing_out_of_memory));
2754  Local<Value> result = script->Run();
2755 
2756  // Check for out of memory state.
2757  CHECK(result.IsEmpty());
2758  CHECK(context->HasOutOfMemoryException());
2759 }
2760 
2761 
2764 
2765  v8::HandleScope scope;
2766  LocalContext context;
2767  Local<Script> script =
2768  Script::Compile(String::New(js_code_causing_out_of_memory));
2769  Local<Value> result = script->Run();
2770 
2771  // Check for out of memory state.
2772  CHECK(result.IsEmpty());
2773  CHECK(context->HasOutOfMemoryException());
2774 
2775  return result;
2776 }
2777 
2778 
2779 TEST(OutOfMemoryNested) {
2780  // It's not possible to read a snapshot into a heap with different dimensions.
2781  if (i::Snapshot::IsEnabled()) return;
2782  // Set heap limits.
2783  static const int K = 1024;
2784  v8::ResourceConstraints constraints;
2785  constraints.set_max_young_space_size(256 * K);
2786  constraints.set_max_old_space_size(4 * K * K);
2787  v8::SetResourceConstraints(&constraints);
2788 
2789  v8::HandleScope scope;
2790  Local<ObjectTemplate> templ = ObjectTemplate::New();
2791  templ->Set(v8_str("ProvokeOutOfMemory"),
2793  LocalContext context(0, templ);
2795  Local<Value> result = CompileRun(
2796  "var thrown = false;"
2797  "try {"
2798  " ProvokeOutOfMemory();"
2799  "} catch (e) {"
2800  " thrown = true;"
2801  "}");
2802  // Check for out of memory state.
2803  CHECK(result.IsEmpty());
2804  CHECK(context->HasOutOfMemoryException());
2805 }
2806 
2807 
2808 TEST(HugeConsStringOutOfMemory) {
2809  // It's not possible to read a snapshot into a heap with different dimensions.
2810  if (i::Snapshot::IsEnabled()) return;
2811  // Set heap limits.
2812  static const int K = 1024;
2813  v8::ResourceConstraints constraints;
2814  constraints.set_max_young_space_size(256 * K);
2815  constraints.set_max_old_space_size(3 * K * K);
2816  v8::SetResourceConstraints(&constraints);
2817 
2818  // Execute a script that causes out of memory.
2820 
2821  v8::HandleScope scope;
2822  LocalContext context;
2823 
2824  // Build huge string. This should fail with out of memory exception.
2825  Local<Value> result = CompileRun(
2826  "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2827  "for (var i = 0; i < 22; i++) { str = str + str; }");
2828 
2829  // Check for out of memory state.
2830  CHECK(result.IsEmpty());
2831  CHECK(context->HasOutOfMemoryException());
2832 }
2833 
2834 
2835 THREADED_TEST(ConstructCall) {
2836  v8::HandleScope scope;
2837  LocalContext context;
2838  CompileRun(
2839  "function Foo() {"
2840  " var result = [];"
2841  " for (var i = 0; i < arguments.length; i++) {"
2842  " result.push(arguments[i]);"
2843  " }"
2844  " return result;"
2845  "}");
2846  Local<Function> Foo =
2847  Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2848 
2849  v8::Handle<Value>* args0 = NULL;
2850  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2851  CHECK_EQ(0, a0->Length());
2852 
2853  v8::Handle<Value> args1[] = { v8_num(1.1) };
2854  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2855  CHECK_EQ(1, a1->Length());
2856  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2857 
2858  v8::Handle<Value> args2[] = { v8_num(2.2),
2859  v8_num(3.3) };
2860  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2861  CHECK_EQ(2, a2->Length());
2862  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2863  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2864 
2865  v8::Handle<Value> args3[] = { v8_num(4.4),
2866  v8_num(5.5),
2867  v8_num(6.6) };
2868  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2869  CHECK_EQ(3, a3->Length());
2870  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2871  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2872  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2873 
2874  v8::Handle<Value> args4[] = { v8_num(7.7),
2875  v8_num(8.8),
2876  v8_num(9.9),
2877  v8_num(10.11) };
2878  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2879  CHECK_EQ(4, a4->Length());
2880  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2881  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2882  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2883  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2884 }
2885 
2886 
2887 static void CheckUncle(v8::TryCatch* try_catch) {
2888  CHECK(try_catch->HasCaught());
2889  String::AsciiValue str_value(try_catch->Exception());
2890  CHECK_EQ(*str_value, "uncle?");
2891  try_catch->Reset();
2892 }
2893 
2894 
2895 THREADED_TEST(ConversionNumber) {
2896  v8::HandleScope scope;
2897  LocalContext env;
2898  // Very large number.
2899  CompileRun("var obj = Math.pow(2,32) * 1237;");
2900  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2901  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2902  CHECK_EQ(0, obj->ToInt32()->Value());
2903  CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2904  // Large number.
2905  CompileRun("var obj = -1234567890123;");
2906  obj = env->Global()->Get(v8_str("obj"));
2907  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2908  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2909  CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2910  // Small positive integer.
2911  CompileRun("var obj = 42;");
2912  obj = env->Global()->Get(v8_str("obj"));
2913  CHECK_EQ(42.0, obj->ToNumber()->Value());
2914  CHECK_EQ(42, obj->ToInt32()->Value());
2915  CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2916  // Negative integer.
2917  CompileRun("var obj = -37;");
2918  obj = env->Global()->Get(v8_str("obj"));
2919  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2920  CHECK_EQ(-37, obj->ToInt32()->Value());
2921  CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2922  // Positive non-int32 integer.
2923  CompileRun("var obj = 0x81234567;");
2924  obj = env->Global()->Get(v8_str("obj"));
2925  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2926  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2927  CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2928  // Fraction.
2929  CompileRun("var obj = 42.3;");
2930  obj = env->Global()->Get(v8_str("obj"));
2931  CHECK_EQ(42.3, obj->ToNumber()->Value());
2932  CHECK_EQ(42, obj->ToInt32()->Value());
2933  CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2934  // Large negative fraction.
2935  CompileRun("var obj = -5726623061.75;");
2936  obj = env->Global()->Get(v8_str("obj"));
2937  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2938  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2939  CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2940 }
2941 
2942 
2943 THREADED_TEST(isNumberType) {
2944  v8::HandleScope scope;
2945  LocalContext env;
2946  // Very large number.
2947  CompileRun("var obj = Math.pow(2,32) * 1237;");
2948  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2949  CHECK(!obj->IsInt32());
2950  CHECK(!obj->IsUint32());
2951  // Large negative number.
2952  CompileRun("var obj = -1234567890123;");
2953  obj = env->Global()->Get(v8_str("obj"));
2954  CHECK(!obj->IsInt32());
2955  CHECK(!obj->IsUint32());
2956  // Small positive integer.
2957  CompileRun("var obj = 42;");
2958  obj = env->Global()->Get(v8_str("obj"));
2959  CHECK(obj->IsInt32());
2960  CHECK(obj->IsUint32());
2961  // Negative integer.
2962  CompileRun("var obj = -37;");
2963  obj = env->Global()->Get(v8_str("obj"));
2964  CHECK(obj->IsInt32());
2965  CHECK(!obj->IsUint32());
2966  // Positive non-int32 integer.
2967  CompileRun("var obj = 0x81234567;");
2968  obj = env->Global()->Get(v8_str("obj"));
2969  CHECK(!obj->IsInt32());
2970  CHECK(obj->IsUint32());
2971  // Fraction.
2972  CompileRun("var obj = 42.3;");
2973  obj = env->Global()->Get(v8_str("obj"));
2974  CHECK(!obj->IsInt32());
2975  CHECK(!obj->IsUint32());
2976  // Large negative fraction.
2977  CompileRun("var obj = -5726623061.75;");
2978  obj = env->Global()->Get(v8_str("obj"));
2979  CHECK(!obj->IsInt32());
2980  CHECK(!obj->IsUint32());
2981  // Positive zero
2982  CompileRun("var obj = 0.0;");
2983  obj = env->Global()->Get(v8_str("obj"));
2984  CHECK(obj->IsInt32());
2985  CHECK(obj->IsUint32());
2986  // Positive zero
2987  CompileRun("var obj = -0.0;");
2988  obj = env->Global()->Get(v8_str("obj"));
2989  CHECK(!obj->IsInt32());
2990  CHECK(!obj->IsUint32());
2991 }
2992 
2993 
2994 THREADED_TEST(ConversionException) {
2995  v8::HandleScope scope;
2996  LocalContext env;
2997  CompileRun(
2998  "function TestClass() { };"
2999  "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3000  "var obj = new TestClass();");
3001  Local<Value> obj = env->Global()->Get(v8_str("obj"));
3002 
3003  v8::TryCatch try_catch;
3004 
3005  Local<Value> to_string_result = obj->ToString();
3006  CHECK(to_string_result.IsEmpty());
3007  CheckUncle(&try_catch);
3008 
3009  Local<Value> to_number_result = obj->ToNumber();
3010  CHECK(to_number_result.IsEmpty());
3011  CheckUncle(&try_catch);
3012 
3013  Local<Value> to_integer_result = obj->ToInteger();
3014  CHECK(to_integer_result.IsEmpty());
3015  CheckUncle(&try_catch);
3016 
3017  Local<Value> to_uint32_result = obj->ToUint32();
3018  CHECK(to_uint32_result.IsEmpty());
3019  CheckUncle(&try_catch);
3020 
3021  Local<Value> to_int32_result = obj->ToInt32();
3022  CHECK(to_int32_result.IsEmpty());
3023  CheckUncle(&try_catch);
3024 
3025  Local<Value> to_object_result = v8::Undefined()->ToObject();
3026  CHECK(to_object_result.IsEmpty());
3027  CHECK(try_catch.HasCaught());
3028  try_catch.Reset();
3029 
3030  int32_t int32_value = obj->Int32Value();
3031  CHECK_EQ(0, int32_value);
3032  CheckUncle(&try_catch);
3033 
3034  uint32_t uint32_value = obj->Uint32Value();
3035  CHECK_EQ(0, uint32_value);
3036  CheckUncle(&try_catch);
3037 
3038  double number_value = obj->NumberValue();
3039  CHECK_NE(0, IsNaN(number_value));
3040  CheckUncle(&try_catch);
3041 
3042  int64_t integer_value = obj->IntegerValue();
3043  CHECK_EQ(0.0, static_cast<double>(integer_value));
3044  CheckUncle(&try_catch);
3045 }
3046 
3047 
3050  return v8::ThrowException(v8_str("konto"));
3051 }
3052 
3053 
3055  if (args.Length() < 1) return v8::False();
3056  v8::HandleScope scope;
3057  v8::TryCatch try_catch;
3058  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3059  CHECK(!try_catch.HasCaught() || result.IsEmpty());
3060  return v8::Boolean::New(try_catch.HasCaught());
3061 }
3062 
3063 
3064 THREADED_TEST(APICatch) {
3065  v8::HandleScope scope;
3066  Local<ObjectTemplate> templ = ObjectTemplate::New();
3067  templ->Set(v8_str("ThrowFromC"),
3069  LocalContext context(0, templ);
3070  CompileRun(
3071  "var thrown = false;"
3072  "try {"
3073  " ThrowFromC();"
3074  "} catch (e) {"
3075  " thrown = true;"
3076  "}");
3077  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3078  CHECK(thrown->BooleanValue());
3079 }
3080 
3081 
3082 THREADED_TEST(APIThrowTryCatch) {
3083  v8::HandleScope scope;
3084  Local<ObjectTemplate> templ = ObjectTemplate::New();
3085  templ->Set(v8_str("ThrowFromC"),
3087  LocalContext context(0, templ);
3088  v8::TryCatch try_catch;
3089  CompileRun("ThrowFromC();");
3090  CHECK(try_catch.HasCaught());
3091 }
3092 
3093 
3094 // Test that a try-finally block doesn't shadow a try-catch block
3095 // when setting up an external handler.
3096 //
3097 // BUG(271): Some of the exception propagation does not work on the
3098 // ARM simulator because the simulator separates the C++ stack and the
3099 // JS stack. This test therefore fails on the simulator. The test is
3100 // not threaded to allow the threading tests to run on the simulator.
3101 TEST(TryCatchInTryFinally) {
3102  v8::HandleScope scope;
3103  Local<ObjectTemplate> templ = ObjectTemplate::New();
3104  templ->Set(v8_str("CCatcher"),
3106  LocalContext context(0, templ);
3107  Local<Value> result = CompileRun("try {"
3108  " try {"
3109  " CCatcher('throw 7;');"
3110  " } finally {"
3111  " }"
3112  "} catch (e) {"
3113  "}");
3114  CHECK(result->IsTrue());
3115 }
3116 
3117 
3118 static void check_reference_error_message(
3119  v8::Handle<v8::Message> message,
3120  v8::Handle<v8::Value> data) {
3121  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3122  CHECK(message->Get()->Equals(v8_str(reference_error)));
3123 }
3124 
3125 
3126 static v8::Handle<Value> Fail(const v8::Arguments& args) {
3128  CHECK(false);
3129  return v8::Undefined();
3130 }
3131 
3132 
3133 // Test that overwritten methods are not invoked on uncaught exception
3134 // formatting. However, they are invoked when performing normal error
3135 // string conversions.
3136 TEST(APIThrowMessageOverwrittenToString) {
3137  v8::HandleScope scope;
3138  v8::V8::AddMessageListener(check_reference_error_message);
3139  Local<ObjectTemplate> templ = ObjectTemplate::New();
3140  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3141  LocalContext context(NULL, templ);
3142  CompileRun("asdf;");
3143  CompileRun("var limit = {};"
3144  "limit.valueOf = fail;"
3145  "Error.stackTraceLimit = limit;");
3146  CompileRun("asdf");
3147  CompileRun("Array.prototype.pop = fail;");
3148  CompileRun("Object.prototype.hasOwnProperty = fail;");
3149  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
3150  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3151  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
3152  CompileRun("ReferenceError.prototype.toString ="
3153  " function() { return 'Whoops' }");
3154  CompileRun("asdf;");
3155  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3156  CompileRun("asdf;");
3157  CompileRun("ReferenceError.prototype.constructor = void 0;");
3158  CompileRun("asdf;");
3159  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3160  CompileRun("asdf;");
3161  CompileRun("ReferenceError.prototype = new Object();");
3162  CompileRun("asdf;");
3163  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3164  CHECK(string->Equals(v8_str("Whoops")));
3165  CompileRun("ReferenceError.prototype.constructor = new Object();"
3166  "ReferenceError.prototype.constructor.name = 1;"
3167  "Number.prototype.toString = function() { return 'Whoops'; };"
3168  "ReferenceError.prototype.toString = Object.prototype.toString;");
3169  CompileRun("asdf;");
3170  v8::V8::RemoveMessageListeners(check_reference_error_message);
3171 }
3172 
3173 
3174 static void check_custom_error_message(
3175  v8::Handle<v8::Message> message,
3176  v8::Handle<v8::Value> data) {
3177  const char* uncaught_error = "Uncaught MyError toString";
3178  CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3179 }
3180 
3181 
3182 TEST(CustomErrorToString) {
3183  v8::HandleScope scope;
3184  v8::V8::AddMessageListener(check_custom_error_message);
3185  LocalContext context;
3186  CompileRun(
3187  "function MyError(name, message) { "
3188  " this.name = name; "
3189  " this.message = message; "
3190  "} "
3191  "MyError.prototype = Object.create(Error.prototype); "
3192  "MyError.prototype.toString = function() { "
3193  " return 'MyError toString'; "
3194  "}; "
3195  "throw new MyError('my name', 'my message'); ");
3196  v8::V8::RemoveMessageListeners(check_custom_error_message);
3197 }
3198 
3199 
3200 static void receive_message(v8::Handle<v8::Message> message,
3201  v8::Handle<v8::Value> data) {
3202  message->Get();
3203  message_received = true;
3204 }
3205 
3206 
3207 TEST(APIThrowMessage) {
3208  message_received = false;
3209  v8::HandleScope scope;
3210  v8::V8::AddMessageListener(receive_message);
3211  Local<ObjectTemplate> templ = ObjectTemplate::New();
3212  templ->Set(v8_str("ThrowFromC"),
3214  LocalContext context(0, templ);
3215  CompileRun("ThrowFromC();");
3216  CHECK(message_received);
3217  v8::V8::RemoveMessageListeners(receive_message);
3218 }
3219 
3220 
3221 TEST(APIThrowMessageAndVerboseTryCatch) {
3222  message_received = false;
3223  v8::HandleScope scope;
3224  v8::V8::AddMessageListener(receive_message);
3225  Local<ObjectTemplate> templ = ObjectTemplate::New();
3226  templ->Set(v8_str("ThrowFromC"),
3228  LocalContext context(0, templ);
3229  v8::TryCatch try_catch;
3230  try_catch.SetVerbose(true);
3231  Local<Value> result = CompileRun("ThrowFromC();");
3232  CHECK(try_catch.HasCaught());
3233  CHECK(result.IsEmpty());
3234  CHECK(message_received);
3235  v8::V8::RemoveMessageListeners(receive_message);
3236 }
3237 
3238 
3239 TEST(APIStackOverflowAndVerboseTryCatch) {
3240  message_received = false;
3241  v8::HandleScope scope;
3242  v8::V8::AddMessageListener(receive_message);
3243  LocalContext context;
3244  v8::TryCatch try_catch;
3245  try_catch.SetVerbose(true);
3246  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3247  CHECK(try_catch.HasCaught());
3248  CHECK(result.IsEmpty());
3249  CHECK(message_received);
3250  v8::V8::RemoveMessageListeners(receive_message);
3251 }
3252 
3253 
3254 THREADED_TEST(ExternalScriptException) {
3255  v8::HandleScope scope;
3256  Local<ObjectTemplate> templ = ObjectTemplate::New();
3257  templ->Set(v8_str("ThrowFromC"),
3259  LocalContext context(0, templ);
3260 
3261  v8::TryCatch try_catch;
3262  Local<Script> script
3263  = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3264  Local<Value> result = script->Run();
3265  CHECK(result.IsEmpty());
3266  CHECK(try_catch.HasCaught());
3267  String::AsciiValue exception_value(try_catch.Exception());
3268  CHECK_EQ("konto", *exception_value);
3269 }
3270 
3271 
3272 
3275  CHECK_EQ(4, args.Length());
3276  int count = args[0]->Int32Value();
3277  int cInterval = args[2]->Int32Value();
3278  if (count == 0) {
3279  return v8::ThrowException(v8_str("FromC"));
3280  } else {
3281  Local<v8::Object> global = Context::GetCurrent()->Global();
3282  Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3283  v8::Handle<Value> argv[] = { v8_num(count - 1),
3284  args[1],
3285  args[2],
3286  args[3] };
3287  if (count % cInterval == 0) {
3288  v8::TryCatch try_catch;
3289  Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3290  int expected = args[3]->Int32Value();
3291  if (try_catch.HasCaught()) {
3292  CHECK_EQ(expected, count);
3293  CHECK(result.IsEmpty());
3294  CHECK(!i::Isolate::Current()->has_scheduled_exception());
3295  } else {
3296  CHECK_NE(expected, count);
3297  }
3298  return result;
3299  } else {
3300  return fun.As<Function>()->Call(global, 4, argv);
3301  }
3302  }
3303 }
3304 
3305 
3308  CHECK_EQ(3, args.Length());
3309  bool equality = args[0]->BooleanValue();
3310  int count = args[1]->Int32Value();
3311  int expected = args[2]->Int32Value();
3312  if (equality) {
3313  CHECK_EQ(count, expected);
3314  } else {
3315  CHECK_NE(count, expected);
3316  }
3317  return v8::Undefined();
3318 }
3319 
3320 
3321 THREADED_TEST(EvalInTryFinally) {
3322  v8::HandleScope scope;
3323  LocalContext context;
3324  v8::TryCatch try_catch;
3325  CompileRun("(function() {"
3326  " try {"
3327  " eval('asldkf (*&^&*^');"
3328  " } finally {"
3329  " return;"
3330  " }"
3331  "})()");
3332  CHECK(!try_catch.HasCaught());
3333 }
3334 
3335 
3336 // This test works by making a stack of alternating JavaScript and C
3337 // activations. These activations set up exception handlers with regular
3338 // intervals, one interval for C activations and another for JavaScript
3339 // activations. When enough activations have been created an exception is
3340 // thrown and we check that the right activation catches the exception and that
3341 // no other activations do. The right activation is always the topmost one with
3342 // a handler, regardless of whether it is in JavaScript or C.
3343 //
3344 // The notation used to describe a test case looks like this:
3345 //
3346 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3347 //
3348 // Each entry is an activation, either JS or C. The index is the count at that
3349 // level. Stars identify activations with exception handlers, the @ identifies
3350 // the exception handler that should catch the exception.
3351 //
3352 // BUG(271): Some of the exception propagation does not work on the
3353 // ARM simulator because the simulator separates the C++ stack and the
3354 // JS stack. This test therefore fails on the simulator. The test is
3355 // not threaded to allow the threading tests to run on the simulator.
3356 TEST(ExceptionOrder) {
3357  v8::HandleScope scope;
3358  Local<ObjectTemplate> templ = ObjectTemplate::New();
3359  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3360  templ->Set(v8_str("CThrowCountDown"),
3362  LocalContext context(0, templ);
3363  CompileRun(
3364  "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3365  " if (count == 0) throw 'FromJS';"
3366  " if (count % jsInterval == 0) {"
3367  " try {"
3368  " var value = CThrowCountDown(count - 1,"
3369  " jsInterval,"
3370  " cInterval,"
3371  " expected);"
3372  " check(false, count, expected);"
3373  " return value;"
3374  " } catch (e) {"
3375  " check(true, count, expected);"
3376  " }"
3377  " } else {"
3378  " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3379  " }"
3380  "}");
3381  Local<Function> fun =
3382  Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3383 
3384  const int argc = 4;
3385  // count jsInterval cInterval expected
3386 
3387  // *JS[4] *C[3] @JS[2] C[1] JS[0]
3388  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3389  fun->Call(fun, argc, a0);
3390 
3391  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3392  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3393  fun->Call(fun, argc, a1);
3394 
3395  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3396  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3397  fun->Call(fun, argc, a2);
3398 
3399  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3400  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3401  fun->Call(fun, argc, a3);
3402 
3403  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3404  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3405  fun->Call(fun, argc, a4);
3406 
3407  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3408  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3409  fun->Call(fun, argc, a5);
3410 }
3411 
3412 
3415  CHECK_EQ(1, args.Length());
3416  return v8::ThrowException(args[0]);
3417 }
3418 
3419 
3420 THREADED_TEST(ThrowValues) {
3421  v8::HandleScope scope;
3422  Local<ObjectTemplate> templ = ObjectTemplate::New();
3423  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3424  LocalContext context(0, templ);
3426  "function Run(obj) {"
3427  " try {"
3428  " Throw(obj);"
3429  " } catch (e) {"
3430  " return e;"
3431  " }"
3432  " return 'no exception';"
3433  "}"
3434  "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3435  CHECK_EQ(5, result->Length());
3436  CHECK(result->Get(v8::Integer::New(0))->IsString());
3437  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3438  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3439  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3440  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3441  CHECK(result->Get(v8::Integer::New(3))->IsNull());
3442  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3443 }
3444 
3445 
3446 THREADED_TEST(CatchZero) {
3447  v8::HandleScope scope;
3448  LocalContext context;
3449  v8::TryCatch try_catch;
3450  CHECK(!try_catch.HasCaught());
3451  Script::Compile(v8_str("throw 10"))->Run();
3452  CHECK(try_catch.HasCaught());
3453  CHECK_EQ(10, try_catch.Exception()->Int32Value());
3454  try_catch.Reset();
3455  CHECK(!try_catch.HasCaught());
3456  Script::Compile(v8_str("throw 0"))->Run();
3457  CHECK(try_catch.HasCaught());
3458  CHECK_EQ(0, try_catch.Exception()->Int32Value());
3459 }
3460 
3461 
3462 THREADED_TEST(CatchExceptionFromWith) {
3463  v8::HandleScope scope;
3464  LocalContext context;
3465  v8::TryCatch try_catch;
3466  CHECK(!try_catch.HasCaught());
3467  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3468  CHECK(try_catch.HasCaught());
3469 }
3470 
3471 
3472 THREADED_TEST(TryCatchAndFinallyHidingException) {
3473  v8::HandleScope scope;
3474  LocalContext context;
3475  v8::TryCatch try_catch;
3476  CHECK(!try_catch.HasCaught());
3477  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3478  CompileRun("f({toString: function() { throw 42; }});");
3479  CHECK(!try_catch.HasCaught());
3480 }
3481 
3482 
3484  v8::TryCatch try_catch;
3485  return v8::Undefined();
3486 }
3487 
3488 
3489 THREADED_TEST(TryCatchAndFinally) {
3490  v8::HandleScope scope;
3491  LocalContext context;
3492  context->Global()->Set(
3493  v8_str("native_with_try_catch"),
3494  v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3495  v8::TryCatch try_catch;
3496  CHECK(!try_catch.HasCaught());
3497  CompileRun(
3498  "try {\n"
3499  " throw new Error('a');\n"
3500  "} finally {\n"
3501  " native_with_try_catch();\n"
3502  "}\n");
3503  CHECK(try_catch.HasCaught());
3504 }
3505 
3506 
3507 THREADED_TEST(Equality) {
3508  v8::HandleScope scope;
3509  LocalContext context;
3510  // Check that equality works at all before relying on CHECK_EQ
3511  CHECK(v8_str("a")->Equals(v8_str("a")));
3512  CHECK(!v8_str("a")->Equals(v8_str("b")));
3513 
3514  CHECK_EQ(v8_str("a"), v8_str("a"));
3515  CHECK_NE(v8_str("a"), v8_str("b"));
3516  CHECK_EQ(v8_num(1), v8_num(1));
3517  CHECK_EQ(v8_num(1.00), v8_num(1));
3518  CHECK_NE(v8_num(1), v8_num(2));
3519 
3520  // Assume String is not symbol.
3521  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3522  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3523  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3524  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3525  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3526  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3527  Local<Value> not_a_number = v8_num(i::OS::nan_value());
3528  CHECK(!not_a_number->StrictEquals(not_a_number));
3529  CHECK(v8::False()->StrictEquals(v8::False()));
3530  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3531 
3534  CHECK(alias->StrictEquals(obj));
3535  alias.Dispose();
3536 }
3537 
3538 
3539 THREADED_TEST(MultiRun) {
3540  v8::HandleScope scope;
3541  LocalContext context;
3542  Local<Script> script = Script::Compile(v8_str("x"));
3543  for (int i = 0; i < 10; i++)
3544  script->Run();
3545 }
3546 
3547 
3548 static v8::Handle<Value> GetXValue(Local<String> name,
3549  const AccessorInfo& info) {
3551  CHECK_EQ(info.Data(), v8_str("donut"));
3552  CHECK_EQ(name, v8_str("x"));
3553  return name;
3554 }
3555 
3556 
3557 THREADED_TEST(SimplePropertyRead) {
3558  v8::HandleScope scope;
3559  Local<ObjectTemplate> templ = ObjectTemplate::New();
3560  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3561  LocalContext context;
3562  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3563  Local<Script> script = Script::Compile(v8_str("obj.x"));
3564  for (int i = 0; i < 10; i++) {
3565  Local<Value> result = script->Run();
3566  CHECK_EQ(result, v8_str("x"));
3567  }
3568 }
3569 
3570 THREADED_TEST(DefinePropertyOnAPIAccessor) {
3571  v8::HandleScope scope;
3572  Local<ObjectTemplate> templ = ObjectTemplate::New();
3573  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3574  LocalContext context;
3575  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3576 
3577  // Uses getOwnPropertyDescriptor to check the configurable status
3578  Local<Script> script_desc
3579  = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3580  "obj, 'x');"
3581  "prop.configurable;"));
3582  Local<Value> result = script_desc->Run();
3583  CHECK_EQ(result->BooleanValue(), true);
3584 
3585  // Redefine get - but still configurable
3586  Local<Script> script_define
3587  = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3588  " configurable: true };"
3589  "Object.defineProperty(obj, 'x', desc);"
3590  "obj.x"));
3591  result = script_define->Run();
3592  CHECK_EQ(result, v8_num(42));
3593 
3594  // Check that the accessor is still configurable
3595  result = script_desc->Run();
3596  CHECK_EQ(result->BooleanValue(), true);
3597 
3598  // Redefine to a non-configurable
3599  script_define
3600  = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3601  " configurable: false };"
3602  "Object.defineProperty(obj, 'x', desc);"
3603  "obj.x"));
3604  result = script_define->Run();
3605  CHECK_EQ(result, v8_num(43));
3606  result = script_desc->Run();
3607  CHECK_EQ(result->BooleanValue(), false);
3608 
3609  // Make sure that it is not possible to redefine again
3610  v8::TryCatch try_catch;
3611  result = script_define->Run();
3612  CHECK(try_catch.HasCaught());
3613  String::AsciiValue exception_value(try_catch.Exception());
3614  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3615 }
3616 
3617 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3618  v8::HandleScope scope;
3619  Local<ObjectTemplate> templ = ObjectTemplate::New();
3620  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3621  LocalContext context;
3622  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3623 
3624  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3625  "Object.getOwnPropertyDescriptor( "
3626  "obj, 'x');"
3627  "prop.configurable;"));
3628  Local<Value> result = script_desc->Run();
3629  CHECK_EQ(result->BooleanValue(), true);
3630 
3631  Local<Script> script_define =
3632  Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3633  " configurable: true };"
3634  "Object.defineProperty(obj, 'x', desc);"
3635  "obj.x"));
3636  result = script_define->Run();
3637  CHECK_EQ(result, v8_num(42));
3638 
3639 
3640  result = script_desc->Run();
3641  CHECK_EQ(result->BooleanValue(), true);
3642 
3643 
3644  script_define =
3645  Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3646  " configurable: false };"
3647  "Object.defineProperty(obj, 'x', desc);"
3648  "obj.x"));
3649  result = script_define->Run();
3650  CHECK_EQ(result, v8_num(43));
3651  result = script_desc->Run();
3652 
3653  CHECK_EQ(result->BooleanValue(), false);
3654 
3655  v8::TryCatch try_catch;
3656  result = script_define->Run();
3657  CHECK(try_catch.HasCaught());
3658  String::AsciiValue exception_value(try_catch.Exception());
3659  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3660 }
3661 
3662 
3663 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3664  char const* name) {
3665  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3666 }
3667 
3668 
3669 THREADED_TEST(DefineAPIAccessorOnObject) {
3670  v8::HandleScope scope;
3671  Local<ObjectTemplate> templ = ObjectTemplate::New();
3672  LocalContext context;
3673 
3674  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3675  CompileRun("var obj2 = {};");
3676 
3677  CHECK(CompileRun("obj1.x")->IsUndefined());
3678  CHECK(CompileRun("obj2.x")->IsUndefined());
3679 
3680  CHECK(GetGlobalProperty(&context, "obj1")->
3681  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3682 
3683  ExpectString("obj1.x", "x");
3684  CHECK(CompileRun("obj2.x")->IsUndefined());
3685 
3686  CHECK(GetGlobalProperty(&context, "obj2")->
3687  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3688 
3689  ExpectString("obj1.x", "x");
3690  ExpectString("obj2.x", "x");
3691 
3692  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3693  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3694 
3695  CompileRun("Object.defineProperty(obj1, 'x',"
3696  "{ get: function() { return 'y'; }, configurable: true })");
3697 
3698  ExpectString("obj1.x", "y");
3699  ExpectString("obj2.x", "x");
3700 
3701  CompileRun("Object.defineProperty(obj2, 'x',"
3702  "{ get: function() { return 'y'; }, configurable: true })");
3703 
3704  ExpectString("obj1.x", "y");
3705  ExpectString("obj2.x", "y");
3706 
3707  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3708  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3709 
3710  CHECK(GetGlobalProperty(&context, "obj1")->
3711  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3712  CHECK(GetGlobalProperty(&context, "obj2")->
3713  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3714 
3715  ExpectString("obj1.x", "x");
3716  ExpectString("obj2.x", "x");
3717 
3718  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3719  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3720 
3721  // Define getters/setters, but now make them not configurable.
3722  CompileRun("Object.defineProperty(obj1, 'x',"
3723  "{ get: function() { return 'z'; }, configurable: false })");
3724  CompileRun("Object.defineProperty(obj2, 'x',"
3725  "{ get: function() { return 'z'; }, configurable: false })");
3726 
3727  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3728  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3729 
3730  ExpectString("obj1.x", "z");
3731  ExpectString("obj2.x", "z");
3732 
3733  CHECK(!GetGlobalProperty(&context, "obj1")->
3734  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3735  CHECK(!GetGlobalProperty(&context, "obj2")->
3736  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3737 
3738  ExpectString("obj1.x", "z");
3739  ExpectString("obj2.x", "z");
3740 }
3741 
3742 
3743 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3744  v8::HandleScope scope;
3745  Local<ObjectTemplate> templ = ObjectTemplate::New();
3746  LocalContext context;
3747 
3748  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3749  CompileRun("var obj2 = {};");
3750 
3751  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3752  v8_str("x"),
3753  GetXValue, NULL,
3754  v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3755  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3756  v8_str("x"),
3757  GetXValue, NULL,
3758  v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3759 
3760  ExpectString("obj1.x", "x");
3761  ExpectString("obj2.x", "x");
3762 
3763  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3764  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3765 
3766  CHECK(!GetGlobalProperty(&context, "obj1")->
3767  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3768  CHECK(!GetGlobalProperty(&context, "obj2")->
3769  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3770 
3771  {
3772  v8::TryCatch try_catch;
3773  CompileRun("Object.defineProperty(obj1, 'x',"
3774  "{get: function() { return 'func'; }})");
3775  CHECK(try_catch.HasCaught());
3776  String::AsciiValue exception_value(try_catch.Exception());
3777  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3778  }
3779  {
3780  v8::TryCatch try_catch;
3781  CompileRun("Object.defineProperty(obj2, 'x',"
3782  "{get: function() { return 'func'; }})");
3783  CHECK(try_catch.HasCaught());
3784  String::AsciiValue exception_value(try_catch.Exception());
3785  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3786  }
3787 }
3788 
3789 
3790 static v8::Handle<Value> Get239Value(Local<String> name,
3791  const AccessorInfo& info) {
3793  CHECK_EQ(info.Data(), v8_str("donut"));
3794  CHECK_EQ(name, v8_str("239"));
3795  return name;
3796 }
3797 
3798 
3799 THREADED_TEST(ElementAPIAccessor) {
3800  v8::HandleScope scope;
3801  Local<ObjectTemplate> templ = ObjectTemplate::New();
3802  LocalContext context;
3803 
3804  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3805  CompileRun("var obj2 = {};");
3806 
3807  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3808  v8_str("239"),
3809  Get239Value, NULL,
3810  v8_str("donut")));
3811  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3812  v8_str("239"),
3813  Get239Value, NULL,
3814  v8_str("donut")));
3815 
3816  ExpectString("obj1[239]", "239");
3817  ExpectString("obj2[239]", "239");
3818  ExpectString("obj1['239']", "239");
3819  ExpectString("obj2['239']", "239");
3820 }
3821 
3822 
3824 
3825 
3826 static void SetXValue(Local<String> name,
3827  Local<Value> value,
3828  const AccessorInfo& info) {
3829  CHECK_EQ(value, v8_num(4));
3830  CHECK_EQ(info.Data(), v8_str("donut"));
3831  CHECK_EQ(name, v8_str("x"));
3832  CHECK(xValue.IsEmpty());
3833  xValue = v8::Persistent<Value>::New(value);
3834 }
3835 
3836 
3837 THREADED_TEST(SimplePropertyWrite) {
3838  v8::HandleScope scope;
3839  Local<ObjectTemplate> templ = ObjectTemplate::New();
3840  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3841  LocalContext context;
3842  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3843  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3844  for (int i = 0; i < 10; i++) {
3845  CHECK(xValue.IsEmpty());
3846  script->Run();
3847  CHECK_EQ(v8_num(4), xValue);
3848  xValue.Dispose();
3849  xValue = v8::Persistent<Value>();
3850  }
3851 }
3852 
3853 
3854 THREADED_TEST(SetterOnly) {
3855  v8::HandleScope scope;
3856  Local<ObjectTemplate> templ = ObjectTemplate::New();
3857  templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
3858  LocalContext context;
3859  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3860  Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3861  for (int i = 0; i < 10; i++) {
3862  CHECK(xValue.IsEmpty());
3863  script->Run();
3864  CHECK_EQ(v8_num(4), xValue);
3865  xValue.Dispose();
3866  xValue = v8::Persistent<Value>();
3867  }
3868 }
3869 
3870 
3871 THREADED_TEST(NoAccessors) {
3872  v8::HandleScope scope;
3873  Local<ObjectTemplate> templ = ObjectTemplate::New();
3874  templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
3875  LocalContext context;
3876  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3877  Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3878  for (int i = 0; i < 10; i++) {
3879  script->Run();
3880  }
3881 }
3882 
3883 
3884 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3885  const AccessorInfo& info) {
3887  CHECK(info.Data()->IsUndefined());
3888  return property;
3889 }
3890 
3891 
3892 THREADED_TEST(NamedInterceptorPropertyRead) {
3893  v8::HandleScope scope;
3894  Local<ObjectTemplate> templ = ObjectTemplate::New();
3895  templ->SetNamedPropertyHandler(XPropertyGetter);
3896  LocalContext context;
3897  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3898  Local<Script> script = Script::Compile(v8_str("obj.x"));
3899  for (int i = 0; i < 10; i++) {
3900  Local<Value> result = script->Run();
3901  CHECK_EQ(result, v8_str("x"));
3902  }
3903 }
3904 
3905 
3906 THREADED_TEST(NamedInterceptorDictionaryIC) {
3907  v8::HandleScope scope;
3908  Local<ObjectTemplate> templ = ObjectTemplate::New();
3909  templ->SetNamedPropertyHandler(XPropertyGetter);
3910  LocalContext context;
3911  // Create an object with a named interceptor.
3912  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3913  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3914  for (int i = 0; i < 10; i++) {
3915  Local<Value> result = script->Run();
3916  CHECK_EQ(result, v8_str("x"));
3917  }
3918  // Create a slow case object and a function accessing a property in
3919  // that slow case object (with dictionary probing in generated
3920  // code). Then force object with a named interceptor into slow-case,
3921  // pass it to the function, and check that the interceptor is called
3922  // instead of accessing the local property.
3923  Local<Value> result =
3924  CompileRun("function get_x(o) { return o.x; };"
3925  "var obj = { x : 42, y : 0 };"
3926  "delete obj.y;"
3927  "for (var i = 0; i < 10; i++) get_x(obj);"
3928  "interceptor_obj.x = 42;"
3929  "interceptor_obj.y = 10;"
3930  "delete interceptor_obj.y;"
3931  "get_x(interceptor_obj)");
3932  CHECK_EQ(result, v8_str("x"));
3933 }
3934 
3935 
3936 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3937  v8::HandleScope scope;
3938 
3939  v8::Persistent<Context> context1 = Context::New();
3940 
3941  context1->Enter();
3942  Local<ObjectTemplate> templ = ObjectTemplate::New();
3943  templ->SetNamedPropertyHandler(XPropertyGetter);
3944  // Create an object with a named interceptor.
3945  v8::Local<v8::Object> object = templ->NewInstance();
3946  context1->Global()->Set(v8_str("interceptor_obj"), object);
3947 
3948  // Force the object into the slow case.
3949  CompileRun("interceptor_obj.y = 0;"
3950  "delete interceptor_obj.y;");
3951  context1->Exit();
3952 
3953  {
3954  // Introduce the object into a different context.
3955  // Repeat named loads to exercise ICs.
3956  LocalContext context2;
3957  context2->Global()->Set(v8_str("interceptor_obj"), object);
3958  Local<Value> result =
3959  CompileRun("function get_x(o) { return o.x; }"
3960  "interceptor_obj.x = 42;"
3961  "for (var i=0; i != 10; i++) {"
3962  " get_x(interceptor_obj);"
3963  "}"
3964  "get_x(interceptor_obj)");
3965  // Check that the interceptor was actually invoked.
3966  CHECK_EQ(result, v8_str("x"));
3967  }
3968 
3969  // Return to the original context and force some object to the slow case
3970  // to cause the NormalizedMapCache to verify.
3971  context1->Enter();
3972  CompileRun("var obj = { x : 0 }; delete obj.x;");
3973  context1->Exit();
3974 
3975  context1.Dispose();
3976 }
3977 
3978 
3979 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3980  const AccessorInfo& info) {
3981  // Set x on the prototype object and do not handle the get request.
3982  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3983  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3984  return v8::Handle<Value>();
3985 }
3986 
3987 
3988 // This is a regression test for http://crbug.com/20104. Map
3989 // transitions should not interfere with post interceptor lookup.
3990 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3991  v8::HandleScope scope;
3992  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3993  Local<v8::ObjectTemplate> instance_template
3994  = function_template->InstanceTemplate();
3995  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3996  LocalContext context;
3997  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3998  // Create an instance of F and introduce a map transition for x.
3999  CompileRun("var o = new F(); o.x = 23;");
4000  // Create an instance of F and invoke the getter. The result should be 23.
4001  Local<Value> result = CompileRun("o = new F(); o.x");
4002  CHECK_EQ(result->Int32Value(), 23);
4003 }
4004 
4005 
4006 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4007  const AccessorInfo& info) {
4009  if (index == 37) {
4010  return v8::Handle<Value>(v8_num(625));
4011  }
4012  return v8::Handle<Value>();
4013 }
4014 
4015 
4016 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4017  Local<Value> value,
4018  const AccessorInfo& info) {
4020  if (index == 39) {
4021  return value;
4022  }
4023  return v8::Handle<Value>();
4024 }
4025 
4026 
4027 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4028  v8::HandleScope scope;
4029  Local<ObjectTemplate> templ = ObjectTemplate::New();
4030  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4031  IndexedPropertySetter);
4032  LocalContext context;
4033  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4034  Local<Script> getter_script = Script::Compile(v8_str(
4035  "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4036  Local<Script> setter_script = Script::Compile(v8_str(
4037  "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4038  "obj[17] = 23;"
4039  "obj.foo;"));
4040  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4041  "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4042  "obj[39] = 47;"
4043  "obj.foo;")); // This setter should not run, due to the interceptor.
4044  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4045  "obj[37];"));
4046  Local<Value> result = getter_script->Run();
4047  CHECK_EQ(v8_num(5), result);
4048  result = setter_script->Run();
4049  CHECK_EQ(v8_num(23), result);
4050  result = interceptor_setter_script->Run();
4051  CHECK_EQ(v8_num(23), result);
4052  result = interceptor_getter_script->Run();
4053  CHECK_EQ(v8_num(625), result);
4054 }
4055 
4056 
4057 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4058  uint32_t index,
4059  const AccessorInfo& info) {
4061  if (index < 25) {
4062  return v8::Handle<Value>(v8_num(index));
4063  }
4064  return v8::Handle<Value>();
4065 }
4066 
4067 
4068 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4069  uint32_t index,
4070  Local<Value> value,
4071  const AccessorInfo& info) {
4073  if (index < 25) {
4074  return v8::Handle<Value>(v8_num(index));
4075  }
4076  return v8::Handle<Value>();
4077 }
4078 
4079 
4081  const AccessorInfo& info) {
4082  // Force the list of returned keys to be stored in a FastDoubleArray.
4083  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4084  "keys = new Array(); keys[125000] = 1;"
4085  "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4086  "keys.length = 25; keys;"));
4087  Local<Value> result = indexed_property_names_script->Run();
4088  return Local<v8::Array>(::v8::Array::Cast(*result));
4089 }
4090 
4091 
4092 // Make sure that the the interceptor code in the runtime properly handles
4093 // merging property name lists for double-array-backed arrays.
4094 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4095  v8::HandleScope scope;
4096  Local<ObjectTemplate> templ = ObjectTemplate::New();
4097  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4098  UnboxedDoubleIndexedPropertySetter,
4099  0,
4100  0,
4102  LocalContext context;
4103  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4104  // When obj is created, force it to be Stored in a FastDoubleArray.
4105  Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4106  "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4107  "key_count = 0; "
4108  "for (x in obj) {key_count++;};"
4109  "obj;"));
4110  Local<Value> result = create_unboxed_double_script->Run();
4111  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4112  Local<Script> key_count_check = Script::Compile(v8_str(
4113  "key_count;"));
4114  result = key_count_check->Run();
4115  CHECK_EQ(v8_num(40013), result);
4116 }
4117 
4118 
4120  const AccessorInfo& info) {
4121  // Force the list of returned keys to be stored in a Arguments object.
4122  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4123  "function f(w,x) {"
4124  " return arguments;"
4125  "}"
4126  "keys = f(0, 1, 2, 3);"
4127  "keys;"));
4128  Local<Value> result = indexed_property_names_script->Run();
4129  return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4130 }
4131 
4132 
4133 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4134  uint32_t index,
4135  const AccessorInfo& info) {
4137  if (index < 4) {
4138  return v8::Handle<Value>(v8_num(index));
4139  }
4140  return v8::Handle<Value>();
4141 }
4142 
4143 
4144 // Make sure that the the interceptor code in the runtime properly handles
4145 // merging property name lists for non-string arguments arrays.
4146 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4147  v8::HandleScope scope;
4148  Local<ObjectTemplate> templ = ObjectTemplate::New();
4149  templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4150  0,
4151  0,
4152  0,
4154  LocalContext context;
4155  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4156  Local<Script> create_args_script =
4157  Script::Compile(v8_str(
4158  "var key_count = 0;"
4159  "for (x in obj) {key_count++;} key_count;"));
4160  Local<Value> result = create_args_script->Run();
4161  CHECK_EQ(v8_num(4), result);
4162 }
4163 
4164 
4165 static v8::Handle<Value> IdentityIndexedPropertyGetter(
4166  uint32_t index,
4167  const AccessorInfo& info) {
4168  return v8::Integer::NewFromUnsigned(index);
4169 }
4170 
4171 
4172 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4173  v8::HandleScope scope;
4174  Local<ObjectTemplate> templ = ObjectTemplate::New();
4175  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4176 
4177  LocalContext context;
4178  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4179 
4180  // Check fast object case.
4181  const char* fast_case_code =
4182  "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4183  ExpectString(fast_case_code, "0");
4184 
4185  // Check slow case.
4186  const char* slow_case_code =
4187  "obj.x = 1; delete obj.x;"
4188  "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4189  ExpectString(slow_case_code, "1");
4190 }
4191 
4192 
4193 THREADED_TEST(IndexedInterceptorWithNoSetter) {
4194  v8::HandleScope scope;
4195  Local<ObjectTemplate> templ = ObjectTemplate::New();
4196  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4197 
4198  LocalContext context;
4199  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4200 
4201  const char* code =
4202  "try {"
4203  " obj[0] = 239;"
4204  " for (var i = 0; i < 100; i++) {"
4205  " var v = obj[0];"
4206  " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4207  " }"
4208  " 'PASSED'"
4209  "} catch(e) {"
4210  " e"
4211  "}";
4212  ExpectString(code, "PASSED");
4213 }
4214 
4215 
4216 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4217  v8::HandleScope scope;
4218  Local<ObjectTemplate> templ = ObjectTemplate::New();
4219  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4220 
4221  LocalContext context;
4222  Local<v8::Object> obj = templ->NewInstance();
4223  obj->TurnOnAccessCheck();
4224  context->Global()->Set(v8_str("obj"), obj);
4225 
4226  const char* code =
4227  "try {"
4228  " for (var i = 0; i < 100; i++) {"
4229  " var v = obj[0];"
4230  " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4231  " }"
4232  " 'PASSED'"
4233  "} catch(e) {"
4234  " e"
4235  "}";
4236  ExpectString(code, "PASSED");
4237 }
4238 
4239 
4240 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4241  i::FLAG_allow_natives_syntax = true;
4242  v8::HandleScope scope;
4243  Local<ObjectTemplate> templ = ObjectTemplate::New();
4244  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4245 
4246  LocalContext context;
4247  Local<v8::Object> obj = templ->NewInstance();
4248  context->Global()->Set(v8_str("obj"), obj);
4249 
4250  const char* code =
4251  "try {"
4252  " for (var i = 0; i < 100; i++) {"
4253  " var expected = i;"
4254  " if (i == 5) {"
4255  " %EnableAccessChecks(obj);"
4256  " expected = undefined;"
4257  " }"
4258  " var v = obj[i];"
4259  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4260  " if (i == 5) %DisableAccessChecks(obj);"
4261  " }"
4262  " 'PASSED'"
4263  "} catch(e) {"
4264  " e"
4265  "}";
4266  ExpectString(code, "PASSED");
4267 }
4268 
4269 
4270 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4271  v8::HandleScope scope;
4272  Local<ObjectTemplate> templ = ObjectTemplate::New();
4273  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4274 
4275  LocalContext context;
4276  Local<v8::Object> obj = templ->NewInstance();
4277  context->Global()->Set(v8_str("obj"), obj);
4278 
4279  const char* code =
4280  "try {"
4281  " for (var i = 0; i < 100; i++) {"
4282  " var v = obj[i];"
4283  " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4284  " }"
4285  " 'PASSED'"
4286  "} catch(e) {"
4287  " e"
4288  "}";
4289  ExpectString(code, "PASSED");
4290 }
4291 
4292 
4293 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4294  v8::HandleScope scope;
4295  Local<ObjectTemplate> templ = ObjectTemplate::New();
4296  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4297 
4298  LocalContext context;
4299  Local<v8::Object> obj = templ->NewInstance();
4300  context->Global()->Set(v8_str("obj"), obj);
4301 
4302  const char* code =
4303  "try {"
4304  " for (var i = 0; i < 100; i++) {"
4305  " var expected = i;"
4306  " var key = i;"
4307  " if (i == 25) {"
4308  " key = -1;"
4309  " expected = undefined;"
4310  " }"
4311  " if (i == 50) {"
4312  " /* probe minimal Smi number on 32-bit platforms */"
4313  " key = -(1 << 30);"
4314  " expected = undefined;"
4315  " }"
4316  " if (i == 75) {"
4317  " /* probe minimal Smi number on 64-bit platforms */"
4318  " key = 1 << 31;"
4319  " expected = undefined;"
4320  " }"
4321  " var v = obj[key];"
4322  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4323  " }"
4324  " 'PASSED'"
4325  "} catch(e) {"
4326  " e"
4327  "}";
4328  ExpectString(code, "PASSED");
4329 }
4330 
4331 
4332 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4333  v8::HandleScope scope;
4334  Local<ObjectTemplate> templ = ObjectTemplate::New();
4335  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4336 
4337  LocalContext context;
4338  Local<v8::Object> obj = templ->NewInstance();
4339  context->Global()->Set(v8_str("obj"), obj);
4340 
4341  const char* code =
4342  "try {"
4343  " for (var i = 0; i < 100; i++) {"
4344  " var expected = i;"
4345  " var key = i;"
4346  " if (i == 50) {"
4347  " key = 'foobar';"
4348  " expected = undefined;"
4349  " }"
4350  " var v = obj[key];"
4351  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4352  " }"
4353  " 'PASSED'"
4354  "} catch(e) {"
4355  " e"
4356  "}";
4357  ExpectString(code, "PASSED");
4358 }
4359 
4360 
4361 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4362  v8::HandleScope scope;
4363  Local<ObjectTemplate> templ = ObjectTemplate::New();
4364  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4365 
4366  LocalContext context;
4367  Local<v8::Object> obj = templ->NewInstance();
4368  context->Global()->Set(v8_str("obj"), obj);
4369 
4370  const char* code =
4371  "var original = obj;"
4372  "try {"
4373  " for (var i = 0; i < 100; i++) {"
4374  " var expected = i;"
4375  " if (i == 50) {"
4376  " obj = {50: 'foobar'};"
4377  " expected = 'foobar';"
4378  " }"
4379  " var v = obj[i];"
4380  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4381  " if (i == 50) obj = original;"
4382  " }"
4383  " 'PASSED'"
4384  "} catch(e) {"
4385  " e"
4386  "}";
4387  ExpectString(code, "PASSED");
4388 }
4389 
4390 
4391 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4392  v8::HandleScope scope;
4393  Local<ObjectTemplate> templ = ObjectTemplate::New();
4394  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4395 
4396  LocalContext context;
4397  Local<v8::Object> obj = templ->NewInstance();
4398  context->Global()->Set(v8_str("obj"), obj);
4399 
4400  const char* code =
4401  "var original = obj;"
4402  "try {"
4403  " for (var i = 0; i < 100; i++) {"
4404  " var expected = i;"
4405  " if (i == 5) {"
4406  " obj = 239;"
4407  " expected = undefined;"
4408  " }"
4409  " var v = obj[i];"
4410  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4411  " if (i == 5) obj = original;"
4412  " }"
4413  " 'PASSED'"
4414  "} catch(e) {"
4415  " e"
4416  "}";
4417  ExpectString(code, "PASSED");
4418 }
4419 
4420 
4421 THREADED_TEST(IndexedInterceptorOnProto) {
4422  v8::HandleScope scope;
4423  Local<ObjectTemplate> templ = ObjectTemplate::New();
4424  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4425 
4426  LocalContext context;
4427  Local<v8::Object> obj = templ->NewInstance();
4428  context->Global()->Set(v8_str("obj"), obj);
4429 
4430  const char* code =
4431  "var o = {__proto__: obj};"
4432  "try {"
4433  " for (var i = 0; i < 100; i++) {"
4434  " var v = o[i];"
4435  " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4436  " }"
4437  " 'PASSED'"
4438  "} catch(e) {"
4439  " e"
4440  "}";
4441  ExpectString(code, "PASSED");
4442 }
4443 
4444 
4445 THREADED_TEST(MultiContexts) {
4446  v8::HandleScope scope;
4447  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4448  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4449 
4450  Local<String> password = v8_str("Password");
4451 
4452  // Create an environment
4453  LocalContext context0(0, templ);
4454  context0->SetSecurityToken(password);
4455  v8::Handle<v8::Object> global0 = context0->Global();
4456  global0->Set(v8_str("custom"), v8_num(1234));
4457  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4458 
4459  // Create an independent environment
4460  LocalContext context1(0, templ);
4461  context1->SetSecurityToken(password);
4462  v8::Handle<v8::Object> global1 = context1->Global();
4463  global1->Set(v8_str("custom"), v8_num(1234));
4464  CHECK_NE(global0, global1);
4465  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4466  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4467 
4468  // Now create a new context with the old global
4469  LocalContext context2(0, templ, global1);
4470  context2->SetSecurityToken(password);
4471  v8::Handle<v8::Object> global2 = context2->Global();
4472  CHECK_EQ(global1, global2);
4473  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4474  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4475 }
4476 
4477 
4478 THREADED_TEST(FunctionPrototypeAcrossContexts) {
4479  // Make sure that functions created by cloning boilerplates cannot
4480  // communicate through their __proto__ field.
4481 
4482  v8::HandleScope scope;
4483 
4484  LocalContext env0;
4485  v8::Handle<v8::Object> global0 =
4486  env0->Global();
4487  v8::Handle<v8::Object> object0 =
4488  global0->Get(v8_str("Object")).As<v8::Object>();
4489  v8::Handle<v8::Object> tostring0 =
4490  object0->Get(v8_str("toString")).As<v8::Object>();
4491  v8::Handle<v8::Object> proto0 =
4492  tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4493  proto0->Set(v8_str("custom"), v8_num(1234));
4494 
4495  LocalContext env1;
4496  v8::Handle<v8::Object> global1 =
4497  env1->Global();
4498  v8::Handle<v8::Object> object1 =
4499  global1->Get(v8_str("Object")).As<v8::Object>();
4500  v8::Handle<v8::Object> tostring1 =
4501  object1->Get(v8_str("toString")).As<v8::Object>();
4502  v8::Handle<v8::Object> proto1 =
4503  tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4504  CHECK(!proto1->Has(v8_str("custom")));
4505 }
4506 
4507 
4508 THREADED_TEST(Regress892105) {
4509  // Make sure that object and array literals created by cloning
4510  // boilerplates cannot communicate through their __proto__
4511  // field. This is rather difficult to check, but we try to add stuff
4512  // to Object.prototype and Array.prototype and create a new
4513  // environment. This should succeed.
4514 
4515  v8::HandleScope scope;
4516 
4517  Local<String> source = v8_str("Object.prototype.obj = 1234;"
4518  "Array.prototype.arr = 4567;"
4519  "8901");
4520 
4521  LocalContext env0;
4522  Local<Script> script0 = Script::Compile(source);
4523  CHECK_EQ(8901.0, script0->Run()->NumberValue());
4524 
4525  LocalContext env1;
4526  Local<Script> script1 = Script::Compile(source);
4527  CHECK_EQ(8901.0, script1->Run()->NumberValue());
4528 }
4529 
4530 
4531 THREADED_TEST(UndetectableObject) {
4532  v8::HandleScope scope;
4533  LocalContext env;
4534 
4535  Local<v8::FunctionTemplate> desc =
4537  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4538 
4539  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4540  env->Global()->Set(v8_str("undetectable"), obj);
4541 
4542  ExpectString("undetectable.toString()", "[object Object]");
4543  ExpectString("typeof undetectable", "undefined");
4544  ExpectString("typeof(undetectable)", "undefined");
4545  ExpectBoolean("typeof undetectable == 'undefined'", true);
4546  ExpectBoolean("typeof undetectable == 'object'", false);
4547  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4548  ExpectBoolean("!undetectable", true);
4549 
4550  ExpectObject("true&&undetectable", obj);
4551  ExpectBoolean("false&&undetectable", false);
4552  ExpectBoolean("true||undetectable", true);
4553  ExpectObject("false||undetectable", obj);
4554 
4555  ExpectObject("undetectable&&true", obj);
4556  ExpectObject("undetectable&&false", obj);
4557  ExpectBoolean("undetectable||true", true);
4558  ExpectBoolean("undetectable||false", false);
4559 
4560  ExpectBoolean("undetectable==null", true);
4561  ExpectBoolean("null==undetectable", true);
4562  ExpectBoolean("undetectable==undefined", true);
4563  ExpectBoolean("undefined==undetectable", true);
4564  ExpectBoolean("undetectable==undetectable", true);
4565 
4566 
4567  ExpectBoolean("undetectable===null", false);
4568  ExpectBoolean("null===undetectable", false);
4569  ExpectBoolean("undetectable===undefined", false);
4570  ExpectBoolean("undefined===undetectable", false);
4571  ExpectBoolean("undetectable===undetectable", true);
4572 }
4573 
4574 
4575 THREADED_TEST(VoidLiteral) {
4576  v8::HandleScope scope;
4577  LocalContext env;
4578 
4579  Local<v8::FunctionTemplate> desc =
4581  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4582 
4583  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4584  env->Global()->Set(v8_str("undetectable"), obj);
4585 
4586  ExpectBoolean("undefined == void 0", true);
4587  ExpectBoolean("undetectable == void 0", true);
4588  ExpectBoolean("null == void 0", true);
4589  ExpectBoolean("undefined === void 0", true);
4590  ExpectBoolean("undetectable === void 0", false);
4591  ExpectBoolean("null === void 0", false);
4592 
4593  ExpectBoolean("void 0 == undefined", true);
4594  ExpectBoolean("void 0 == undetectable", true);
4595  ExpectBoolean("void 0 == null", true);
4596  ExpectBoolean("void 0 === undefined", true);
4597  ExpectBoolean("void 0 === undetectable", false);
4598  ExpectBoolean("void 0 === null", false);
4599 
4600  ExpectString("(function() {"
4601  " try {"
4602  " return x === void 0;"
4603  " } catch(e) {"
4604  " return e.toString();"
4605  " }"
4606  "})()",
4607  "ReferenceError: x is not defined");
4608  ExpectString("(function() {"
4609  " try {"
4610  " return void 0 === x;"
4611  " } catch(e) {"
4612  " return e.toString();"
4613  " }"
4614  "})()",
4615  "ReferenceError: x is not defined");
4616 }
4617 
4618 
4619 THREADED_TEST(ExtensibleOnUndetectable) {
4620  v8::HandleScope scope;
4621  LocalContext env;
4622 
4623  Local<v8::FunctionTemplate> desc =
4625  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4626 
4627  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4628  env->Global()->Set(v8_str("undetectable"), obj);
4629 
4630  Local<String> source = v8_str("undetectable.x = 42;"
4631  "undetectable.x");
4632 
4633  Local<Script> script = Script::Compile(source);
4634 
4635  CHECK_EQ(v8::Integer::New(42), script->Run());
4636 
4637  ExpectBoolean("Object.isExtensible(undetectable)", true);
4638 
4639  source = v8_str("Object.preventExtensions(undetectable);");
4640  script = Script::Compile(source);
4641  script->Run();
4642  ExpectBoolean("Object.isExtensible(undetectable)", false);
4643 
4644  source = v8_str("undetectable.y = 2000;");
4645  script = Script::Compile(source);
4646  script->Run();
4647  ExpectBoolean("undetectable.y == undefined", true);
4648 }
4649 
4650 
4651 
4652 THREADED_TEST(UndetectableString) {
4653  v8::HandleScope scope;
4654  LocalContext env;
4655 
4656  Local<String> obj = String::NewUndetectable("foo");
4657  env->Global()->Set(v8_str("undetectable"), obj);
4658 
4659  ExpectString("undetectable", "foo");
4660  ExpectString("typeof undetectable", "undefined");
4661  ExpectString("typeof(undetectable)", "undefined");
4662  ExpectBoolean("typeof undetectable == 'undefined'", true);
4663  ExpectBoolean("typeof undetectable == 'string'", false);
4664  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4665  ExpectBoolean("!undetectable", true);
4666 
4667  ExpectObject("true&&undetectable", obj);
4668  ExpectBoolean("false&&undetectable", false);
4669  ExpectBoolean("true||undetectable", true);
4670  ExpectObject("false||undetectable", obj);
4671 
4672  ExpectObject("undetectable&&true", obj);
4673  ExpectObject("undetectable&&false", obj);
4674  ExpectBoolean("undetectable||true", true);
4675  ExpectBoolean("undetectable||false", false);
4676 
4677  ExpectBoolean("undetectable==null", true);
4678  ExpectBoolean("null==undetectable", true);
4679  ExpectBoolean("undetectable==undefined", true);
4680  ExpectBoolean("undefined==undetectable", true);
4681  ExpectBoolean("undetectable==undetectable", true);
4682 
4683 
4684  ExpectBoolean("undetectable===null", false);
4685  ExpectBoolean("null===undetectable", false);
4686  ExpectBoolean("undetectable===undefined", false);
4687  ExpectBoolean("undefined===undetectable", false);
4688  ExpectBoolean("undetectable===undetectable", true);
4689 }
4690 
4691 
4692 TEST(UndetectableOptimized) {
4693  i::FLAG_allow_natives_syntax = true;
4694  v8::HandleScope scope;
4695  LocalContext env;
4696 
4697  Local<String> obj = String::NewUndetectable("foo");
4698  env->Global()->Set(v8_str("undetectable"), obj);
4699  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4700 
4701  ExpectString(
4702  "function testBranch() {"
4703  " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4704  " if (%_IsUndetectableObject(detectable)) throw 2;"
4705  "}\n"
4706  "function testBool() {"
4707  " var b1 = !%_IsUndetectableObject(undetectable);"
4708  " var b2 = %_IsUndetectableObject(detectable);"
4709  " if (b1) throw 3;"
4710  " if (b2) throw 4;"
4711  " return b1 == b2;"
4712  "}\n"
4713  "%OptimizeFunctionOnNextCall(testBranch);"
4714  "%OptimizeFunctionOnNextCall(testBool);"
4715  "for (var i = 0; i < 10; i++) {"
4716  " testBranch();"
4717  " testBool();"
4718  "}\n"
4719  "\"PASS\"",
4720  "PASS");
4721 }
4722 
4723 
4724 template <typename T> static void USE(T) { }
4725 
4726 
4727 // This test is not intended to be run, just type checked.
4728 static inline void PersistentHandles() {
4729  USE(PersistentHandles);
4730  Local<String> str = v8_str("foo");
4732  USE(p_str);
4733  Local<Script> scr = Script::Compile(v8_str(""));
4735  USE(p_scr);
4736  Local<ObjectTemplate> templ = ObjectTemplate::New();
4739  USE(p_templ);
4740 }
4741 
4742 
4743 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4745  return v8::Undefined();
4746 }
4747 
4748 
4749 THREADED_TEST(GlobalObjectTemplate) {
4750  v8::HandleScope handle_scope;
4751  Local<ObjectTemplate> global_template = ObjectTemplate::New();
4752  global_template->Set(v8_str("JSNI_Log"),
4753  v8::FunctionTemplate::New(HandleLogDelegator));
4754  v8::Persistent<Context> context = Context::New(0, global_template);
4755  Context::Scope context_scope(context);
4756  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4757  context.Dispose();
4758 }
4759 
4760 
4761 static const char* kSimpleExtensionSource =
4762  "function Foo() {"
4763  " return 4;"
4764  "}";
4765 
4766 
4767 THREADED_TEST(SimpleExtensions) {
4768  v8::HandleScope handle_scope;
4769  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4770  const char* extension_names[] = { "simpletest" };
4771  v8::ExtensionConfiguration extensions(1, extension_names);
4772  v8::Handle<Context> context = Context::New(&extensions);
4773  Context::Scope lock(context);
4774  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4775  CHECK_EQ(result, v8::Integer::New(4));
4776 }
4777 
4778 
4779 THREADED_TEST(NullExtensions) {
4780  v8::HandleScope handle_scope;
4781  v8::RegisterExtension(new Extension("nulltest", NULL));
4782  const char* extension_names[] = { "nulltest" };
4783  v8::ExtensionConfiguration extensions(1, extension_names);
4784  v8::Handle<Context> context = Context::New(&extensions);
4785  Context::Scope lock(context);
4786  v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
4787  CHECK_EQ(result, v8::Integer::New(4));
4788 }
4789 
4790 
4791 static const char* kEmbeddedExtensionSource =
4792  "function Ret54321(){return 54321;}~~@@$"
4793  "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4794 static const int kEmbeddedExtensionSourceValidLen = 34;
4795 
4796 
4797 THREADED_TEST(ExtensionMissingSourceLength) {
4798  v8::HandleScope handle_scope;
4799  v8::RegisterExtension(new Extension("srclentest_fail",
4800  kEmbeddedExtensionSource));
4801  const char* extension_names[] = { "srclentest_fail" };
4802  v8::ExtensionConfiguration extensions(1, extension_names);
4803  v8::Handle<Context> context = Context::New(&extensions);
4804  CHECK_EQ(0, *context);
4805 }
4806 
4807 
4808 THREADED_TEST(ExtensionWithSourceLength) {
4809  for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4810  source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4811  v8::HandleScope handle_scope;
4812  i::ScopedVector<char> extension_name(32);
4813  i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4814  v8::RegisterExtension(new Extension(extension_name.start(),
4815  kEmbeddedExtensionSource, 0, 0,
4816  source_len));
4817  const char* extension_names[1] = { extension_name.start() };
4818  v8::ExtensionConfiguration extensions(1, extension_names);
4819  v8::Handle<Context> context = Context::New(&extensions);
4820  if (source_len == kEmbeddedExtensionSourceValidLen) {
4821  Context::Scope lock(context);
4822  v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4823  CHECK_EQ(v8::Integer::New(54321), result);
4824  } else {
4825  // Anything but exactly the right length should fail to compile.
4826  CHECK_EQ(0, *context);
4827  }
4828  }
4829 }
4830 
4831 
4832 static const char* kEvalExtensionSource1 =
4833  "function UseEval1() {"
4834  " var x = 42;"
4835  " return eval('x');"
4836  "}";
4837 
4838 
4839 static const char* kEvalExtensionSource2 =
4840  "(function() {"
4841  " var x = 42;"
4842  " function e() {"
4843  " return eval('x');"
4844  " }"
4845  " this.UseEval2 = e;"
4846  "})()";
4847 
4848 
4849 THREADED_TEST(UseEvalFromExtension) {
4850  v8::HandleScope handle_scope;
4851  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4852  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4853  const char* extension_names[] = { "evaltest1", "evaltest2" };
4854  v8::ExtensionConfiguration extensions(2, extension_names);
4855  v8::Handle<Context> context = Context::New(&extensions);
4856  Context::Scope lock(context);
4857  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4858  CHECK_EQ(result, v8::Integer::New(42));
4859  result = Script::Compile(v8_str("UseEval2()"))->Run();
4860  CHECK_EQ(result, v8::Integer::New(42));
4861 }
4862 
4863 
4864 static const char* kWithExtensionSource1 =
4865  "function UseWith1() {"
4866  " var x = 42;"
4867  " with({x:87}) { return x; }"
4868  "}";
4869 
4870 
4871 
4872 static const char* kWithExtensionSource2 =
4873  "(function() {"
4874  " var x = 42;"
4875  " function e() {"
4876  " with ({x:87}) { return x; }"
4877  " }"
4878  " this.UseWith2 = e;"
4879  "})()";
4880 
4881 
4882 THREADED_TEST(UseWithFromExtension) {
4883  v8::HandleScope handle_scope;
4884  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4885  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4886  const char* extension_names[] = { "withtest1", "withtest2" };
4887  v8::ExtensionConfiguration extensions(2, extension_names);
4888  v8::Handle<Context> context = Context::New(&extensions);
4889  Context::Scope lock(context);
4890  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4891  CHECK_EQ(result, v8::Integer::New(87));
4892  result = Script::Compile(v8_str("UseWith2()"))->Run();
4893  CHECK_EQ(result, v8::Integer::New(87));
4894 }
4895 
4896 
4897 THREADED_TEST(AutoExtensions) {
4898  v8::HandleScope handle_scope;
4899  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4900  extension->set_auto_enable(true);
4901  v8::RegisterExtension(extension);
4902  v8::Handle<Context> context = Context::New();
4903  Context::Scope lock(context);
4904  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4905  CHECK_EQ(result, v8::Integer::New(4));
4906 }
4907 
4908 
4909 static const char* kSyntaxErrorInExtensionSource =
4910  "[";
4911 
4912 
4913 // Test that a syntax error in an extension does not cause a fatal
4914 // error but results in an empty context.
4915 THREADED_TEST(SyntaxErrorExtensions) {
4916  v8::HandleScope handle_scope;
4917  v8::RegisterExtension(new Extension("syntaxerror",
4918  kSyntaxErrorInExtensionSource));
4919  const char* extension_names[] = { "syntaxerror" };
4920  v8::ExtensionConfiguration extensions(1, extension_names);
4921  v8::Handle<Context> context = Context::New(&extensions);
4922  CHECK(context.IsEmpty());
4923 }
4924 
4925 
4926 static const char* kExceptionInExtensionSource =
4927  "throw 42";
4928 
4929 
4930 // Test that an exception when installing an extension does not cause
4931 // a fatal error but results in an empty context.
4932 THREADED_TEST(ExceptionExtensions) {
4933  v8::HandleScope handle_scope;
4934  v8::RegisterExtension(new Extension("exception",
4935  kExceptionInExtensionSource));
4936  const char* extension_names[] = { "exception" };
4937  v8::ExtensionConfiguration extensions(1, extension_names);
4938  v8::Handle<Context> context = Context::New(&extensions);
4939  CHECK(context.IsEmpty());
4940 }
4941 
4942 
4943 static const char* kNativeCallInExtensionSource =
4944  "function call_runtime_last_index_of(x) {"
4945  " return %StringLastIndexOf(x, 'bob', 10);"
4946  "}";
4947 
4948 
4949 static const char* kNativeCallTest =
4950  "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4951 
4952 // Test that a native runtime calls are supported in extensions.
4953 THREADED_TEST(NativeCallInExtensions) {
4954  v8::HandleScope handle_scope;
4955  v8::RegisterExtension(new Extension("nativecall",
4956  kNativeCallInExtensionSource));
4957  const char* extension_names[] = { "nativecall" };
4958  v8::ExtensionConfiguration extensions(1, extension_names);
4959  v8::Handle<Context> context = Context::New(&extensions);
4960  Context::Scope lock(context);
4961  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4962  CHECK_EQ(result, v8::Integer::New(3));
4963 }
4964 
4965 
4966 class NativeFunctionExtension : public Extension {
4967  public:
4968  NativeFunctionExtension(const char* name,
4969  const char* source,
4971  : Extension(name, source),
4972  function_(fun) { }
4973 
4975  v8::Handle<v8::String> name) {
4976  return v8::FunctionTemplate::New(function_);
4977  }
4978 
4980  if (args.Length() >= 1) return (args[0]);
4981  return v8::Undefined();
4982  }
4983  private:
4984  v8::InvocationCallback function_;
4985 };
4986 
4987 
4988 THREADED_TEST(NativeFunctionDeclaration) {
4989  v8::HandleScope handle_scope;
4990  const char* name = "nativedecl";
4992  "native function foo();"));
4993  const char* extension_names[] = { name };
4994  v8::ExtensionConfiguration extensions(1, extension_names);
4995  v8::Handle<Context> context = Context::New(&extensions);
4996  Context::Scope lock(context);
4997  v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4998  CHECK_EQ(result, v8::Integer::New(42));
4999 }
5000 
5001 
5002 THREADED_TEST(NativeFunctionDeclarationError) {
5003  v8::HandleScope handle_scope;
5004  const char* name = "nativedeclerr";
5005  // Syntax error in extension code.
5007  "native\nfunction foo();"));
5008  const char* extension_names[] = { name };
5009  v8::ExtensionConfiguration extensions(1, extension_names);
5010  v8::Handle<Context> context(Context::New(&extensions));
5011  CHECK(context.IsEmpty());
5012 }
5013 
5014 
5015 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5016  v8::HandleScope handle_scope;
5017  const char* name = "nativedeclerresc";
5018  // Syntax error in extension code - escape code in "native" means that
5019  // it's not treated as a keyword.
5021  name,
5022  "nativ\\u0065 function foo();"));
5023  const char* extension_names[] = { name };
5024  v8::ExtensionConfiguration extensions(1, extension_names);
5025  v8::Handle<Context> context(Context::New(&extensions));
5026  CHECK(context.IsEmpty());
5027 }
5028 
5029 
5030 static void CheckDependencies(const char* name, const char* expected) {
5031  v8::HandleScope handle_scope;
5032  v8::ExtensionConfiguration config(1, &name);
5033  LocalContext context(&config);
5034  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5035 }
5036 
5037 
5038 /*
5039  * Configuration:
5040  *
5041  * /-- B <--\
5042  * A <- -- D <-- E
5043  * \-- C <--/
5044  */
5045 THREADED_TEST(ExtensionDependency) {
5046  static const char* kEDeps[] = { "D" };
5047  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5048  static const char* kDDeps[] = { "B", "C" };
5049  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5050  static const char* kBCDeps[] = { "A" };
5051  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5052  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5053  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5054  CheckDependencies("A", "undefinedA");
5055  CheckDependencies("B", "undefinedAB");
5056  CheckDependencies("C", "undefinedAC");
5057  CheckDependencies("D", "undefinedABCD");
5058  CheckDependencies("E", "undefinedABCDE");
5059  v8::HandleScope handle_scope;
5060  static const char* exts[2] = { "C", "E" };
5061  v8::ExtensionConfiguration config(2, exts);
5062  LocalContext context(&config);
5063  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5064 }
5065 
5066 
5067 static const char* kExtensionTestScript =
5068  "native function A();"
5069  "native function B();"
5070  "native function C();"
5071  "function Foo(i) {"
5072  " if (i == 0) return A();"
5073  " if (i == 1) return B();"
5074  " if (i == 2) return C();"
5075  "}";
5076 
5077 
5078 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5080  if (args.IsConstructCall()) {
5081  args.This()->Set(v8_str("data"), args.Data());
5082  return v8::Null();
5083  }
5084  return args.Data();
5085 }
5086 
5087 
5088 class FunctionExtension : public Extension {
5089  public:
5090  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5092  v8::Handle<String> name);
5093 };
5094 
5095 
5096 static int lookup_count = 0;
5098  v8::Handle<String> name) {
5099  lookup_count++;
5100  if (name->Equals(v8_str("A"))) {
5101  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5102  } else if (name->Equals(v8_str("B"))) {
5103  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5104  } else if (name->Equals(v8_str("C"))) {
5105  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5106  } else {
5108  }
5109 }
5110 
5111 
5112 THREADED_TEST(FunctionLookup) {
5114  v8::HandleScope handle_scope;
5115  static const char* exts[1] = { "functiontest" };
5116  v8::ExtensionConfiguration config(1, exts);
5117  LocalContext context(&config);
5118  CHECK_EQ(3, lookup_count);
5119  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5120  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5121  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5122 }
5123 
5124 
5125 THREADED_TEST(NativeFunctionConstructCall) {
5127  v8::HandleScope handle_scope;
5128  static const char* exts[1] = { "functiontest" };
5129  v8::ExtensionConfiguration config(1, exts);
5130  LocalContext context(&config);
5131  for (int i = 0; i < 10; i++) {
5132  // Run a few times to ensure that allocation of objects doesn't
5133  // change behavior of a constructor function.
5135  Script::Compile(v8_str("(new A()).data"))->Run());
5137  Script::Compile(v8_str("(new B()).data"))->Run());
5139  Script::Compile(v8_str("(new C()).data"))->Run());
5140  }
5141 }
5142 
5143 
5144 static const char* last_location;
5145 static const char* last_message;
5146 void StoringErrorCallback(const char* location, const char* message) {
5147  if (last_location == NULL) {
5148  last_location = location;
5149  last_message = message;
5150  }
5151 }
5152 
5153 
5154 // ErrorReporting creates a circular extensions configuration and
5155 // tests that the fatal error handler gets called. This renders V8
5156 // unusable and therefore this test cannot be run in parallel.
5157 TEST(ErrorReporting) {
5159  static const char* aDeps[] = { "B" };
5160  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5161  static const char* bDeps[] = { "A" };
5162  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5163  last_location = NULL;
5164  v8::ExtensionConfiguration config(1, bDeps);
5165  v8::Handle<Context> context = Context::New(&config);
5166  CHECK(context.IsEmpty());
5167  CHECK_NE(last_location, NULL);
5168 }
5169 
5170 
5171 static const char* js_code_causing_huge_string_flattening =
5172  "var str = 'X';"
5173  "for (var i = 0; i < 30; i++) {"
5174  " str = str + str;"
5175  "}"
5176  "str.match(/X/);";
5177 
5178 
5179 void OOMCallback(const char* location, const char* message) {
5180  exit(0);
5181 }
5182 
5183 
5184 TEST(RegexpOutOfMemory) {
5185  // Execute a script that causes out of memory when flattening a string.
5186  v8::HandleScope scope;
5188  LocalContext context;
5189  Local<Script> script =
5190  Script::Compile(String::New(js_code_causing_huge_string_flattening));
5191  last_location = NULL;
5192  script->Run();
5193 
5194  CHECK(false); // Should not return.
5195 }
5196 
5197 
5198 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5199  v8::Handle<Value> data) {
5200  CHECK(message->GetScriptResourceName()->IsUndefined());
5202  message->GetLineNumber();
5203  message->GetSourceLine();
5204 }
5205 
5206 
5207 THREADED_TEST(ErrorWithMissingScriptInfo) {
5208  v8::HandleScope scope;
5209  LocalContext context;
5210  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5211  Script::Compile(v8_str("throw Error()"))->Run();
5212  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5213 }
5214 
5215 
5217 
5218 class Snorkel {
5219  public:
5220  Snorkel() { index_ = global_index++; }
5221  int index_;
5222 };
5223 
5224 class Whammy {
5225  public:
5227  cursor_ = 0;
5228  }
5230  script_.Dispose();
5231  }
5233  if (script_.IsEmpty())
5234  script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5235  return Local<Script>(*script_);
5236  }
5237 
5238  public:
5239  static const int kObjectCount = 256;
5240  int cursor_;
5243 };
5244 
5245 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5246  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5247  delete snorkel;
5248  obj.ClearWeak();
5249 }
5250 
5252  const AccessorInfo& info) {
5253  Whammy* whammy =
5254  static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5255 
5256  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5257 
5260  if (!prev.IsEmpty()) {
5261  prev->Set(v8_str("next"), obj);
5262  prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5263  whammy->objects_[whammy->cursor_].Clear();
5264  }
5265  whammy->objects_[whammy->cursor_] = global;
5266  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5267  return whammy->getScript()->Run();
5268 }
5269 
5270 THREADED_TEST(WeakReference) {
5271  v8::HandleScope handle_scope;
5273  Whammy* whammy = new Whammy();
5275  0, 0, 0, 0,
5276  v8::External::New(whammy));
5277  const char* extension_list[] = { "v8/gc" };
5278  v8::ExtensionConfiguration extensions(1, extension_list);
5279  v8::Persistent<Context> context = Context::New(&extensions);
5280  Context::Scope context_scope(context);
5281 
5282  v8::Handle<v8::Object> interceptor = templ->NewInstance();
5283  context->Global()->Set(v8_str("whammy"), interceptor);
5284  const char* code =
5285  "var last;"
5286  "for (var i = 0; i < 10000; i++) {"
5287  " var obj = whammy.length;"
5288  " if (last) last.next = obj;"
5289  " last = obj;"
5290  "}"
5291  "gc();"
5292  "4";
5293  v8::Handle<Value> result = CompileRun(code);
5294  CHECK_EQ(4.0, result->NumberValue());
5295  delete whammy;
5296  context.Dispose();
5297 }
5298 
5299 
5300 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5301  obj.Dispose();
5302  obj.Clear();
5303  *(reinterpret_cast<bool*>(data)) = true;
5304 }
5305 
5306 
5307 THREADED_TEST(IndependentWeakHandle) {
5308  v8::Persistent<Context> context = Context::New();
5309  Context::Scope context_scope(context);
5310 
5311  v8::Persistent<v8::Object> object_a;
5312 
5313  {
5314  v8::HandleScope handle_scope;
5316  }
5317 
5318  bool object_a_disposed = false;
5319  object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5320  CHECK(!object_a.IsIndependent());
5321  object_a.MarkIndependent();
5322  CHECK(object_a.IsIndependent());
5323  HEAP->PerformScavenge();
5324  CHECK(object_a_disposed);
5325 }
5326 
5327 
5328 static void InvokeScavenge() {
5329  HEAP->PerformScavenge();
5330 }
5331 
5332 
5333 static void InvokeMarkSweep() {
5334  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5335 }
5336 
5337 
5338 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5339  obj.Dispose();
5340  obj.Clear();
5341  *(reinterpret_cast<bool*>(data)) = true;
5342  InvokeScavenge();
5343 }
5344 
5345 
5346 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5347  obj.Dispose();
5348  obj.Clear();
5349  *(reinterpret_cast<bool*>(data)) = true;
5350  InvokeMarkSweep();
5351 }
5352 
5353 
5354 THREADED_TEST(GCFromWeakCallbacks) {
5355  v8::Persistent<Context> context = Context::New();
5356  Context::Scope context_scope(context);
5357 
5358  static const int kNumberOfGCTypes = 2;
5359  v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5360  {&ForceScavenge, &ForceMarkSweep};
5361 
5362  typedef void (*GCInvoker)();
5363  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5364 
5365  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5366  for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5368  {
5369  v8::HandleScope handle_scope;
5371  }
5372  bool disposed = false;
5373  object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5374  object.MarkIndependent();
5375  invoke_gc[outer_gc]();
5376  CHECK(disposed);
5377  }
5378  }
5379 }
5380 
5381 
5382 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5383  obj.ClearWeak();
5384  *(reinterpret_cast<bool*>(data)) = true;
5385 }
5386 
5387 
5388 THREADED_TEST(IndependentHandleRevival) {
5389  v8::Persistent<Context> context = Context::New();
5390  Context::Scope context_scope(context);
5391 
5393  {
5394  v8::HandleScope handle_scope;
5396  object->Set(v8_str("x"), v8::Integer::New(1));
5397  v8::Local<String> y_str = v8_str("y");
5398  object->Set(y_str, y_str);
5399  }
5400  bool revived = false;
5401  object.MakeWeak(&revived, &RevivingCallback);
5402  object.MarkIndependent();
5403  HEAP->PerformScavenge();
5404  CHECK(revived);
5405  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
5406  {
5407  v8::HandleScope handle_scope;
5408  v8::Local<String> y_str = v8_str("y");
5409  CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5410  CHECK(object->Get(y_str)->Equals(y_str));
5411  }
5412 }
5413 
5414 
5416 
5417 
5418 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5420  CHECK_EQ(args_fun, args.Callee());
5421  CHECK_EQ(3, args.Length());
5422  CHECK_EQ(v8::Integer::New(1), args[0]);
5423  CHECK_EQ(v8::Integer::New(2), args[1]);
5424  CHECK_EQ(v8::Integer::New(3), args[2]);
5425  CHECK_EQ(v8::Undefined(), args[3]);
5426  v8::HandleScope scope;
5427  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5428  return v8::Undefined();
5429 }
5430 
5431 
5432 THREADED_TEST(Arguments) {
5433  v8::HandleScope scope;
5434  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5435  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5436  LocalContext context(NULL, global);
5437  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5438  v8_compile("f(1, 2, 3)")->Run();
5439 }
5440 
5441 
5442 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5443  const AccessorInfo&) {
5444  return v8::Handle<Value>();
5445 }
5446 
5447 
5448 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5449  const AccessorInfo&) {
5450  return v8::Handle<Value>();
5451 }
5452 
5453 
5454 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5455  const AccessorInfo&) {
5456  if (!name->Equals(v8_str("foo"))) {
5457  return v8::Handle<v8::Boolean>(); // not intercepted
5458  }
5459 
5460  return v8::False(); // intercepted, and don't delete the property
5461 }
5462 
5463 
5464 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5465  if (index != 2) {
5466  return v8::Handle<v8::Boolean>(); // not intercepted
5467  }
5468 
5469  return v8::False(); // intercepted, and don't delete the property
5470 }
5471 
5472 
5473 THREADED_TEST(Deleter) {
5474  v8::HandleScope scope;
5475  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5476  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5477  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5478  LocalContext context;
5479  context->Global()->Set(v8_str("k"), obj->NewInstance());
5480  CompileRun(
5481  "k.foo = 'foo';"
5482  "k.bar = 'bar';"
5483  "k[2] = 2;"
5484  "k[4] = 4;");
5485  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5486  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5487 
5488  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5489  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5490 
5491  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5492  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5493 
5494  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5495  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5496 }
5497 
5498 
5499 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5501  if (name->Equals(v8_str("foo")) ||
5502  name->Equals(v8_str("bar")) ||
5503  name->Equals(v8_str("baz"))) {
5504  return v8::Undefined();
5505  }
5506  return v8::Handle<Value>();
5507 }
5508 
5509 
5510 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5512  if (index == 0 || index == 1) return v8::Undefined();
5513  return v8::Handle<Value>();
5514 }
5515 
5516 
5517 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5520  result->Set(v8::Integer::New(0), v8_str("foo"));
5521  result->Set(v8::Integer::New(1), v8_str("bar"));
5522  result->Set(v8::Integer::New(2), v8_str("baz"));
5523  return result;
5524 }
5525 
5526 
5527 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5530  result->Set(v8::Integer::New(0), v8_str("0"));
5531  result->Set(v8::Integer::New(1), v8_str("1"));
5532  return result;
5533 }
5534 
5535 
5536 THREADED_TEST(Enumerators) {
5537  v8::HandleScope scope;
5538  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5539  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5540  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5541  LocalContext context;
5542  context->Global()->Set(v8_str("k"), obj->NewInstance());
5544  "k[10] = 0;"
5545  "k.a = 0;"
5546  "k[5] = 0;"
5547  "k.b = 0;"
5548  "k[4294967295] = 0;"
5549  "k.c = 0;"
5550  "k[4294967296] = 0;"
5551  "k.d = 0;"
5552  "k[140000] = 0;"
5553  "k.e = 0;"
5554  "k[30000000000] = 0;"
5555  "k.f = 0;"
5556  "var result = [];"
5557  "for (var prop in k) {"
5558  " result.push(prop);"
5559  "}"
5560  "result"));
5561  // Check that we get all the property names returned including the
5562  // ones from the enumerators in the right order: indexed properties
5563  // in numerical order, indexed interceptor properties, named
5564  // properties in insertion order, named interceptor properties.
5565  // This order is not mandated by the spec, so this test is just
5566  // documenting our behavior.
5567  CHECK_EQ(17, result->Length());
5568  // Indexed properties in numerical order.
5569  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5570  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5571  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5572  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5573  // Indexed interceptor properties in the order they are returned
5574  // from the enumerator interceptor.
5575  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5576  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5577  // Named properties in insertion order.
5578  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5579  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5580  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5581  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5582  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5583  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5584  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5585  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5586  // Named interceptor properties.
5587  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5588  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5589  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5590 }
5591 
5592 
5595 
5596 
5597 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5599  p_getter_count++;
5600  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5601  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5602  if (name->Equals(v8_str("p1"))) {
5603  CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5604  } else if (name->Equals(v8_str("p2"))) {
5605  CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5606  } else if (name->Equals(v8_str("p3"))) {
5607  CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5608  } else if (name->Equals(v8_str("p4"))) {
5609  CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5610  }
5611  return v8::Undefined();
5612 }
5613 
5614 
5615 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5617  LocalContext context;
5618  context->Global()->Set(v8_str("o1"), obj->NewInstance());
5619  CompileRun(
5620  "o1.__proto__ = { };"
5621  "var o2 = { __proto__: o1 };"
5622  "var o3 = { __proto__: o2 };"
5623  "var o4 = { __proto__: o3 };"
5624  "for (var i = 0; i < 10; i++) o4.p4;"
5625  "for (var i = 0; i < 10; i++) o3.p3;"
5626  "for (var i = 0; i < 10; i++) o2.p2;"
5627  "for (var i = 0; i < 10; i++) o1.p1;");
5628 }
5629 
5630 
5631 static v8::Handle<Value> PGetter2(Local<String> name,
5632  const AccessorInfo& info) {
5634  p_getter_count2++;
5635  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5636  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5637  if (name->Equals(v8_str("p1"))) {
5638  CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5639  } else if (name->Equals(v8_str("p2"))) {
5640  CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5641  } else if (name->Equals(v8_str("p3"))) {
5642  CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5643  } else if (name->Equals(v8_str("p4"))) {
5644  CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5645  }
5646  return v8::Undefined();
5647 }
5648 
5649 
5650 THREADED_TEST(GetterHolders) {
5651  v8::HandleScope scope;
5652  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5653  obj->SetAccessor(v8_str("p1"), PGetter);
5654  obj->SetAccessor(v8_str("p2"), PGetter);
5655  obj->SetAccessor(v8_str("p3"), PGetter);
5656  obj->SetAccessor(v8_str("p4"), PGetter);
5657  p_getter_count = 0;
5658  RunHolderTest(obj);
5659  CHECK_EQ(40, p_getter_count);
5660 }
5661 
5662 
5663 THREADED_TEST(PreInterceptorHolders) {
5664  v8::HandleScope scope;
5665  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5666  obj->SetNamedPropertyHandler(PGetter2);
5667  p_getter_count2 = 0;
5668  RunHolderTest(obj);
5669  CHECK_EQ(40, p_getter_count2);
5670 }
5671 
5672 
5673 THREADED_TEST(ObjectInstantiation) {
5674  v8::HandleScope scope;
5675  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5676  templ->SetAccessor(v8_str("t"), PGetter2);
5677  LocalContext context;
5678  context->Global()->Set(v8_str("o"), templ->NewInstance());
5679  for (int i = 0; i < 100; i++) {
5680  v8::HandleScope inner_scope;
5681  v8::Handle<v8::Object> obj = templ->NewInstance();
5682  CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5683  context->Global()->Set(v8_str("o2"), obj);
5684  v8::Handle<Value> value =
5685  Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5686  CHECK_EQ(v8::True(), value);
5687  context->Global()->Set(v8_str("o"), obj);
5688  }
5689 }
5690 
5691 
5692 static int StrCmp16(uint16_t* a, uint16_t* b) {
5693  while (true) {
5694  if (*a == 0 && *b == 0) return 0;
5695  if (*a != *b) return 0 + *a - *b;
5696  a++;
5697  b++;
5698  }
5699 }
5700 
5701 
5702 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5703  while (true) {
5704  if (n-- == 0) return 0;
5705  if (*a == 0 && *b == 0) return 0;
5706  if (*a != *b) return 0 + *a - *b;
5707  a++;
5708  b++;
5709  }
5710 }
5711 
5712 
5713 int GetUtf8Length(Handle<String> str) {
5714  int len = str->Utf8Length();
5715  if (len < 0) {
5716  i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5717  i::FlattenString(istr);
5718  len = str->Utf8Length();
5719  }
5720  return len;
5721 }
5722 
5723 
5724 THREADED_TEST(StringWrite) {
5725  LocalContext context;
5726  v8::HandleScope scope;
5727  v8::Handle<String> str = v8_str("abcde");
5728  // abc<Icelandic eth><Unicode snowman>.
5729  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5730  v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
5731  const int kStride = 4; // Must match stride in for loops in JS below.
5732  CompileRun(
5733  "var left = '';"
5734  "for (var i = 0; i < 0xd800; i += 4) {"
5735  " left = left + String.fromCharCode(i);"
5736  "}");
5737  CompileRun(
5738  "var right = '';"
5739  "for (var i = 0; i < 0xd800; i += 4) {"
5740  " right = String.fromCharCode(i) + right;"
5741  "}");
5742  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5743  Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5744  Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5745 
5746  CHECK_EQ(5, str2->Length());
5747  CHECK_EQ(0xd800 / kStride, left_tree->Length());
5748  CHECK_EQ(0xd800 / kStride, right_tree->Length());
5749 
5750  char buf[100];
5751  char utf8buf[0xd800 * 3];
5752  uint16_t wbuf[100];
5753  int len;
5754  int charlen;
5755 
5756  memset(utf8buf, 0x1, 1000);
5757  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5758  CHECK_EQ(9, len);
5759  CHECK_EQ(5, charlen);
5760  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5761 
5762  memset(utf8buf, 0x1, 1000);
5763  len = str2->WriteUtf8(utf8buf, 8, &charlen);
5764  CHECK_EQ(8, len);
5765  CHECK_EQ(5, charlen);
5766  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5767 
5768  memset(utf8buf, 0x1, 1000);
5769  len = str2->WriteUtf8(utf8buf, 7, &charlen);
5770  CHECK_EQ(5, len);
5771  CHECK_EQ(4, charlen);
5772  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5773 
5774  memset(utf8buf, 0x1, 1000);
5775  len = str2->WriteUtf8(utf8buf, 6, &charlen);
5776  CHECK_EQ(5, len);
5777  CHECK_EQ(4, charlen);
5778  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5779 
5780  memset(utf8buf, 0x1, 1000);
5781  len = str2->WriteUtf8(utf8buf, 5, &charlen);
5782  CHECK_EQ(5, len);
5783  CHECK_EQ(4, charlen);
5784  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5785 
5786  memset(utf8buf, 0x1, 1000);
5787  len = str2->WriteUtf8(utf8buf, 4, &charlen);
5788  CHECK_EQ(3, len);
5789  CHECK_EQ(3, charlen);
5790  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5791 
5792  memset(utf8buf, 0x1, 1000);
5793  len = str2->WriteUtf8(utf8buf, 3, &charlen);
5794  CHECK_EQ(3, len);
5795  CHECK_EQ(3, charlen);
5796  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5797 
5798  memset(utf8buf, 0x1, 1000);
5799  len = str2->WriteUtf8(utf8buf, 2, &charlen);
5800  CHECK_EQ(2, len);
5801  CHECK_EQ(2, charlen);
5802  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5803 
5804  memset(utf8buf, 0x1, sizeof(utf8buf));
5805  len = GetUtf8Length(left_tree);
5806  int utf8_expected =
5807  (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5808  CHECK_EQ(utf8_expected, len);
5809  len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5810  CHECK_EQ(utf8_expected, len);
5811  CHECK_EQ(0xd800 / kStride, charlen);
5812  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5813  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5814  CHECK_EQ(0xc0 - kStride,
5815  static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5816  CHECK_EQ(1, utf8buf[utf8_expected]);
5817 
5818  memset(utf8buf, 0x1, sizeof(utf8buf));
5819  len = GetUtf8Length(right_tree);
5820  CHECK_EQ(utf8_expected, len);
5821  len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5822  CHECK_EQ(utf8_expected, len);
5823  CHECK_EQ(0xd800 / kStride, charlen);
5824  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5825  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5826  CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5827  CHECK_EQ(1, utf8buf[utf8_expected]);
5828 
5829  memset(buf, 0x1, sizeof(buf));
5830  memset(wbuf, 0x1, sizeof(wbuf));
5831  len = str->WriteAscii(buf);
5832  CHECK_EQ(5, len);
5833  len = str->Write(wbuf);
5834  CHECK_EQ(5, len);
5835  CHECK_EQ(0, strcmp("abcde", buf));
5836  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5837  CHECK_EQ(0, StrCmp16(answer1, wbuf));
5838 
5839  memset(buf, 0x1, sizeof(buf));
5840  memset(wbuf, 0x1, sizeof(wbuf));
5841  len = str->WriteAscii(buf, 0, 4);
5842  CHECK_EQ(4, len);
5843  len = str->Write(wbuf, 0, 4);
5844  CHECK_EQ(4, len);
5845  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5846  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5847  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5848 
5849  memset(buf, 0x1, sizeof(buf));
5850  memset(wbuf, 0x1, sizeof(wbuf));
5851  len = str->WriteAscii(buf, 0, 5);
5852  CHECK_EQ(5, len);
5853  len = str->Write(wbuf, 0, 5);
5854  CHECK_EQ(5, len);
5855  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5856  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5857  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5858 
5859  memset(buf, 0x1, sizeof(buf));
5860  memset(wbuf, 0x1, sizeof(wbuf));
5861  len = str->WriteAscii(buf, 0, 6);
5862  CHECK_EQ(5, len);
5863  len = str->Write(wbuf, 0, 6);
5864  CHECK_EQ(5, len);
5865  CHECK_EQ(0, strcmp("abcde", buf));
5866  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5867  CHECK_EQ(0, StrCmp16(answer4, wbuf));
5868 
5869  memset(buf, 0x1, sizeof(buf));
5870  memset(wbuf, 0x1, sizeof(wbuf));
5871  len = str->WriteAscii(buf, 4, -1);
5872  CHECK_EQ(1, len);
5873  len = str->Write(wbuf, 4, -1);
5874  CHECK_EQ(1, len);
5875  CHECK_EQ(0, strcmp("e", buf));
5876  uint16_t answer5[] = {'e', '\0'};
5877  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5878 
5879  memset(buf, 0x1, sizeof(buf));
5880  memset(wbuf, 0x1, sizeof(wbuf));
5881  len = str->WriteAscii(buf, 4, 6);
5882  CHECK_EQ(1, len);
5883  len = str->Write(wbuf, 4, 6);
5884  CHECK_EQ(1, len);
5885  CHECK_EQ(0, strcmp("e", buf));
5886  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5887 
5888  memset(buf, 0x1, sizeof(buf));
5889  memset(wbuf, 0x1, sizeof(wbuf));
5890  len = str->WriteAscii(buf, 4, 1);
5891  CHECK_EQ(1, len);
5892  len = str->Write(wbuf, 4, 1);
5893  CHECK_EQ(1, len);
5894  CHECK_EQ(0, strncmp("e\1", buf, 2));
5895  uint16_t answer6[] = {'e', 0x101};
5896  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5897 
5898  memset(buf, 0x1, sizeof(buf));
5899  memset(wbuf, 0x1, sizeof(wbuf));
5900  len = str->WriteAscii(buf, 3, 1);
5901  CHECK_EQ(1, len);
5902  len = str->Write(wbuf, 3, 1);
5903  CHECK_EQ(1, len);
5904  CHECK_EQ(0, strncmp("d\1", buf, 2));
5905  uint16_t answer7[] = {'d', 0x101};
5906  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5907 
5908  memset(wbuf, 0x1, sizeof(wbuf));
5909  wbuf[5] = 'X';
5910  len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5911  CHECK_EQ(5, len);
5912  CHECK_EQ('X', wbuf[5]);
5913  uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5914  uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5915  CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5916  CHECK_NE(0, StrCmp16(answer8b, wbuf));
5917  wbuf[5] = '\0';
5918  CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5919 
5920  memset(buf, 0x1, sizeof(buf));
5921  buf[5] = 'X';
5922  len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5923  CHECK_EQ(5, len);
5924  CHECK_EQ('X', buf[5]);
5925  CHECK_EQ(0, strncmp("abcde", buf, 5));
5926  CHECK_NE(0, strcmp("abcde", buf));
5927  buf[5] = '\0';
5928  CHECK_EQ(0, strcmp("abcde", buf));
5929 
5930  memset(utf8buf, 0x1, sizeof(utf8buf));
5931  utf8buf[8] = 'X';
5932  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5933  String::NO_NULL_TERMINATION);
5934  CHECK_EQ(8, len);
5935  CHECK_EQ('X', utf8buf[8]);
5936  CHECK_EQ(5, charlen);
5937  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5938  CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5939  utf8buf[8] = '\0';
5940  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5941 
5942  memset(utf8buf, 0x1, sizeof(utf8buf));
5943  utf8buf[5] = 'X';
5944  len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5945  String::NO_NULL_TERMINATION);
5946  CHECK_EQ(5, len);
5947  CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
5948  CHECK_EQ(5, charlen);
5949  utf8buf[5] = '\0';
5950  CHECK_EQ(0, strcmp(utf8buf, "abcde"));
5951 
5952  memset(buf, 0x1, sizeof(buf));
5953  len = str3->WriteAscii(buf);
5954  CHECK_EQ(7, len);
5955  CHECK_EQ(0, strcmp("abc def", buf));
5956 
5957  memset(buf, 0x1, sizeof(buf));
5958  len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
5959  CHECK_EQ(7, len);
5960  CHECK_EQ(0, strcmp("abc", buf));
5961  CHECK_EQ(0, buf[3]);
5962  CHECK_EQ(0, strcmp("def", buf + 4));
5963 }
5964 
5965 
5966 static void Utf16Helper(
5967  LocalContext& context,
5968  const char* name,
5969  const char* lengths_name,
5970  int len) {
5971  Local<v8::Array> a =
5972  Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5973  Local<v8::Array> alens =
5974  Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5975  for (int i = 0; i < len; i++) {
5976  Local<v8::String> string =
5977  Local<v8::String>::Cast(a->Get(i));
5978  Local<v8::Number> expected_len =
5979  Local<v8::Number>::Cast(alens->Get(i));
5980  CHECK_EQ(expected_len->Value() != string->Length(),
5981  string->MayContainNonAscii());
5982  int length = GetUtf8Length(string);
5983  CHECK_EQ(static_cast<int>(expected_len->Value()), length);
5984  }
5985 }
5986 
5987 
5988 static uint16_t StringGet(Handle<String> str, int index) {
5989  i::Handle<i::String> istring =
5990  v8::Utils::OpenHandle(String::Cast(*str));
5991  return istring->Get(index);
5992 }
5993 
5994 
5995 static void WriteUtf8Helper(
5996  LocalContext& context,
5997  const char* name,
5998  const char* lengths_name,
5999  int len) {
6000  Local<v8::Array> b =
6001  Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6002  Local<v8::Array> alens =
6003  Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6004  char buffer[1000];
6005  char buffer2[1000];
6006  for (int i = 0; i < len; i++) {
6007  Local<v8::String> string =
6008  Local<v8::String>::Cast(b->Get(i));
6009  Local<v8::Number> expected_len =
6010  Local<v8::Number>::Cast(alens->Get(i));
6011  int utf8_length = static_cast<int>(expected_len->Value());
6012  for (int j = utf8_length + 1; j >= 0; j--) {
6013  memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6014  memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6015  int nchars;
6016  int utf8_written =
6017  string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6018  int utf8_written2 =
6019  string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6020  CHECK_GE(utf8_length + 1, utf8_written);
6021  CHECK_GE(utf8_length, utf8_written2);
6022  for (int k = 0; k < utf8_written2; k++) {
6023  CHECK_EQ(buffer[k], buffer2[k]);
6024  }
6025  CHECK(nchars * 3 >= utf8_written - 1);
6026  CHECK(nchars <= utf8_written);
6027  if (j == utf8_length + 1) {
6028  CHECK_EQ(utf8_written2, utf8_length);
6029  CHECK_EQ(utf8_written2 + 1, utf8_written);
6030  }
6031  CHECK_EQ(buffer[utf8_written], 42);
6032  if (j > utf8_length) {
6033  if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6034  if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6035  Handle<String> roundtrip = v8_str(buffer);
6036  CHECK(roundtrip->Equals(string));
6037  } else {
6038  if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6039  }
6040  if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6041  if (nchars >= 2) {
6042  uint16_t trail = StringGet(string, nchars - 1);
6043  uint16_t lead = StringGet(string, nchars - 2);
6044  if (((lead & 0xfc00) == 0xd800) &&
6045  ((trail & 0xfc00) == 0xdc00)) {
6046  unsigned char u1 = buffer2[utf8_written2 - 4];
6047  unsigned char u2 = buffer2[utf8_written2 - 3];
6048  unsigned char u3 = buffer2[utf8_written2 - 2];
6049  unsigned char u4 = buffer2[utf8_written2 - 1];
6050  CHECK_EQ((u1 & 0xf8), 0xf0);
6051  CHECK_EQ((u2 & 0xc0), 0x80);
6052  CHECK_EQ((u3 & 0xc0), 0x80);
6053  CHECK_EQ((u4 & 0xc0), 0x80);
6054  uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6055  CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6056  CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6057  CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6058  CHECK_EQ((u1 & 0x3), c >> 18);
6059  }
6060  }
6061  }
6062  }
6063 }
6064 
6065 
6067  LocalContext context;
6068  v8::HandleScope scope;
6069  CompileRun(
6070  "var pad = '01234567890123456789';"
6071  "var p = [];"
6072  "var plens = [20, 3, 3];"
6073  "p.push('01234567890123456789');"
6074  "var lead = 0xd800;"
6075  "var trail = 0xdc00;"
6076  "p.push(String.fromCharCode(0xd800));"
6077  "p.push(String.fromCharCode(0xdc00));"
6078  "var a = [];"
6079  "var b = [];"
6080  "var c = [];"
6081  "var alens = [];"
6082  "for (var i = 0; i < 3; i++) {"
6083  " p[1] = String.fromCharCode(lead++);"
6084  " for (var j = 0; j < 3; j++) {"
6085  " p[2] = String.fromCharCode(trail++);"
6086  " a.push(p[i] + p[j]);"
6087  " b.push(p[i] + p[j]);"
6088  " c.push(p[i] + p[j]);"
6089  " alens.push(plens[i] + plens[j]);"
6090  " }"
6091  "}"
6092  "alens[5] -= 2;" // Here the surrogate pairs match up.
6093  "var a2 = [];"
6094  "var b2 = [];"
6095  "var c2 = [];"
6096  "var a2lens = [];"
6097  "for (var m = 0; m < 9; m++) {"
6098  " for (var n = 0; n < 9; n++) {"
6099  " a2.push(a[m] + a[n]);"
6100  " b2.push(b[m] + b[n]);"
6101  " var newc = 'x' + c[m] + c[n] + 'y';"
6102  " c2.push(newc.substring(1, newc.length - 1));"
6103  " var utf = alens[m] + alens[n];" // And here.
6104  // The 'n's that start with 0xdc.. are 6-8
6105  // The 'm's that end with 0xd8.. are 1, 4 and 7
6106  " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6107  " a2lens.push(utf);"
6108  " }"
6109  "}");
6110  Utf16Helper(context, "a", "alens", 9);
6111  Utf16Helper(context, "a2", "a2lens", 81);
6112  WriteUtf8Helper(context, "b", "alens", 9);
6113  WriteUtf8Helper(context, "b2", "a2lens", 81);
6114  WriteUtf8Helper(context, "c2", "a2lens", 81);
6115 }
6116 
6117 
6118 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6119  i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6120  i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6121  return *is1 == *is2;
6122 }
6123 
6124 
6125 static void SameSymbolHelper(const char* a, const char* b) {
6126  Handle<String> symbol1 = v8::String::NewSymbol(a);
6127  Handle<String> symbol2 = v8::String::NewSymbol(b);
6128  CHECK(SameSymbol(symbol1, symbol2));
6129 }
6130 
6131 
6132 THREADED_TEST(Utf16Symbol) {
6133  LocalContext context;
6134  v8::HandleScope scope;
6135 
6136  Handle<String> symbol1 = v8::String::NewSymbol("abc");
6137  Handle<String> symbol2 = v8::String::NewSymbol("abc");
6138  CHECK(SameSymbol(symbol1, symbol2));
6139 
6140  SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6141  "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6142  SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6143  "\360\220\220\206"); // 4 byte encoding.
6144  SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6145  "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6146  SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6147  "x\360\220\220\206"); // 4 byte encoding.
6148  CompileRun(
6149  "var sym0 = 'benedictus';"
6150  "var sym0b = 'S\303\270ren';"
6151  "var sym1 = '\355\240\201\355\260\207';"
6152  "var sym2 = '\360\220\220\210';"
6153  "var sym3 = 'x\355\240\201\355\260\207';"
6154  "var sym4 = 'x\360\220\220\210';"
6155  "if (sym1.length != 2) throw sym1;"
6156  "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6157  "if (sym2.length != 2) throw sym2;"
6158  "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6159  "if (sym3.length != 3) throw sym3;"
6160  "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6161  "if (sym4.length != 3) throw sym4;"
6162  "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6163  Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6164  Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6165  Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6166  Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6167  Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6168  Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6169  v8::Local<v8::Object> global = context->Global();
6170  Local<Value> s0 = global->Get(v8_str("sym0"));
6171  Local<Value> s0b = global->Get(v8_str("sym0b"));
6172  Local<Value> s1 = global->Get(v8_str("sym1"));
6173  Local<Value> s2 = global->Get(v8_str("sym2"));
6174  Local<Value> s3 = global->Get(v8_str("sym3"));
6175  Local<Value> s4 = global->Get(v8_str("sym4"));
6176  CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6177  CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6178  CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6179  CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6180  CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6181  CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6182 }
6183 
6184 
6185 THREADED_TEST(ToArrayIndex) {
6186  v8::HandleScope scope;
6187  LocalContext context;
6188 
6189  v8::Handle<String> str = v8_str("42");
6190  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6191  CHECK(!index.IsEmpty());
6192  CHECK_EQ(42.0, index->Uint32Value());
6193  str = v8_str("42asdf");
6194  index = str->ToArrayIndex();
6195  CHECK(index.IsEmpty());
6196  str = v8_str("-42");
6197  index = str->ToArrayIndex();
6198  CHECK(index.IsEmpty());
6199  str = v8_str("4294967295");
6200  index = str->ToArrayIndex();
6201  CHECK(!index.IsEmpty());
6202  CHECK_EQ(4294967295.0, index->Uint32Value());
6204  index = num->ToArrayIndex();
6205  CHECK(!index.IsEmpty());
6206  CHECK_EQ(1.0, index->Uint32Value());
6207  num = v8::Number::New(-1);
6208  index = num->ToArrayIndex();
6209  CHECK(index.IsEmpty());
6211  index = obj->ToArrayIndex();
6212  CHECK(index.IsEmpty());
6213 }
6214 
6215 
6216 THREADED_TEST(ErrorConstruction) {
6217  v8::HandleScope scope;
6218  LocalContext context;
6219 
6220  v8::Handle<String> foo = v8_str("foo");
6221  v8::Handle<String> message = v8_str("message");
6222  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6223  CHECK(range_error->IsObject());
6224  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
6225  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6226  CHECK(reference_error->IsObject());
6227  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
6228  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6229  CHECK(syntax_error->IsObject());
6230  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
6231  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6232  CHECK(type_error->IsObject());
6233  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
6235  CHECK(error->IsObject());
6236  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
6237 }
6238 
6239 
6240 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6242  return v8_num(10);
6243 }
6244 
6245 
6246 static void YSetter(Local<String> name,
6247  Local<Value> value,
6248  const AccessorInfo& info) {
6249  if (info.This()->Has(name)) {
6250  info.This()->Delete(name);
6251  }
6252  info.This()->Set(name, value);
6253 }
6254 
6255 
6256 THREADED_TEST(DeleteAccessor) {
6257  v8::HandleScope scope;
6258  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6259  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6260  LocalContext context;
6261  v8::Handle<v8::Object> holder = obj->NewInstance();
6262  context->Global()->Set(v8_str("holder"), holder);
6263  v8::Handle<Value> result = CompileRun(
6264  "holder.y = 11; holder.y = 12; holder.y");
6265  CHECK_EQ(12, result->Uint32Value());
6266 }
6267 
6268 
6269 THREADED_TEST(TypeSwitch) {
6270  v8::HandleScope scope;
6274  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6275  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6276  LocalContext context;
6278  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6279  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6280  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6281  for (int i = 0; i < 10; i++) {
6282  CHECK_EQ(0, type_switch->match(obj0));
6283  CHECK_EQ(1, type_switch->match(obj1));
6284  CHECK_EQ(2, type_switch->match(obj2));
6285  CHECK_EQ(3, type_switch->match(obj3));
6286  CHECK_EQ(3, type_switch->match(obj3));
6287  CHECK_EQ(2, type_switch->match(obj2));
6288  CHECK_EQ(1, type_switch->match(obj1));
6289  CHECK_EQ(0, type_switch->match(obj0));
6290  }
6291 }
6292 
6293 
6294 // For use within the TestSecurityHandler() test.
6295 static bool g_security_callback_result = false;
6296 static bool NamedSecurityTestCallback(Local<v8::Object> global,
6297  Local<Value> name,
6298  v8::AccessType type,
6299  Local<Value> data) {
6300  // Always allow read access.
6301  if (type == v8::ACCESS_GET)
6302  return true;
6303 
6304  // Sometimes allow other access.
6305  return g_security_callback_result;
6306 }
6307 
6308 
6309 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6310  uint32_t key,
6311  v8::AccessType type,
6312  Local<Value> data) {
6313  // Always allow read access.
6314  if (type == v8::ACCESS_GET)
6315  return true;
6316 
6317  // Sometimes allow other access.
6318  return g_security_callback_result;
6319 }
6320 
6321 
6322 static int trouble_nesting = 0;
6323 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6325  trouble_nesting++;
6326 
6327  // Call a JS function that throws an uncaught exception.
6328  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6329  Local<Value> trouble_callee = (trouble_nesting == 3) ?
6330  arg_this->Get(v8_str("trouble_callee")) :
6331  arg_this->Get(v8_str("trouble_caller"));
6332  CHECK(trouble_callee->IsFunction());
6333  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6334 }
6335 
6336 
6337 static int report_count = 0;
6338 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6340  report_count++;
6341 }
6342 
6343 
6344 // Counts uncaught exceptions, but other tests running in parallel
6345 // also have uncaught exceptions.
6346 TEST(ApiUncaughtException) {
6347  report_count = 0;
6348  v8::HandleScope scope;
6349  LocalContext env;
6350  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6351 
6352  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6353  v8::Local<v8::Object> global = env->Global();
6354  global->Set(v8_str("trouble"), fun->GetFunction());
6355 
6356  Script::Compile(v8_str("function trouble_callee() {"
6357  " var x = null;"
6358  " return x.foo;"
6359  "};"
6360  "function trouble_caller() {"
6361  " trouble();"
6362  "};"))->Run();
6363  Local<Value> trouble = global->Get(v8_str("trouble"));
6364  CHECK(trouble->IsFunction());
6365  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6366  CHECK(trouble_callee->IsFunction());
6367  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6368  CHECK(trouble_caller->IsFunction());
6369  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6370  CHECK_EQ(1, report_count);
6371  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6372 }
6373 
6374 static const char* script_resource_name = "ExceptionInNativeScript.js";
6375 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6377  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6378  CHECK(!name_val.IsEmpty() && name_val->IsString());
6380  CHECK_EQ(script_resource_name, *name);
6381  CHECK_EQ(3, message->GetLineNumber());
6382  v8::String::AsciiValue source_line(message->GetSourceLine());
6383  CHECK_EQ(" new o.foo();", *source_line);
6384 }
6385 
6386 TEST(ExceptionInNativeScript) {
6387  v8::HandleScope scope;
6388  LocalContext env;
6389  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6390 
6391  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6392  v8::Local<v8::Object> global = env->Global();
6393  global->Set(v8_str("trouble"), fun->GetFunction());
6394 
6395  Script::Compile(v8_str("function trouble() {\n"
6396  " var o = {};\n"
6397  " new o.foo();\n"
6398  "};"), v8::String::New(script_resource_name))->Run();
6399  Local<Value> trouble = global->Get(v8_str("trouble"));
6400  CHECK(trouble->IsFunction());
6401  Function::Cast(*trouble)->Call(global, 0, NULL);
6402  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6403 }
6404 
6405 
6406 TEST(CompilationErrorUsingTryCatchHandler) {
6407  v8::HandleScope scope;
6408  LocalContext env;
6409  v8::TryCatch try_catch;
6410  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6411  CHECK_NE(NULL, *try_catch.Exception());
6412  CHECK(try_catch.HasCaught());
6413 }
6414 
6415 
6416 TEST(TryCatchFinallyUsingTryCatchHandler) {
6417  v8::HandleScope scope;
6418  LocalContext env;
6419  v8::TryCatch try_catch;
6420  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6421  CHECK(!try_catch.HasCaught());
6422  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6423  CHECK(try_catch.HasCaught());
6424  try_catch.Reset();
6425  Script::Compile(v8_str("(function() {"
6426  "try { throw ''; } finally { return; }"
6427  "})()"))->Run();
6428  CHECK(!try_catch.HasCaught());
6429  Script::Compile(v8_str("(function()"
6430  " { try { throw ''; } finally { throw 0; }"
6431  "})()"))->Run();
6432  CHECK(try_catch.HasCaught());
6433 }
6434 
6435 
6436 // SecurityHandler can't be run twice
6437 TEST(SecurityHandler) {
6438  v8::HandleScope scope0;
6440  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6441  IndexedSecurityTestCallback);
6442  // Create an environment
6443  v8::Persistent<Context> context0 =
6444  Context::New(NULL, global_template);
6445  context0->Enter();
6446 
6447  v8::Handle<v8::Object> global0 = context0->Global();
6448  v8::Handle<Script> script0 = v8_compile("foo = 111");
6449  script0->Run();
6450  global0->Set(v8_str("0"), v8_num(999));
6451  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6452  CHECK_EQ(111, foo0->Int32Value());
6453  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6454  CHECK_EQ(999, z0->Int32Value());
6455 
6456  // Create another environment, should fail security checks.
6457  v8::HandleScope scope1;
6458 
6459  v8::Persistent<Context> context1 =
6460  Context::New(NULL, global_template);
6461  context1->Enter();
6462 
6463  v8::Handle<v8::Object> global1 = context1->Global();
6464  global1->Set(v8_str("othercontext"), global0);
6465  // This set will fail the security check.
6466  v8::Handle<Script> script1 =
6467  v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6468  script1->Run();
6469  // This read will pass the security check.
6470  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6471  CHECK_EQ(111, foo1->Int32Value());
6472  // This read will pass the security check.
6473  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6474  CHECK_EQ(999, z1->Int32Value());
6475 
6476  // Create another environment, should pass security checks.
6477  { g_security_callback_result = true; // allow security handler to pass.
6478  v8::HandleScope scope2;
6479  LocalContext context2;
6480  v8::Handle<v8::Object> global2 = context2->Global();
6481  global2->Set(v8_str("othercontext"), global0);
6482  v8::Handle<Script> script2 =
6483  v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6484  script2->Run();
6485  v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6486  CHECK_EQ(333, foo2->Int32Value());
6487  v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6488  CHECK_EQ(888, z2->Int32Value());
6489  }
6490 
6491  context1->Exit();
6492  context1.Dispose();
6493 
6494  context0->Exit();
6495  context0.Dispose();
6496 }
6497 
6498 
6499 THREADED_TEST(SecurityChecks) {
6500  v8::HandleScope handle_scope;
6501  LocalContext env1;
6502  v8::Persistent<Context> env2 = Context::New();
6503 
6504  Local<Value> foo = v8_str("foo");
6505  Local<Value> bar = v8_str("bar");
6506 
6507  // Set to the same domain.
6508  env1->SetSecurityToken(foo);
6509 
6510  // Create a function in env1.
6511  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6512  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6513  CHECK(spy->IsFunction());
6514 
6515  // Create another function accessing global objects.
6516  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
6517  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6518  CHECK(spy2->IsFunction());
6519 
6520  // Switch to env2 in the same domain and invoke spy on env2.
6521  {
6522  env2->SetSecurityToken(foo);
6523  // Enter env2
6524  Context::Scope scope_env2(env2);
6525  Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6526  CHECK(result->IsFunction());
6527  }
6528 
6529  {
6530  env2->SetSecurityToken(bar);
6531  Context::Scope scope_env2(env2);
6532 
6533  // Call cross_domain_call, it should throw an exception
6534  v8::TryCatch try_catch;
6535  Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6536  CHECK(try_catch.HasCaught());
6537  }
6538 
6539  env2.Dispose();
6540 }
6541 
6542 
6543 // Regression test case for issue 1183439.
6544 THREADED_TEST(SecurityChecksForPrototypeChain) {
6545  v8::HandleScope scope;
6546  LocalContext current;
6547  v8::Persistent<Context> other = Context::New();
6548 
6549  // Change context to be able to get to the Object function in the
6550  // other context without hitting the security checks.
6551  v8::Local<Value> other_object;
6552  { Context::Scope scope(other);
6553  other_object = other->Global()->Get(v8_str("Object"));
6554  other->Global()->Set(v8_num(42), v8_num(87));
6555  }
6556 
6557  current->Global()->Set(v8_str("other"), other->Global());
6558  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6559 
6560  // Make sure the security check fails here and we get an undefined
6561  // result instead of getting the Object function. Repeat in a loop
6562  // to make sure to exercise the IC code.
6563  v8::Local<Script> access_other0 = v8_compile("other.Object");
6564  v8::Local<Script> access_other1 = v8_compile("other[42]");
6565  for (int i = 0; i < 5; i++) {
6566  CHECK(!access_other0->Run()->Equals(other_object));
6567  CHECK(access_other0->Run()->IsUndefined());
6568  CHECK(!access_other1->Run()->Equals(v8_num(87)));
6569  CHECK(access_other1->Run()->IsUndefined());
6570  }
6571 
6572  // Create an object that has 'other' in its prototype chain and make
6573  // sure we cannot access the Object function indirectly through
6574  // that. Repeat in a loop to make sure to exercise the IC code.
6575  v8_compile("function F() { };"
6576  "F.prototype = other;"
6577  "var f = new F();")->Run();
6578  v8::Local<Script> access_f0 = v8_compile("f.Object");
6579  v8::Local<Script> access_f1 = v8_compile("f[42]");
6580  for (int j = 0; j < 5; j++) {
6581  CHECK(!access_f0->Run()->Equals(other_object));
6582  CHECK(access_f0->Run()->IsUndefined());
6583  CHECK(!access_f1->Run()->Equals(v8_num(87)));
6584  CHECK(access_f1->Run()->IsUndefined());
6585  }
6586 
6587  // Now it gets hairy: Set the prototype for the other global object
6588  // to be the current global object. The prototype chain for 'f' now
6589  // goes through 'other' but ends up in the current global object.
6590  { Context::Scope scope(other);
6591  other->Global()->Set(v8_str("__proto__"), current->Global());
6592  }
6593  // Set a named and an index property on the current global
6594  // object. To force the lookup to go through the other global object,
6595  // the properties must not exist in the other global object.
6596  current->Global()->Set(v8_str("foo"), v8_num(100));
6597  current->Global()->Set(v8_num(99), v8_num(101));
6598  // Try to read the properties from f and make sure that the access
6599  // gets stopped by the security checks on the other global object.
6600  Local<Script> access_f2 = v8_compile("f.foo");
6601  Local<Script> access_f3 = v8_compile("f[99]");
6602  for (int k = 0; k < 5; k++) {
6603  CHECK(!access_f2->Run()->Equals(v8_num(100)));
6604  CHECK(access_f2->Run()->IsUndefined());
6605  CHECK(!access_f3->Run()->Equals(v8_num(101)));
6606  CHECK(access_f3->Run()->IsUndefined());
6607  }
6608  other.Dispose();
6609 }
6610 
6611 
6612 THREADED_TEST(CrossDomainDelete) {
6613  v8::HandleScope handle_scope;
6614  LocalContext env1;
6615  v8::Persistent<Context> env2 = Context::New();
6616 
6617  Local<Value> foo = v8_str("foo");
6618  Local<Value> bar = v8_str("bar");
6619 
6620  // Set to the same domain.
6621  env1->SetSecurityToken(foo);
6622  env2->SetSecurityToken(foo);
6623 
6624  env1->Global()->Set(v8_str("prop"), v8_num(3));
6625  env2->Global()->Set(v8_str("env1"), env1->Global());
6626 
6627  // Change env2 to a different domain and delete env1.prop.
6628  env2->SetSecurityToken(bar);
6629  {
6630  Context::Scope scope_env2(env2);
6631  Local<Value> result =
6632  Script::Compile(v8_str("delete env1.prop"))->Run();
6633  CHECK(result->IsFalse());
6634  }
6635 
6636  // Check that env1.prop still exists.
6637  Local<Value> v = env1->Global()->Get(v8_str("prop"));
6638  CHECK(v->IsNumber());
6639  CHECK_EQ(3, v->Int32Value());
6640 
6641  env2.Dispose();
6642 }
6643 
6644 
6645 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6646  v8::HandleScope handle_scope;
6647  LocalContext env1;
6648  v8::Persistent<Context> env2 = Context::New();
6649 
6650  Local<Value> foo = v8_str("foo");
6651  Local<Value> bar = v8_str("bar");
6652 
6653  // Set to the same domain.
6654  env1->SetSecurityToken(foo);
6655  env2->SetSecurityToken(foo);
6656 
6657  env1->Global()->Set(v8_str("prop"), v8_num(3));
6658  env2->Global()->Set(v8_str("env1"), env1->Global());
6659 
6660  // env1.prop is enumerable in env2.
6661  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6662  {
6663  Context::Scope scope_env2(env2);
6664  Local<Value> result = Script::Compile(test)->Run();
6665  CHECK(result->IsTrue());
6666  }
6667 
6668  // Change env2 to a different domain and test again.
6669  env2->SetSecurityToken(bar);
6670  {
6671  Context::Scope scope_env2(env2);
6672  Local<Value> result = Script::Compile(test)->Run();
6673  CHECK(result->IsFalse());
6674  }
6675 
6676  env2.Dispose();
6677 }
6678 
6679 
6680 THREADED_TEST(CrossDomainForIn) {
6681  v8::HandleScope handle_scope;
6682  LocalContext env1;
6683  v8::Persistent<Context> env2 = Context::New();
6684 
6685  Local<Value> foo = v8_str("foo");
6686  Local<Value> bar = v8_str("bar");
6687 
6688  // Set to the same domain.
6689  env1->SetSecurityToken(foo);
6690  env2->SetSecurityToken(foo);
6691 
6692  env1->Global()->Set(v8_str("prop"), v8_num(3));
6693  env2->Global()->Set(v8_str("env1"), env1->Global());
6694 
6695  // Change env2 to a different domain and set env1's global object
6696  // as the __proto__ of an object in env2 and enumerate properties
6697  // in for-in. It shouldn't enumerate properties on env1's global
6698  // object.
6699  env2->SetSecurityToken(bar);
6700  {
6701  Context::Scope scope_env2(env2);
6702  Local<Value> result =
6703  CompileRun("(function(){var obj = {'__proto__':env1};"
6704  "for (var p in obj)"
6705  " if (p == 'prop') return false;"
6706  "return true;})()");
6707  CHECK(result->IsTrue());
6708  }
6709  env2.Dispose();
6710 }
6711 
6712 
6713 TEST(ContextDetachGlobal) {
6714  v8::HandleScope handle_scope;
6715  LocalContext env1;
6716  v8::Persistent<Context> env2 = Context::New();
6717 
6718  Local<v8::Object> global1 = env1->Global();
6719 
6720  Local<Value> foo = v8_str("foo");
6721 
6722  // Set to the same domain.
6723  env1->SetSecurityToken(foo);
6724  env2->SetSecurityToken(foo);
6725 
6726  // Enter env2
6727  env2->Enter();
6728 
6729  // Create a function in env2 and add a reference to it in env1.
6730  Local<v8::Object> global2 = env2->Global();
6731  global2->Set(v8_str("prop"), v8::Integer::New(1));
6732  CompileRun("function getProp() {return prop;}");
6733 
6734  env1->Global()->Set(v8_str("getProp"),
6735  global2->Get(v8_str("getProp")));
6736 
6737  // Detach env2's global, and reuse the global object of env2
6738  env2->Exit();
6739  env2->DetachGlobal();
6740  // env2 has a new global object.
6741  CHECK(!env2->Global()->Equals(global2));
6742 
6744  Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6745  env3->SetSecurityToken(v8_str("bar"));
6746  env3->Enter();
6747 
6748  Local<v8::Object> global3 = env3->Global();
6749  CHECK_EQ(global2, global3);
6750  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6751  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6752  global3->Set(v8_str("prop"), v8::Integer::New(-1));
6753  global3->Set(v8_str("prop2"), v8::Integer::New(2));
6754  env3->Exit();
6755 
6756  // Call getProp in env1, and it should return the value 1
6757  {
6758  Local<Value> get_prop = global1->Get(v8_str("getProp"));
6759  CHECK(get_prop->IsFunction());
6760  v8::TryCatch try_catch;
6761  Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6762  CHECK(!try_catch.HasCaught());
6763  CHECK_EQ(1, r->Int32Value());
6764  }
6765 
6766  // Check that env3 is not accessible from env1
6767  {
6768  Local<Value> r = global3->Get(v8_str("prop2"));
6769  CHECK(r->IsUndefined());
6770  }
6771 
6772  env2.Dispose();
6773  env3.Dispose();
6774 }
6775 
6776 
6777 TEST(DetachAndReattachGlobal) {
6778  v8::HandleScope scope;
6779  LocalContext env1;
6780 
6781  // Create second environment.
6782  v8::Persistent<Context> env2 = Context::New();
6783 
6784  Local<Value> foo = v8_str("foo");
6785 
6786  // Set same security token for env1 and env2.
6787  env1->SetSecurityToken(foo);
6788  env2->SetSecurityToken(foo);
6789 
6790  // Create a property on the global object in env2.
6791  {
6792  v8::Context::Scope scope(env2);
6793  env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6794  }
6795 
6796  // Create a reference to env2 global from env1 global.
6797  env1->Global()->Set(v8_str("other"), env2->Global());
6798 
6799  // Check that we have access to other.p in env2 from env1.
6800  Local<Value> result = CompileRun("other.p");
6801  CHECK(result->IsInt32());
6802  CHECK_EQ(42, result->Int32Value());
6803 
6804  // Hold on to global from env2 and detach global from env2.
6805  Local<v8::Object> global2 = env2->Global();
6806  env2->DetachGlobal();
6807 
6808  // Check that the global has been detached. No other.p property can
6809  // be found.
6810  result = CompileRun("other.p");
6811  CHECK(result->IsUndefined());
6812 
6813  // Reuse global2 for env3.
6815  Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6816  CHECK_EQ(global2, env3->Global());
6817 
6818  // Start by using the same security token for env3 as for env1 and env2.
6819  env3->SetSecurityToken(foo);
6820 
6821  // Create a property on the global object in env3.
6822  {
6823  v8::Context::Scope scope(env3);
6824  env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6825  }
6826 
6827  // Check that other.p is now the property in env3 and that we have access.
6828  result = CompileRun("other.p");
6829  CHECK(result->IsInt32());
6830  CHECK_EQ(24, result->Int32Value());
6831 
6832  // Change security token for env3 to something different from env1 and env2.
6833  env3->SetSecurityToken(v8_str("bar"));
6834 
6835  // Check that we do not have access to other.p in env1. |other| is now
6836  // the global object for env3 which has a different security token,
6837  // so access should be blocked.
6838  result = CompileRun("other.p");
6839  CHECK(result->IsUndefined());
6840 
6841  // Detach the global for env3 and reattach it to env2.
6842  env3->DetachGlobal();
6843  env2->ReattachGlobal(global2);
6844 
6845  // Check that we have access to other.p again in env1. |other| is now
6846  // the global object for env2 which has the same security token as env1.
6847  result = CompileRun("other.p");
6848  CHECK(result->IsInt32());
6849  CHECK_EQ(42, result->Int32Value());
6850 
6851  env2.Dispose();
6852  env3.Dispose();
6853 }
6854 
6855 
6856 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6857 static bool NamedAccessBlocker(Local<v8::Object> global,
6858  Local<Value> name,
6859  v8::AccessType type,
6860  Local<Value> data) {
6861  return Context::GetCurrent()->Global()->Equals(global) ||
6862  allowed_access_type[type];
6863 }
6864 
6865 
6866 static bool IndexedAccessBlocker(Local<v8::Object> global,
6867  uint32_t key,
6868  v8::AccessType type,
6869  Local<Value> data) {
6870  return Context::GetCurrent()->Global()->Equals(global) ||
6871  allowed_access_type[type];
6872 }
6873 
6874 
6875 static int g_echo_value = -1;
6876 static v8::Handle<Value> EchoGetter(Local<String> name,
6877  const AccessorInfo& info) {
6878  return v8_num(g_echo_value);
6879 }
6880 
6881 
6882 static void EchoSetter(Local<String> name,
6883  Local<Value> value,
6884  const AccessorInfo&) {
6885  if (value->IsNumber())
6886  g_echo_value = value->Int32Value();
6887 }
6888 
6889 
6890 static v8::Handle<Value> UnreachableGetter(Local<String> name,
6891  const AccessorInfo& info) {
6892  CHECK(false); // This function should not be called..
6893  return v8::Undefined();
6894 }
6895 
6896 
6897 static void UnreachableSetter(Local<String>, Local<Value>,
6898  const AccessorInfo&) {
6899  CHECK(false); // This function should nto be called.
6900 }
6901 
6902 
6904  v8::HandleScope handle_scope;
6906 
6907  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6908  IndexedAccessBlocker);
6909 
6910  // Add an accessor accessible by cross-domain JS code.
6911  global_template->SetAccessor(
6912  v8_str("accessible_prop"),
6913  EchoGetter, EchoSetter,
6916 
6917  // Add an accessor that is not accessible by cross-domain JS code.
6918  global_template->SetAccessor(v8_str("blocked_prop"),
6919  UnreachableGetter, UnreachableSetter,
6921  v8::DEFAULT);
6922 
6923  // Create an environment
6924  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6925  context0->Enter();
6926 
6927  v8::Handle<v8::Object> global0 = context0->Global();
6928 
6929  // Define a property with JS getter and setter.
6930  CompileRun(
6931  "function getter() { return 'getter'; };\n"
6932  "function setter() { return 'setter'; }\n"
6933  "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6934 
6935  Local<Value> getter = global0->Get(v8_str("getter"));
6936  Local<Value> setter = global0->Get(v8_str("setter"));
6937 
6938  // And define normal element.
6939  global0->Set(239, v8_str("239"));
6940 
6941  // Define an element with JS getter and setter.
6942  CompileRun(
6943  "function el_getter() { return 'el_getter'; };\n"
6944  "function el_setter() { return 'el_setter'; };\n"
6945  "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6946 
6947  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6948  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6949 
6950  v8::HandleScope scope1;
6951 
6952  v8::Persistent<Context> context1 = Context::New();
6953  context1->Enter();
6954 
6955  v8::Handle<v8::Object> global1 = context1->Global();
6956  global1->Set(v8_str("other"), global0);
6957 
6958  // Access blocked property.
6959  CompileRun("other.blocked_prop = 1");
6960 
6961  ExpectUndefined("other.blocked_prop");
6962  ExpectUndefined(
6963  "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6964  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6965 
6966  // Enable ACCESS_HAS
6967  allowed_access_type[v8::ACCESS_HAS] = true;
6968  ExpectUndefined("other.blocked_prop");
6969  // ... and now we can get the descriptor...
6970  ExpectUndefined(
6971  "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6972  // ... and enumerate the property.
6973  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6974  allowed_access_type[v8::ACCESS_HAS] = false;
6975 
6976  // Access blocked element.
6977  CompileRun("other[239] = 1");
6978 
6979  ExpectUndefined("other[239]");
6980  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6981  ExpectFalse("propertyIsEnumerable.call(other, '239')");
6982 
6983  // Enable ACCESS_HAS
6984  allowed_access_type[v8::ACCESS_HAS] = true;
6985  ExpectUndefined("other[239]");
6986  // ... and now we can get the descriptor...
6987  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6988  // ... and enumerate the property.
6989  ExpectTrue("propertyIsEnumerable.call(other, '239')");
6990  allowed_access_type[v8::ACCESS_HAS] = false;
6991 
6992  // Access a property with JS accessor.
6993  CompileRun("other.js_accessor_p = 2");
6994 
6995  ExpectUndefined("other.js_accessor_p");
6996  ExpectUndefined(
6997  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6998 
6999  // Enable ACCESS_HAS.
7000  allowed_access_type[v8::ACCESS_HAS] = true;
7001  ExpectUndefined("other.js_accessor_p");
7002  ExpectUndefined(
7003  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7004  ExpectUndefined(
7005  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7006  ExpectUndefined(
7007  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7008  allowed_access_type[v8::ACCESS_HAS] = false;
7009 
7010  // Enable both ACCESS_HAS and ACCESS_GET.
7011  allowed_access_type[v8::ACCESS_HAS] = true;
7012  allowed_access_type[v8::ACCESS_GET] = true;
7013 
7014  ExpectString("other.js_accessor_p", "getter");
7015  ExpectObject(
7016  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7017  ExpectUndefined(
7018  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7019  ExpectUndefined(
7020  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7021 
7022  allowed_access_type[v8::ACCESS_GET] = false;
7023  allowed_access_type[v8::ACCESS_HAS] = false;
7024 
7025  // Enable both ACCESS_HAS and ACCESS_SET.
7026  allowed_access_type[v8::ACCESS_HAS] = true;
7027  allowed_access_type[v8::ACCESS_SET] = true;
7028 
7029  ExpectUndefined("other.js_accessor_p");
7030  ExpectUndefined(
7031  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7032  ExpectObject(
7033  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7034  ExpectUndefined(
7035  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7036 
7037  allowed_access_type[v8::ACCESS_SET] = false;
7038  allowed_access_type[v8::ACCESS_HAS] = false;
7039 
7040  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7041  allowed_access_type[v8::ACCESS_HAS] = true;
7042  allowed_access_type[v8::ACCESS_GET] = true;
7043  allowed_access_type[v8::ACCESS_SET] = true;
7044 
7045  ExpectString("other.js_accessor_p", "getter");
7046  ExpectObject(
7047  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7048  ExpectObject(
7049  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7050  ExpectUndefined(
7051  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7052 
7053  allowed_access_type[v8::ACCESS_SET] = false;
7054  allowed_access_type[v8::ACCESS_GET] = false;
7055  allowed_access_type[v8::ACCESS_HAS] = false;
7056 
7057  // Access an element with JS accessor.
7058  CompileRun("other[42] = 2");
7059 
7060  ExpectUndefined("other[42]");
7061  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7062 
7063  // Enable ACCESS_HAS.
7064  allowed_access_type[v8::ACCESS_HAS] = true;
7065  ExpectUndefined("other[42]");
7066  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7067  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7068  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7069  allowed_access_type[v8::ACCESS_HAS] = false;
7070 
7071  // Enable both ACCESS_HAS and ACCESS_GET.
7072  allowed_access_type[v8::ACCESS_HAS] = true;
7073  allowed_access_type[v8::ACCESS_GET] = true;
7074 
7075  ExpectString("other[42]", "el_getter");
7076  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7077  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7078  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7079 
7080  allowed_access_type[v8::ACCESS_GET] = false;
7081  allowed_access_type[v8::ACCESS_HAS] = false;
7082 
7083  // Enable both ACCESS_HAS and ACCESS_SET.
7084  allowed_access_type[v8::ACCESS_HAS] = true;
7085  allowed_access_type[v8::ACCESS_SET] = true;
7086 
7087  ExpectUndefined("other[42]");
7088  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7089  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7090  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7091 
7092  allowed_access_type[v8::ACCESS_SET] = false;
7093  allowed_access_type[v8::ACCESS_HAS] = false;
7094 
7095  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7096  allowed_access_type[v8::ACCESS_HAS] = true;
7097  allowed_access_type[v8::ACCESS_GET] = true;
7098  allowed_access_type[v8::ACCESS_SET] = true;
7099 
7100  ExpectString("other[42]", "el_getter");
7101  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7102  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7103  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7104 
7105  allowed_access_type[v8::ACCESS_SET] = false;
7106  allowed_access_type[v8::ACCESS_GET] = false;
7107  allowed_access_type[v8::ACCESS_HAS] = false;
7108 
7109  v8::Handle<Value> value;
7110 
7111  // Access accessible property
7112  value = CompileRun("other.accessible_prop = 3");
7113  CHECK(value->IsNumber());
7114  CHECK_EQ(3, value->Int32Value());
7115  CHECK_EQ(3, g_echo_value);
7116 
7117  value = CompileRun("other.accessible_prop");
7118  CHECK(value->IsNumber());
7119  CHECK_EQ(3, value->Int32Value());
7120 
7121  value = CompileRun(
7122  "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7123  CHECK(value->IsNumber());
7124  CHECK_EQ(3, value->Int32Value());
7125 
7126  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
7127  CHECK(value->IsTrue());
7128 
7129  // Enumeration doesn't enumerate accessors from inaccessible objects in
7130  // the prototype chain even if the accessors are in themselves accessible.
7131  value =
7132  CompileRun("(function(){var obj = {'__proto__':other};"
7133  "for (var p in obj)"
7134  " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7135  " return false;"
7136  " }"
7137  "return true;})()");
7138  CHECK(value->IsTrue());
7139 
7140  context1->Exit();
7141  context0->Exit();
7142  context1.Dispose();
7143  context0.Dispose();
7144 }
7145 
7146 
7147 TEST(AccessControlES5) {
7148  v8::HandleScope handle_scope;
7150 
7151  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7152  IndexedAccessBlocker);
7153 
7154  // Add accessible accessor.
7155  global_template->SetAccessor(
7156  v8_str("accessible_prop"),
7157  EchoGetter, EchoSetter,
7160 
7161 
7162  // Add an accessor that is not accessible by cross-domain JS code.
7163  global_template->SetAccessor(v8_str("blocked_prop"),
7164  UnreachableGetter, UnreachableSetter,
7166  v8::DEFAULT);
7167 
7168  // Create an environment
7169  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7170  context0->Enter();
7171 
7172  v8::Handle<v8::Object> global0 = context0->Global();
7173 
7174  v8::Persistent<Context> context1 = Context::New();
7175  context1->Enter();
7176  v8::Handle<v8::Object> global1 = context1->Global();
7177  global1->Set(v8_str("other"), global0);
7178 
7179  // Regression test for issue 1154.
7180  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
7181 
7182  ExpectUndefined("other.blocked_prop");
7183 
7184  // Regression test for issue 1027.
7185  CompileRun("Object.defineProperty(\n"
7186  " other, 'blocked_prop', {configurable: false})");
7187  ExpectUndefined("other.blocked_prop");
7188  ExpectUndefined(
7189  "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7190 
7191  // Regression test for issue 1171.
7192  ExpectTrue("Object.isExtensible(other)");
7193  CompileRun("Object.preventExtensions(other)");
7194  ExpectTrue("Object.isExtensible(other)");
7195 
7196  // Object.seal and Object.freeze.
7197  CompileRun("Object.freeze(other)");
7198  ExpectTrue("Object.isExtensible(other)");
7199 
7200  CompileRun("Object.seal(other)");
7201  ExpectTrue("Object.isExtensible(other)");
7202 
7203  // Regression test for issue 1250.
7204  // Make sure that we can set the accessible accessors value using normal
7205  // assignment.
7206  CompileRun("other.accessible_prop = 42");
7207  CHECK_EQ(42, g_echo_value);
7208 
7209  v8::Handle<Value> value;
7210  // We follow Safari in ignoring assignments to host object accessors.
7211  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7212  value = CompileRun("other.accessible_prop == 42");
7213  CHECK(value->IsTrue());
7214 }
7215 
7216 
7217 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7218  Local<Value> name,
7219  v8::AccessType type,
7220  Local<Value> data) {
7221  return false;
7222 }
7223 
7224 
7225 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7226  uint32_t key,
7227  v8::AccessType type,
7228  Local<Value> data) {
7229  return false;
7230 }
7231 
7232 
7233 THREADED_TEST(AccessControlGetOwnPropertyNames) {
7234  v8::HandleScope handle_scope;
7236 
7237  obj_template->Set(v8_str("x"), v8::Integer::New(42));
7238  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7239  GetOwnPropertyNamesIndexedBlocker);
7240 
7241  // Create an environment
7242  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7243  context0->Enter();
7244 
7245  v8::Handle<v8::Object> global0 = context0->Global();
7246 
7247  v8::HandleScope scope1;
7248 
7249  v8::Persistent<Context> context1 = Context::New();
7250  context1->Enter();
7251 
7252  v8::Handle<v8::Object> global1 = context1->Global();
7253  global1->Set(v8_str("other"), global0);
7254  global1->Set(v8_str("object"), obj_template->NewInstance());
7255 
7256  v8::Handle<Value> value;
7257 
7258  // Attempt to get the property names of the other global object and
7259  // of an object that requires access checks. Accessing the other
7260  // global object should be blocked by access checks on the global
7261  // proxy object. Accessing the object that requires access checks
7262  // is blocked by the access checks on the object itself.
7263  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7264  CHECK(value->IsTrue());
7265 
7266  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7267  CHECK(value->IsTrue());
7268 
7269  context1->Exit();
7270  context0->Exit();
7271  context1.Dispose();
7272  context0.Dispose();
7273 }
7274 
7275 
7276 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7278  result->Set(0, v8_str("x"));
7279  return result;
7280 }
7281 
7282 
7283 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7284  v8::HandleScope handle_scope;
7286 
7287  obj_template->Set(v8_str("x"), v8::Integer::New(42));
7288  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7289  NamedPropertyEnumerator);
7290 
7291  LocalContext context;
7292  v8::Handle<v8::Object> global = context->Global();
7293  global->Set(v8_str("object"), obj_template->NewInstance());
7294 
7295  v8::Handle<Value> value =
7296  CompileRun("Object.getOwnPropertyNames(object).join(',')");
7297  CHECK_EQ(v8_str("x"), value);
7298 }
7299 
7300 
7301 static v8::Handle<Value> ConstTenGetter(Local<String> name,
7302  const AccessorInfo& info) {
7303  return v8_num(10);
7304 }
7305 
7306 
7307 THREADED_TEST(CrossDomainAccessors) {
7308  v8::HandleScope handle_scope;
7309 
7311 
7312  v8::Handle<v8::ObjectTemplate> global_template =
7313  func_template->InstanceTemplate();
7314 
7315  v8::Handle<v8::ObjectTemplate> proto_template =
7316  func_template->PrototypeTemplate();
7317 
7318  // Add an accessor to proto that's accessible by cross-domain JS code.
7319  proto_template->SetAccessor(v8_str("accessible"),
7320  ConstTenGetter, 0,
7323 
7324  // Add an accessor that is not accessible by cross-domain JS code.
7325  global_template->SetAccessor(v8_str("unreachable"),
7326  UnreachableGetter, 0,
7328  v8::DEFAULT);
7329 
7330  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7331  context0->Enter();
7332 
7333  Local<v8::Object> global = context0->Global();
7334  // Add a normal property that shadows 'accessible'
7335  global->Set(v8_str("accessible"), v8_num(11));
7336 
7337  // Enter a new context.
7338  v8::HandleScope scope1;
7339  v8::Persistent<Context> context1 = Context::New();
7340  context1->Enter();
7341 
7342  v8::Handle<v8::Object> global1 = context1->Global();
7343  global1->Set(v8_str("other"), global);
7344 
7345  // Should return 10, instead of 11
7346  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7347  CHECK(value->IsNumber());
7348  CHECK_EQ(10, value->Int32Value());
7349 
7350  value = v8_compile("other.unreachable")->Run();
7351  CHECK(value->IsUndefined());
7352 
7353  context1->Exit();
7354  context0->Exit();
7355  context1.Dispose();
7356  context0.Dispose();
7357 }
7358 
7359 
7360 static int named_access_count = 0;
7361 static int indexed_access_count = 0;
7362 
7363 static bool NamedAccessCounter(Local<v8::Object> global,
7364  Local<Value> name,
7365  v8::AccessType type,
7366  Local<Value> data) {
7367  named_access_count++;
7368  return true;
7369 }
7370 
7371 
7372 static bool IndexedAccessCounter(Local<v8::Object> global,
7373  uint32_t key,
7374  v8::AccessType type,
7375  Local<Value> data) {
7376  indexed_access_count++;
7377  return true;
7378 }
7379 
7380 
7381 // This one is too easily disturbed by other tests.
7382 TEST(AccessControlIC) {
7383  named_access_count = 0;
7384  indexed_access_count = 0;
7385 
7386  v8::HandleScope handle_scope;
7387 
7388  // Create an environment.
7389  v8::Persistent<Context> context0 = Context::New();
7390  context0->Enter();
7391 
7392  // Create an object that requires access-check functions to be
7393  // called for cross-domain access.
7395  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7396  IndexedAccessCounter);
7397  Local<v8::Object> object = object_template->NewInstance();
7398 
7399  v8::HandleScope scope1;
7400 
7401  // Create another environment.
7402  v8::Persistent<Context> context1 = Context::New();
7403  context1->Enter();
7404 
7405  // Make easy access to the object from the other environment.
7406  v8::Handle<v8::Object> global1 = context1->Global();
7407  global1->Set(v8_str("obj"), object);
7408 
7409  v8::Handle<Value> value;
7410 
7411  // Check that the named access-control function is called every time.
7412  CompileRun("function testProp(obj) {"
7413  " for (var i = 0; i < 10; i++) obj.prop = 1;"
7414  " for (var j = 0; j < 10; j++) obj.prop;"
7415  " return obj.prop"
7416  "}");
7417  value = CompileRun("testProp(obj)");
7418  CHECK(value->IsNumber());
7419  CHECK_EQ(1, value->Int32Value());
7420  CHECK_EQ(21, named_access_count);
7421 
7422  // Check that the named access-control function is called every time.
7423  CompileRun("var p = 'prop';"
7424  "function testKeyed(obj) {"
7425  " for (var i = 0; i < 10; i++) obj[p] = 1;"
7426  " for (var j = 0; j < 10; j++) obj[p];"
7427  " return obj[p];"
7428  "}");
7429  // Use obj which requires access checks. No inline caching is used
7430  // in that case.
7431  value = CompileRun("testKeyed(obj)");
7432  CHECK(value->IsNumber());
7433  CHECK_EQ(1, value->Int32Value());
7434  CHECK_EQ(42, named_access_count);
7435  // Force the inline caches into generic state and try again.
7436  CompileRun("testKeyed({ a: 0 })");
7437  CompileRun("testKeyed({ b: 0 })");
7438  value = CompileRun("testKeyed(obj)");
7439  CHECK(value->IsNumber());
7440  CHECK_EQ(1, value->Int32Value());
7441  CHECK_EQ(63, named_access_count);
7442 
7443  // Check that the indexed access-control function is called every time.
7444  CompileRun("function testIndexed(obj) {"
7445  " for (var i = 0; i < 10; i++) obj[0] = 1;"
7446  " for (var j = 0; j < 10; j++) obj[0];"
7447  " return obj[0]"
7448  "}");
7449  value = CompileRun("testIndexed(obj)");
7450  CHECK(value->IsNumber());
7451  CHECK_EQ(1, value->Int32Value());
7452  CHECK_EQ(21, indexed_access_count);
7453  // Force the inline caches into generic state.
7454  CompileRun("testIndexed(new Array(1))");
7455  // Test that the indexed access check is called.
7456  value = CompileRun("testIndexed(obj)");
7457  CHECK(value->IsNumber());
7458  CHECK_EQ(1, value->Int32Value());
7459  CHECK_EQ(42, indexed_access_count);
7460 
7461  // Check that the named access check is called when invoking
7462  // functions on an object that requires access checks.
7463  CompileRun("obj.f = function() {}");
7464  CompileRun("function testCallNormal(obj) {"
7465  " for (var i = 0; i < 10; i++) obj.f();"
7466  "}");
7467  CompileRun("testCallNormal(obj)");
7468  CHECK_EQ(74, named_access_count);
7469 
7470  // Force obj into slow case.
7471  value = CompileRun("delete obj.prop");
7472  CHECK(value->BooleanValue());
7473  // Force inline caches into dictionary probing mode.
7474  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7475  // Test that the named access check is called.
7476  value = CompileRun("testProp(obj);");
7477  CHECK(value->IsNumber());
7478  CHECK_EQ(1, value->Int32Value());
7479  CHECK_EQ(96, named_access_count);
7480 
7481  // Force the call inline cache into dictionary probing mode.
7482  CompileRun("o.f = function() {}; testCallNormal(o)");
7483  // Test that the named access check is still called for each
7484  // invocation of the function.
7485  value = CompileRun("testCallNormal(obj)");
7486  CHECK_EQ(106, named_access_count);
7487 
7488  context1->Exit();
7489  context0->Exit();
7490  context1.Dispose();
7491  context0.Dispose();
7492 }
7493 
7494 
7495 static bool NamedAccessFlatten(Local<v8::Object> global,
7496  Local<Value> name,
7497  v8::AccessType type,
7498  Local<Value> data) {
7499  char buf[100];
7500  int len;
7501 
7502  CHECK(name->IsString());
7503 
7504  memset(buf, 0x1, sizeof(buf));
7505  len = name.As<String>()->WriteAscii(buf);
7506  CHECK_EQ(4, len);
7507 
7508  uint16_t buf2[100];
7509 
7510  memset(buf, 0x1, sizeof(buf));
7511  len = name.As<String>()->Write(buf2);
7512  CHECK_EQ(4, len);
7513 
7514  return true;
7515 }
7516 
7517 
7518 static bool IndexedAccessFlatten(Local<v8::Object> global,
7519  uint32_t key,
7520  v8::AccessType type,
7521  Local<Value> data) {
7522  return true;
7523 }
7524 
7525 
7526 // Regression test. In access checks, operations that may cause
7527 // garbage collection are not allowed. It used to be the case that
7528 // using the Write operation on a string could cause a garbage
7529 // collection due to flattening of the string. This is no longer the
7530 // case.
7531 THREADED_TEST(AccessControlFlatten) {
7532  named_access_count = 0;
7533  indexed_access_count = 0;
7534 
7535  v8::HandleScope handle_scope;
7536 
7537  // Create an environment.
7538  v8::Persistent<Context> context0 = Context::New();
7539  context0->Enter();
7540 
7541  // Create an object that requires access-check functions to be
7542  // called for cross-domain access.
7544  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7545  IndexedAccessFlatten);
7546  Local<v8::Object> object = object_template->NewInstance();
7547 
7548  v8::HandleScope scope1;
7549 
7550  // Create another environment.
7551  v8::Persistent<Context> context1 = Context::New();
7552  context1->Enter();
7553 
7554  // Make easy access to the object from the other environment.
7555  v8::Handle<v8::Object> global1 = context1->Global();
7556  global1->Set(v8_str("obj"), object);
7557 
7558  v8::Handle<Value> value;
7559 
7560  value = v8_compile("var p = 'as' + 'df';")->Run();
7561  value = v8_compile("obj[p];")->Run();
7562 
7563  context1->Exit();
7564  context0->Exit();
7565  context1.Dispose();
7566  context0.Dispose();
7567 }
7568 
7569 
7570 static v8::Handle<Value> AccessControlNamedGetter(
7571  Local<String>, const AccessorInfo&) {
7572  return v8::Integer::New(42);
7573 }
7574 
7575 
7576 static v8::Handle<Value> AccessControlNamedSetter(
7577  Local<String>, Local<Value> value, const AccessorInfo&) {
7578  return value;
7579 }
7580 
7581 
7582 static v8::Handle<Value> AccessControlIndexedGetter(
7583  uint32_t index,
7584  const AccessorInfo& info) {
7585  return v8_num(42);
7586 }
7587 
7588 
7589 static v8::Handle<Value> AccessControlIndexedSetter(
7590  uint32_t, Local<Value> value, const AccessorInfo&) {
7591  return value;
7592 }
7593 
7594 
7595 THREADED_TEST(AccessControlInterceptorIC) {
7596  named_access_count = 0;
7597  indexed_access_count = 0;
7598 
7599  v8::HandleScope handle_scope;
7600 
7601  // Create an environment.
7602  v8::Persistent<Context> context0 = Context::New();
7603  context0->Enter();
7604 
7605  // Create an object that requires access-check functions to be
7606  // called for cross-domain access. The object also has interceptors
7607  // interceptor.
7609  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7610  IndexedAccessCounter);
7611  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7612  AccessControlNamedSetter);
7613  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7614  AccessControlIndexedSetter);
7615  Local<v8::Object> object = object_template->NewInstance();
7616 
7617  v8::HandleScope scope1;
7618 
7619  // Create another environment.
7620  v8::Persistent<Context> context1 = Context::New();
7621  context1->Enter();
7622 
7623  // Make easy access to the object from the other environment.
7624  v8::Handle<v8::Object> global1 = context1->Global();
7625  global1->Set(v8_str("obj"), object);
7626 
7627  v8::Handle<Value> value;
7628 
7629  // Check that the named access-control function is called every time
7630  // eventhough there is an interceptor on the object.
7631  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7632  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7633  "obj.x")->Run();
7634  CHECK(value->IsNumber());
7635  CHECK_EQ(42, value->Int32Value());
7636  CHECK_EQ(21, named_access_count);
7637 
7638  value = v8_compile("var p = 'x';")->Run();
7639  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7640  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7641  "obj[p]")->Run();
7642  CHECK(value->IsNumber());
7643  CHECK_EQ(42, value->Int32Value());
7644  CHECK_EQ(42, named_access_count);
7645 
7646  // Check that the indexed access-control function is called every
7647  // time eventhough there is an interceptor on the object.
7648  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7649  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7650  "obj[0]")->Run();
7651  CHECK(value->IsNumber());
7652  CHECK_EQ(42, value->Int32Value());
7653  CHECK_EQ(21, indexed_access_count);
7654 
7655  context1->Exit();
7656  context0->Exit();
7657  context1.Dispose();
7658  context0.Dispose();
7659 }
7660 
7661 
7664 }
7665 
7666 
7667 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7669  return v8_num(12);
7670 }
7671 
7672 
7673 THREADED_TEST(InstanceProperties) {
7674  v8::HandleScope handle_scope;
7675  LocalContext context;
7676 
7677  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7678  Local<ObjectTemplate> instance = t->InstanceTemplate();
7679 
7680  instance->Set(v8_str("x"), v8_num(42));
7681  instance->Set(v8_str("f"),
7682  v8::FunctionTemplate::New(InstanceFunctionCallback));
7683 
7684  Local<Value> o = t->GetFunction()->NewInstance();
7685 
7686  context->Global()->Set(v8_str("i"), o);
7687  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7688  CHECK_EQ(42, value->Int32Value());
7689 
7690  value = Script::Compile(v8_str("i.f()"))->Run();
7691  CHECK_EQ(12, value->Int32Value());
7692 }
7693 
7694 
7695 static v8::Handle<Value>
7696 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7698  return v8::Handle<Value>();
7699 }
7700 
7701 
7702 THREADED_TEST(GlobalObjectInstanceProperties) {
7703  v8::HandleScope handle_scope;
7704 
7705  Local<Value> global_object;
7706 
7707  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7708  t->InstanceTemplate()->SetNamedPropertyHandler(
7709  GlobalObjectInstancePropertiesGet);
7710  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7711  instance_template->Set(v8_str("x"), v8_num(42));
7712  instance_template->Set(v8_str("f"),
7713  v8::FunctionTemplate::New(InstanceFunctionCallback));
7714 
7715  // The script to check how Crankshaft compiles missing global function
7716  // invocations. function g is not defined and should throw on call.
7717  const char* script =
7718  "function wrapper(call) {"
7719  " var x = 0, y = 1;"
7720  " for (var i = 0; i < 1000; i++) {"
7721  " x += i * 100;"
7722  " y += i * 100;"
7723  " }"
7724  " if (call) g();"
7725  "}"
7726  "for (var i = 0; i < 17; i++) wrapper(false);"
7727  "var thrown = 0;"
7728  "try { wrapper(true); } catch (e) { thrown = 1; };"
7729  "thrown";
7730 
7731  {
7732  LocalContext env(NULL, instance_template);
7733  // Hold on to the global object so it can be used again in another
7734  // environment initialization.
7735  global_object = env->Global();
7736 
7737  Local<Value> value = Script::Compile(v8_str("x"))->Run();
7738  CHECK_EQ(42, value->Int32Value());
7739  value = Script::Compile(v8_str("f()"))->Run();
7740  CHECK_EQ(12, value->Int32Value());
7741  value = Script::Compile(v8_str(script))->Run();
7742  CHECK_EQ(1, value->Int32Value());
7743  }
7744 
7745  {
7746  // Create new environment reusing the global object.
7747  LocalContext env(NULL, instance_template, global_object);
7748  Local<Value> value = Script::Compile(v8_str("x"))->Run();
7749  CHECK_EQ(42, value->Int32Value());
7750  value = Script::Compile(v8_str("f()"))->Run();
7751  CHECK_EQ(12, value->Int32Value());
7752  value = Script::Compile(v8_str(script))->Run();
7753  CHECK_EQ(1, value->Int32Value());
7754  }
7755 }
7756 
7757 
7758 THREADED_TEST(CallKnownGlobalReceiver) {
7759  v8::HandleScope handle_scope;
7760 
7761  Local<Value> global_object;
7762 
7763  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7764  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7765 
7766  // The script to check that we leave global object not
7767  // global object proxy on stack when we deoptimize from inside
7768  // arguments evaluation.
7769  // To provoke error we need to both force deoptimization
7770  // from arguments evaluation and to force CallIC to take
7771  // CallIC_Miss code path that can't cope with global proxy.
7772  const char* script =
7773  "function bar(x, y) { try { } finally { } }"
7774  "function baz(x) { try { } finally { } }"
7775  "function bom(x) { try { } finally { } }"
7776  "function foo(x) { bar([x], bom(2)); }"
7777  "for (var i = 0; i < 10000; i++) foo(1);"
7778  "foo";
7779 
7780  Local<Value> foo;
7781  {
7782  LocalContext env(NULL, instance_template);
7783  // Hold on to the global object so it can be used again in another
7784  // environment initialization.
7785  global_object = env->Global();
7786  foo = Script::Compile(v8_str(script))->Run();
7787  }
7788 
7789  {
7790  // Create new environment reusing the global object.
7791  LocalContext env(NULL, instance_template, global_object);
7792  env->Global()->Set(v8_str("foo"), foo);
7793  Script::Compile(v8_str("foo()"))->Run();
7794  }
7795 }
7796 
7797 
7798 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7800  return v8_num(42);
7801 }
7802 
7803 
7804 static int shadow_y;
7805 static int shadow_y_setter_call_count;
7806 static int shadow_y_getter_call_count;
7807 
7808 
7809 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7810  shadow_y_setter_call_count++;
7811  shadow_y = 42;
7812 }
7813 
7814 
7815 static v8::Handle<Value> ShadowYGetter(Local<String> name,
7816  const AccessorInfo& info) {
7818  shadow_y_getter_call_count++;
7819  return v8_num(shadow_y);
7820 }
7821 
7822 
7823 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7824  const AccessorInfo& info) {
7825  return v8::Handle<Value>();
7826 }
7827 
7828 
7829 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7830  const AccessorInfo&) {
7831  return v8::Handle<Value>();
7832 }
7833 
7834 
7835 THREADED_TEST(ShadowObject) {
7836  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7837  v8::HandleScope handle_scope;
7838 
7839  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7840  LocalContext context(NULL, global_template);
7841 
7842  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7843  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7844  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7845  Local<ObjectTemplate> proto = t->PrototypeTemplate();
7846  Local<ObjectTemplate> instance = t->InstanceTemplate();
7847 
7848  // Only allow calls of f on instances of t.
7849  Local<v8::Signature> signature = v8::Signature::New(t);
7850  proto->Set(v8_str("f"),
7851  v8::FunctionTemplate::New(ShadowFunctionCallback,
7852  Local<Value>(),
7853  signature));
7854  proto->Set(v8_str("x"), v8_num(12));
7855 
7856  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7857 
7858  Local<Value> o = t->GetFunction()->NewInstance();
7859  context->Global()->Set(v8_str("__proto__"), o);
7860 
7861  Local<Value> value =
7862  Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7863  CHECK(value->IsBoolean());
7864  CHECK(!value->BooleanValue());
7865 
7866  value = Script::Compile(v8_str("x"))->Run();
7867  CHECK_EQ(12, value->Int32Value());
7868 
7869  value = Script::Compile(v8_str("f()"))->Run();
7870  CHECK_EQ(42, value->Int32Value());
7871 
7872  Script::Compile(v8_str("y = 43"))->Run();
7873  CHECK_EQ(1, shadow_y_setter_call_count);
7874  value = Script::Compile(v8_str("y"))->Run();
7875  CHECK_EQ(1, shadow_y_getter_call_count);
7876  CHECK_EQ(42, value->Int32Value());
7877 }
7878 
7879 
7880 THREADED_TEST(HiddenPrototype) {
7881  v8::HandleScope handle_scope;
7882  LocalContext context;
7883 
7884  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7885  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7886  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7887  t1->SetHiddenPrototype(true);
7888  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7889  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7890  t2->SetHiddenPrototype(true);
7891  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7892  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7893  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7894 
7895  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7896  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7897  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7898  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7899 
7900  // Setting the prototype on an object skips hidden prototypes.
7901  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7902  o0->Set(v8_str("__proto__"), o1);
7903  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7904  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7905  o0->Set(v8_str("__proto__"), o2);
7906  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7907  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7908  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7909  o0->Set(v8_str("__proto__"), o3);
7910  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7911  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7912  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7913  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7914 
7915  // Getting the prototype of o0 should get the first visible one
7916  // which is o3. Therefore, z should not be defined on the prototype
7917  // object.
7918  Local<Value> proto = o0->Get(v8_str("__proto__"));
7919  CHECK(proto->IsObject());
7920  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7921 }
7922 
7923 
7925  v8::HandleScope handle_scope;
7926  LocalContext context;
7927 
7928  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7929  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7930  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7931  t1->SetHiddenPrototype(true);
7932  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7933  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7934  t2->SetHiddenPrototype(true);
7935  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7936  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7937  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7938 
7939  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7940  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7941  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7942  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7943 
7944  // Setting the prototype on an object does not skip hidden prototypes.
7945  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7946  CHECK(o0->SetPrototype(o1));
7947  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7948  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7949  CHECK(o1->SetPrototype(o2));
7950  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7951  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7952  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7953  CHECK(o2->SetPrototype(o3));
7954  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7955  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7956  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7957  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7958 
7959  // Getting the prototype of o0 should get the first visible one
7960  // which is o3. Therefore, z should not be defined on the prototype
7961  // object.
7962  Local<Value> proto = o0->Get(v8_str("__proto__"));
7963  CHECK(proto->IsObject());
7964  CHECK_EQ(proto.As<v8::Object>(), o3);
7965 
7966  // However, Object::GetPrototype ignores hidden prototype.
7967  Local<Value> proto0 = o0->GetPrototype();
7968  CHECK(proto0->IsObject());
7969  CHECK_EQ(proto0.As<v8::Object>(), o1);
7970 
7971  Local<Value> proto1 = o1->GetPrototype();
7972  CHECK(proto1->IsObject());
7973  CHECK_EQ(proto1.As<v8::Object>(), o2);
7974 
7975  Local<Value> proto2 = o2->GetPrototype();
7976  CHECK(proto2->IsObject());
7977  CHECK_EQ(proto2.As<v8::Object>(), o3);
7978 }
7979 
7980 
7981 // Getting property names of an object with a prototype chain that
7982 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
7983 // crash the runtime.
7984 THREADED_TEST(Regress91517) {
7985  i::FLAG_allow_natives_syntax = true;
7986  v8::HandleScope handle_scope;
7987  LocalContext context;
7988 
7989  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7990  t1->SetHiddenPrototype(true);
7991  t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7992  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7993  t2->SetHiddenPrototype(true);
7994  t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7995  t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7996  t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7997  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7998  t3->SetHiddenPrototype(true);
7999  t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8000  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8001  t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8002 
8003  // Force dictionary-based properties.
8004  i::ScopedVector<char> name_buf(1024);
8005  for (int i = 1; i <= 1000; i++) {
8006  i::OS::SNPrintF(name_buf, "sdf%d", i);
8007  t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8008  }
8009 
8010  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8011  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8012  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8013  Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8014 
8015  // Create prototype chain of hidden prototypes.
8016  CHECK(o4->SetPrototype(o3));
8017  CHECK(o3->SetPrototype(o2));
8018  CHECK(o2->SetPrototype(o1));
8019 
8020  // Call the runtime version of GetLocalPropertyNames() on the natively
8021  // created object through JavaScript.
8022  context->Global()->Set(v8_str("obj"), o4);
8023  CompileRun("var names = %GetLocalPropertyNames(obj);");
8024 
8025  ExpectInt32("names.length", 1006);
8026  ExpectTrue("names.indexOf(\"baz\") >= 0");
8027  ExpectTrue("names.indexOf(\"boo\") >= 0");
8028  ExpectTrue("names.indexOf(\"foo\") >= 0");
8029  ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8030  ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8031  ExpectFalse("names[1005] == undefined");
8032 }
8033 
8034 
8035 THREADED_TEST(FunctionReadOnlyPrototype) {
8036  v8::HandleScope handle_scope;
8037  LocalContext context;
8038 
8039  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8040  t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8041  t1->ReadOnlyPrototype();
8042  context->Global()->Set(v8_str("func1"), t1->GetFunction());
8043  // Configured value of ReadOnly flag.
8044  CHECK(CompileRun(
8045  "(function() {"
8046  " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
8047  " return (descriptor['writable'] == false);"
8048  "})()")->BooleanValue());
8049  CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8050  CHECK_EQ(42,
8051  CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
8052 
8053  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8054  t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8055  context->Global()->Set(v8_str("func2"), t2->GetFunction());
8056  // Default value of ReadOnly flag.
8057  CHECK(CompileRun(
8058  "(function() {"
8059  " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
8060  " return (descriptor['writable'] == true);"
8061  "})()")->BooleanValue());
8062  CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
8063 }
8064 
8065 
8066 THREADED_TEST(SetPrototypeThrows) {
8067  v8::HandleScope handle_scope;
8068  LocalContext context;
8069 
8070  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8071 
8072  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8073  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8074 
8075  CHECK(o0->SetPrototype(o1));
8076  // If setting the prototype leads to the cycle, SetPrototype should
8077  // return false and keep VM in sane state.
8078  v8::TryCatch try_catch;
8079  CHECK(!o1->SetPrototype(o0));
8080  CHECK(!try_catch.HasCaught());
8081  ASSERT(!i::Isolate::Current()->has_pending_exception());
8082 
8083  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8084 }
8085 
8086 
8087 THREADED_TEST(GetterSetterExceptions) {
8088  v8::HandleScope handle_scope;
8089  LocalContext context;
8090  CompileRun(
8091  "function Foo() { };"
8092  "function Throw() { throw 5; };"
8093  "var x = { };"
8094  "x.__defineSetter__('set', Throw);"
8095  "x.__defineGetter__('get', Throw);");
8096  Local<v8::Object> x =
8097  Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8098  v8::TryCatch try_catch;
8099  x->Set(v8_str("set"), v8::Integer::New(8));
8100  x->Get(v8_str("get"));
8101  x->Set(v8_str("set"), v8::Integer::New(8));
8102  x->Get(v8_str("get"));
8103  x->Set(v8_str("set"), v8::Integer::New(8));
8104  x->Get(v8_str("get"));
8105  x->Set(v8_str("set"), v8::Integer::New(8));
8106  x->Get(v8_str("get"));
8107 }
8108 
8109 
8110 THREADED_TEST(Constructor) {
8111  v8::HandleScope handle_scope;
8112  LocalContext context;
8113  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8114  templ->SetClassName(v8_str("Fun"));
8115  Local<Function> cons = templ->GetFunction();
8116  context->Global()->Set(v8_str("Fun"), cons);
8117  Local<v8::Object> inst = cons->NewInstance();
8118  i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
8119  CHECK(obj->IsJSObject());
8120  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8121  CHECK(value->BooleanValue());
8122 }
8123 
8124 
8125 static Handle<Value> ConstructorCallback(const Arguments& args) {
8127  Local<Object> This;
8128 
8129  if (args.IsConstructCall()) {
8130  Local<Object> Holder = args.Holder();
8131  This = Object::New();
8132  Local<Value> proto = Holder->GetPrototype();
8133  if (proto->IsObject()) {
8134  This->SetPrototype(proto);
8135  }
8136  } else {
8137  This = args.This();
8138  }
8139 
8140  This->Set(v8_str("a"), args[0]);
8141  return This;
8142 }
8143 
8144 
8145 static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8147  return args[0];
8148 }
8149 
8150 
8151 THREADED_TEST(ConstructorForObject) {
8152  v8::HandleScope handle_scope;
8153  LocalContext context;
8154 
8155  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8156  instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8157  Local<Object> instance = instance_template->NewInstance();
8158  context->Global()->Set(v8_str("obj"), instance);
8159  v8::TryCatch try_catch;
8160  Local<Value> value;
8161  CHECK(!try_catch.HasCaught());
8162 
8163  // Call the Object's constructor with a 32-bit signed integer.
8164  value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8165  CHECK(!try_catch.HasCaught());
8166  CHECK(value->IsInt32());
8167  CHECK_EQ(28, value->Int32Value());
8168 
8169  Local<Value> args1[] = { v8_num(28) };
8170  Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8171  CHECK(value_obj1->IsObject());
8172  Local<Object> object1 = Local<Object>::Cast(value_obj1);
8173  value = object1->Get(v8_str("a"));
8174  CHECK(value->IsInt32());
8175  CHECK(!try_catch.HasCaught());
8176  CHECK_EQ(28, value->Int32Value());
8177 
8178  // Call the Object's constructor with a String.
8179  value = CompileRun(
8180  "(function() { var o = new obj('tipli'); return o.a; })()");
8181  CHECK(!try_catch.HasCaught());
8182  CHECK(value->IsString());
8183  String::AsciiValue string_value1(value->ToString());
8184  CHECK_EQ("tipli", *string_value1);
8185 
8186  Local<Value> args2[] = { v8_str("tipli") };
8187  Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8188  CHECK(value_obj2->IsObject());
8189  Local<Object> object2 = Local<Object>::Cast(value_obj2);
8190  value = object2->Get(v8_str("a"));
8191  CHECK(!try_catch.HasCaught());
8192  CHECK(value->IsString());
8193  String::AsciiValue string_value2(value->ToString());
8194  CHECK_EQ("tipli", *string_value2);
8195 
8196  // Call the Object's constructor with a Boolean.
8197  value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8198  CHECK(!try_catch.HasCaught());
8199  CHECK(value->IsBoolean());
8200  CHECK_EQ(true, value->BooleanValue());
8201 
8202  Handle<Value> args3[] = { v8::True() };
8203  Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8204  CHECK(value_obj3->IsObject());
8205  Local<Object> object3 = Local<Object>::Cast(value_obj3);
8206  value = object3->Get(v8_str("a"));
8207  CHECK(!try_catch.HasCaught());
8208  CHECK(value->IsBoolean());
8209  CHECK_EQ(true, value->BooleanValue());
8210 
8211  // Call the Object's constructor with undefined.
8212  Handle<Value> args4[] = { v8::Undefined() };
8213  Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8214  CHECK(value_obj4->IsObject());
8215  Local<Object> object4 = Local<Object>::Cast(value_obj4);
8216  value = object4->Get(v8_str("a"));
8217  CHECK(!try_catch.HasCaught());
8218  CHECK(value->IsUndefined());
8219 
8220  // Call the Object's constructor with null.
8221  Handle<Value> args5[] = { v8::Null() };
8222  Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8223  CHECK(value_obj5->IsObject());
8224  Local<Object> object5 = Local<Object>::Cast(value_obj5);
8225  value = object5->Get(v8_str("a"));
8226  CHECK(!try_catch.HasCaught());
8227  CHECK(value->IsNull());
8228  }
8229 
8230  // Check exception handling when there is no constructor set for the Object.
8231  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8232  Local<Object> instance = instance_template->NewInstance();
8233  context->Global()->Set(v8_str("obj2"), instance);
8234  v8::TryCatch try_catch;
8235  Local<Value> value;
8236  CHECK(!try_catch.HasCaught());
8237 
8238  value = CompileRun("new obj2(28)");
8239  CHECK(try_catch.HasCaught());
8240  String::AsciiValue exception_value1(try_catch.Exception());
8241  CHECK_EQ("TypeError: object is not a function", *exception_value1);
8242  try_catch.Reset();
8243 
8244  Local<Value> args[] = { v8_num(29) };
8245  value = instance->CallAsConstructor(1, args);
8246  CHECK(try_catch.HasCaught());
8247  String::AsciiValue exception_value2(try_catch.Exception());
8248  CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8249  try_catch.Reset();
8250  }
8251 
8252  // Check the case when constructor throws exception.
8253  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8254  instance_template->SetCallAsFunctionHandler(ThrowValue);
8255  Local<Object> instance = instance_template->NewInstance();
8256  context->Global()->Set(v8_str("obj3"), instance);
8257  v8::TryCatch try_catch;
8258  Local<Value> value;
8259  CHECK(!try_catch.HasCaught());
8260 
8261  value = CompileRun("new obj3(22)");
8262  CHECK(try_catch.HasCaught());
8263  String::AsciiValue exception_value1(try_catch.Exception());
8264  CHECK_EQ("22", *exception_value1);
8265  try_catch.Reset();
8266 
8267  Local<Value> args[] = { v8_num(23) };
8268  value = instance->CallAsConstructor(1, args);
8269  CHECK(try_catch.HasCaught());
8270  String::AsciiValue exception_value2(try_catch.Exception());
8271  CHECK_EQ("23", *exception_value2);
8272  try_catch.Reset();
8273  }
8274 
8275  // Check whether constructor returns with an object or non-object.
8276  { Local<FunctionTemplate> function_template =
8277  FunctionTemplate::New(FakeConstructorCallback);
8278  Local<Function> function = function_template->GetFunction();
8279  Local<Object> instance1 = function;
8280  context->Global()->Set(v8_str("obj4"), instance1);
8281  v8::TryCatch try_catch;
8282  Local<Value> value;
8283  CHECK(!try_catch.HasCaught());
8284 
8285  CHECK(instance1->IsObject());
8286  CHECK(instance1->IsFunction());
8287 
8288  value = CompileRun("new obj4(28)");
8289  CHECK(!try_catch.HasCaught());
8290  CHECK(value->IsObject());
8291 
8292  Local<Value> args1[] = { v8_num(28) };
8293  value = instance1->CallAsConstructor(1, args1);
8294  CHECK(!try_catch.HasCaught());
8295  CHECK(value->IsObject());
8296 
8297  Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8298  instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8299  Local<Object> instance2 = instance_template->NewInstance();
8300  context->Global()->Set(v8_str("obj5"), instance2);
8301  CHECK(!try_catch.HasCaught());
8302 
8303  CHECK(instance2->IsObject());
8304  CHECK(!instance2->IsFunction());
8305 
8306  value = CompileRun("new obj5(28)");
8307  CHECK(!try_catch.HasCaught());
8308  CHECK(!value->IsObject());
8309 
8310  Local<Value> args2[] = { v8_num(28) };
8311  value = instance2->CallAsConstructor(1, args2);
8312  CHECK(!try_catch.HasCaught());
8313  CHECK(!value->IsObject());
8314  }
8315 }
8316 
8317 
8318 THREADED_TEST(FunctionDescriptorException) {
8319  v8::HandleScope handle_scope;
8320  LocalContext context;
8321  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8322  templ->SetClassName(v8_str("Fun"));
8323  Local<Function> cons = templ->GetFunction();
8324  context->Global()->Set(v8_str("Fun"), cons);
8325  Local<Value> value = CompileRun(
8326  "function test() {"
8327  " try {"
8328  " (new Fun()).blah()"
8329  " } catch (e) {"
8330  " var str = String(e);"
8331  " if (str.indexOf('TypeError') == -1) return 1;"
8332  " if (str.indexOf('[object Fun]') != -1) return 2;"
8333  " if (str.indexOf('#<Fun>') == -1) return 3;"
8334  " return 0;"
8335  " }"
8336  " return 4;"
8337  "}"
8338  "test();");
8339  CHECK_EQ(0, value->Int32Value());
8340 }
8341 
8342 
8343 THREADED_TEST(EvalAliasedDynamic) {
8344  v8::HandleScope scope;
8345  LocalContext current;
8346 
8347  // Tests where aliased eval can only be resolved dynamically.
8348  Local<Script> script =
8349  Script::Compile(v8_str("function f(x) { "
8350  " var foo = 2;"
8351  " with (x) { return eval('foo'); }"
8352  "}"
8353  "foo = 0;"
8354  "result1 = f(new Object());"
8355  "result2 = f(this);"
8356  "var x = new Object();"
8357  "x.eval = function(x) { return 1; };"
8358  "result3 = f(x);"));
8359  script->Run();
8360  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8361  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8362  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8363 
8364  v8::TryCatch try_catch;
8365  script =
8366  Script::Compile(v8_str("function f(x) { "
8367  " var bar = 2;"
8368  " with (x) { return eval('bar'); }"
8369  "}"
8370  "result4 = f(this)"));
8371  script->Run();
8372  CHECK(!try_catch.HasCaught());
8373  CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8374 
8375  try_catch.Reset();
8376 }
8377 
8378 
8379 THREADED_TEST(CrossEval) {
8380  v8::HandleScope scope;
8381  LocalContext other;
8382  LocalContext current;
8383 
8384  Local<String> token = v8_str("<security token>");
8385  other->SetSecurityToken(token);
8386  current->SetSecurityToken(token);
8387 
8388  // Set up reference from current to other.
8389  current->Global()->Set(v8_str("other"), other->Global());
8390 
8391  // Check that new variables are introduced in other context.
8392  Local<Script> script =
8393  Script::Compile(v8_str("other.eval('var foo = 1234')"));
8394  script->Run();
8395  Local<Value> foo = other->Global()->Get(v8_str("foo"));
8396  CHECK_EQ(1234, foo->Int32Value());
8397  CHECK(!current->Global()->Has(v8_str("foo")));
8398 
8399  // Check that writing to non-existing properties introduces them in
8400  // the other context.
8401  script =
8402  Script::Compile(v8_str("other.eval('na = 1234')"));
8403  script->Run();
8404  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8405  CHECK(!current->Global()->Has(v8_str("na")));
8406 
8407  // Check that global variables in current context are not visible in other
8408  // context.
8409  v8::TryCatch try_catch;
8410  script =
8411  Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
8412  Local<Value> result = script->Run();
8413  CHECK(try_catch.HasCaught());
8414  try_catch.Reset();
8415 
8416  // Check that local variables in current context are not visible in other
8417  // context.
8418  script =
8419  Script::Compile(v8_str("(function() { "
8420  " var baz = 87;"
8421  " return other.eval('baz');"
8422  "})();"));
8423  result = script->Run();
8424  CHECK(try_catch.HasCaught());
8425  try_catch.Reset();
8426 
8427  // Check that global variables in the other environment are visible
8428  // when evaluting code.
8429  other->Global()->Set(v8_str("bis"), v8_num(1234));
8430  script = Script::Compile(v8_str("other.eval('bis')"));
8431  CHECK_EQ(1234, script->Run()->Int32Value());
8432  CHECK(!try_catch.HasCaught());
8433 
8434  // Check that the 'this' pointer points to the global object evaluating
8435  // code.
8436  other->Global()->Set(v8_str("t"), other->Global());
8437  script = Script::Compile(v8_str("other.eval('this == t')"));
8438  result = script->Run();
8439  CHECK(result->IsTrue());
8440  CHECK(!try_catch.HasCaught());
8441 
8442  // Check that variables introduced in with-statement are not visible in
8443  // other context.
8444  script =
8445  Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8446  result = script->Run();
8447  CHECK(try_catch.HasCaught());
8448  try_catch.Reset();
8449 
8450  // Check that you cannot use 'eval.call' with another object than the
8451  // current global object.
8452  script =
8453  Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8454  result = script->Run();
8455  CHECK(try_catch.HasCaught());
8456 }
8457 
8458 
8459 // Test that calling eval in a context which has been detached from
8460 // its global throws an exception. This behavior is consistent with
8461 // other JavaScript implementations.
8462 THREADED_TEST(EvalInDetachedGlobal) {
8463  v8::HandleScope scope;
8464 
8465  v8::Persistent<Context> context0 = Context::New();
8466  v8::Persistent<Context> context1 = Context::New();
8467 
8468  // Set up function in context0 that uses eval from context0.
8469  context0->Enter();
8470  v8::Handle<v8::Value> fun =
8471  CompileRun("var x = 42;"
8472  "(function() {"
8473  " var e = eval;"
8474  " return function(s) { return e(s); }"
8475  "})()");
8476  context0->Exit();
8477 
8478  // Put the function into context1 and call it before and after
8479  // detaching the global. Before detaching, the call succeeds and
8480  // after detaching and exception is thrown.
8481  context1->Enter();
8482  context1->Global()->Set(v8_str("fun"), fun);
8483  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8484  CHECK_EQ(42, x_value->Int32Value());
8485  context0->DetachGlobal();
8486  v8::TryCatch catcher;
8487  x_value = CompileRun("fun('x')");
8488  CHECK(x_value.IsEmpty());
8489  CHECK(catcher.HasCaught());
8490  context1->Exit();
8491 
8492  context1.Dispose();
8493  context0.Dispose();
8494 }
8495 
8496 
8497 THREADED_TEST(CrossLazyLoad) {
8498  v8::HandleScope scope;
8499  LocalContext other;
8500  LocalContext current;
8501 
8502  Local<String> token = v8_str("<security token>");
8503  other->SetSecurityToken(token);
8504  current->SetSecurityToken(token);
8505 
8506  // Set up reference from current to other.
8507  current->Global()->Set(v8_str("other"), other->Global());
8508 
8509  // Trigger lazy loading in other context.
8510  Local<Script> script =
8511  Script::Compile(v8_str("other.eval('new Date(42)')"));
8512  Local<Value> value = script->Run();
8513  CHECK_EQ(42.0, value->NumberValue());
8514 }
8515 
8516 
8517 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8519  if (args.IsConstructCall()) {
8520  if (args[0]->IsInt32()) {
8521  return v8_num(-args[0]->Int32Value());
8522  }
8523  }
8524 
8525  return args[0];
8526 }
8527 
8528 
8529 // Test that a call handler can be set for objects which will allow
8530 // non-function objects created through the API to be called as
8531 // functions.
8532 THREADED_TEST(CallAsFunction) {
8533  v8::HandleScope scope;
8534  LocalContext context;
8535 
8536  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8537  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8538  instance_template->SetCallAsFunctionHandler(call_as_function);
8539  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8540  context->Global()->Set(v8_str("obj"), instance);
8541  v8::TryCatch try_catch;
8542  Local<Value> value;
8543  CHECK(!try_catch.HasCaught());
8544 
8545  value = CompileRun("obj(42)");
8546  CHECK(!try_catch.HasCaught());
8547  CHECK_EQ(42, value->Int32Value());
8548 
8549  value = CompileRun("(function(o){return o(49)})(obj)");
8550  CHECK(!try_catch.HasCaught());
8551  CHECK_EQ(49, value->Int32Value());
8552 
8553  // test special case of call as function
8554  value = CompileRun("[obj]['0'](45)");
8555  CHECK(!try_catch.HasCaught());
8556  CHECK_EQ(45, value->Int32Value());
8557 
8558  value = CompileRun("obj.call = Function.prototype.call;"
8559  "obj.call(null, 87)");
8560  CHECK(!try_catch.HasCaught());
8561  CHECK_EQ(87, value->Int32Value());
8562 
8563  // Regression tests for bug #1116356: Calling call through call/apply
8564  // must work for non-function receivers.
8565  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8566  value = CompileRun(apply_99);
8567  CHECK(!try_catch.HasCaught());
8568  CHECK_EQ(99, value->Int32Value());
8569 
8570  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8571  value = CompileRun(call_17);
8572  CHECK(!try_catch.HasCaught());
8573  CHECK_EQ(17, value->Int32Value());
8574 
8575  // Check that the call-as-function handler can be called through
8576  // new.
8577  value = CompileRun("new obj(43)");
8578  CHECK(!try_catch.HasCaught());
8579  CHECK_EQ(-43, value->Int32Value());
8580 
8581  // Check that the call-as-function handler can be called through
8582  // the API.
8583  v8::Handle<Value> args[] = { v8_num(28) };
8584  value = instance->CallAsFunction(instance, 1, args);
8585  CHECK(!try_catch.HasCaught());
8586  CHECK_EQ(28, value->Int32Value());
8587  }
8588 
8589  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8590  Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8591  USE(instance_template);
8592  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8593  context->Global()->Set(v8_str("obj2"), instance);
8594  v8::TryCatch try_catch;
8595  Local<Value> value;
8596  CHECK(!try_catch.HasCaught());
8597 
8598  // Call an object without call-as-function handler through the JS
8599  value = CompileRun("obj2(28)");
8600  CHECK(value.IsEmpty());
8601  CHECK(try_catch.HasCaught());
8602  String::AsciiValue exception_value1(try_catch.Exception());
8603  CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8604  *exception_value1);
8605  try_catch.Reset();
8606 
8607  // Call an object without call-as-function handler through the API
8608  value = CompileRun("obj2(28)");
8609  v8::Handle<Value> args[] = { v8_num(28) };
8610  value = instance->CallAsFunction(instance, 1, args);
8611  CHECK(value.IsEmpty());
8612  CHECK(try_catch.HasCaught());
8613  String::AsciiValue exception_value2(try_catch.Exception());
8614  CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8615  try_catch.Reset();
8616  }
8617 
8618  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8619  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8620  instance_template->SetCallAsFunctionHandler(ThrowValue);
8621  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8622  context->Global()->Set(v8_str("obj3"), instance);
8623  v8::TryCatch try_catch;
8624  Local<Value> value;
8625  CHECK(!try_catch.HasCaught());
8626 
8627  // Catch the exception which is thrown by call-as-function handler
8628  value = CompileRun("obj3(22)");
8629  CHECK(try_catch.HasCaught());
8630  String::AsciiValue exception_value1(try_catch.Exception());
8631  CHECK_EQ("22", *exception_value1);
8632  try_catch.Reset();
8633 
8634  v8::Handle<Value> args[] = { v8_num(23) };
8635  value = instance->CallAsFunction(instance, 1, args);
8636  CHECK(try_catch.HasCaught());
8637  String::AsciiValue exception_value2(try_catch.Exception());
8638  CHECK_EQ("23", *exception_value2);
8639  try_catch.Reset();
8640  }
8641 }
8642 
8643 
8644 // Check whether a non-function object is callable.
8645 THREADED_TEST(CallableObject) {
8646  v8::HandleScope scope;
8647  LocalContext context;
8648 
8649  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8650  instance_template->SetCallAsFunctionHandler(call_as_function);
8651  Local<Object> instance = instance_template->NewInstance();
8652  v8::TryCatch try_catch;
8653 
8654  CHECK(instance->IsCallable());
8655  CHECK(!try_catch.HasCaught());
8656  }
8657 
8658  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8659  Local<Object> instance = instance_template->NewInstance();
8660  v8::TryCatch try_catch;
8661 
8662  CHECK(!instance->IsCallable());
8663  CHECK(!try_catch.HasCaught());
8664  }
8665 
8666  { Local<FunctionTemplate> function_template =
8667  FunctionTemplate::New(call_as_function);
8668  Local<Function> function = function_template->GetFunction();
8669  Local<Object> instance = function;
8670  v8::TryCatch try_catch;
8671 
8672  CHECK(instance->IsCallable());
8673  CHECK(!try_catch.HasCaught());
8674  }
8675 
8676  { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8677  Local<Function> function = function_template->GetFunction();
8678  Local<Object> instance = function;
8679  v8::TryCatch try_catch;
8680 
8681  CHECK(instance->IsCallable());
8682  CHECK(!try_catch.HasCaught());
8683  }
8684 }
8685 
8686 
8687 static int CountHandles() {
8689 }
8690 
8691 
8692 static int Recurse(int depth, int iterations) {
8693  v8::HandleScope scope;
8694  if (depth == 0) return CountHandles();
8695  for (int i = 0; i < iterations; i++) {
8696  Local<v8::Number> n(v8::Integer::New(42));
8697  }
8698  return Recurse(depth - 1, iterations);
8699 }
8700 
8701 
8702 THREADED_TEST(HandleIteration) {
8703  static const int kIterations = 500;
8704  static const int kNesting = 200;
8705  CHECK_EQ(0, CountHandles());
8706  {
8707  v8::HandleScope scope1;
8708  CHECK_EQ(0, CountHandles());
8709  for (int i = 0; i < kIterations; i++) {
8710  Local<v8::Number> n(v8::Integer::New(42));
8711  CHECK_EQ(i + 1, CountHandles());
8712  }
8713 
8714  CHECK_EQ(kIterations, CountHandles());
8715  {
8716  v8::HandleScope scope2;
8717  for (int j = 0; j < kIterations; j++) {
8718  Local<v8::Number> n(v8::Integer::New(42));
8719  CHECK_EQ(j + 1 + kIterations, CountHandles());
8720  }
8721  }
8722  CHECK_EQ(kIterations, CountHandles());
8723  }
8724  CHECK_EQ(0, CountHandles());
8725  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8726 }
8727 
8728 
8729 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8730  Local<String> name,
8731  const AccessorInfo& info) {
8733  return v8::Handle<Value>();
8734 }
8735 
8736 
8737 THREADED_TEST(InterceptorHasOwnProperty) {
8738  v8::HandleScope scope;
8739  LocalContext context;
8740  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8741  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8742  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8743  Local<Function> function = fun_templ->GetFunction();
8744  context->Global()->Set(v8_str("constructor"), function);
8745  v8::Handle<Value> value = CompileRun(
8746  "var o = new constructor();"
8747  "o.hasOwnProperty('ostehaps');");
8748  CHECK_EQ(false, value->BooleanValue());
8749  value = CompileRun(
8750  "o.ostehaps = 42;"
8751  "o.hasOwnProperty('ostehaps');");
8752  CHECK_EQ(true, value->BooleanValue());
8753  value = CompileRun(
8754  "var p = new constructor();"
8755  "p.hasOwnProperty('ostehaps');");
8756  CHECK_EQ(false, value->BooleanValue());
8757 }
8758 
8759 
8760 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8761  Local<String> name,
8762  const AccessorInfo& info) {
8764  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8765  return v8::Handle<Value>();
8766 }
8767 
8768 
8769 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8770  v8::HandleScope scope;
8771  LocalContext context;
8772  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8773  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8774  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8775  Local<Function> function = fun_templ->GetFunction();
8776  context->Global()->Set(v8_str("constructor"), function);
8777  // Let's first make some stuff so we can be sure to get a good GC.
8778  CompileRun(
8779  "function makestr(size) {"
8780  " switch (size) {"
8781  " case 1: return 'f';"
8782  " case 2: return 'fo';"
8783  " case 3: return 'foo';"
8784  " }"
8785  " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8786  "}"
8787  "var x = makestr(12345);"
8788  "x = makestr(31415);"
8789  "x = makestr(23456);");
8790  v8::Handle<Value> value = CompileRun(
8791  "var o = new constructor();"
8792  "o.__proto__ = new String(x);"
8793  "o.hasOwnProperty('ostehaps');");
8794  CHECK_EQ(false, value->BooleanValue());
8795 }
8796 
8797 
8798 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8799  const AccessorInfo& info);
8800 
8801 
8802 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8803  const char* source,
8804  int expected) {
8805  v8::HandleScope scope;
8806  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8807  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8808  LocalContext context;
8809  context->Global()->Set(v8_str("o"), templ->NewInstance());
8810  v8::Handle<Value> value = CompileRun(source);
8811  CHECK_EQ(expected, value->Int32Value());
8812 }
8813 
8814 
8815 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8816  const AccessorInfo& info) {
8818  v8::Isolate* isolate = v8::Isolate::GetCurrent();
8819  CHECK_EQ(isolate, info.GetIsolate());
8820  CHECK_EQ(v8_str("data"), info.Data());
8821  CHECK_EQ(v8_str("x"), name);
8822  return v8::Integer::New(42);
8823 }
8824 
8825 
8826 // This test should hit the load IC for the interceptor case.
8827 THREADED_TEST(InterceptorLoadIC) {
8828  CheckInterceptorLoadIC(InterceptorLoadICGetter,
8829  "var result = 0;"
8830  "for (var i = 0; i < 1000; i++) {"
8831  " result = o.x;"
8832  "}",
8833  42);
8834 }
8835 
8836 
8837 // Below go several tests which verify that JITing for various
8838 // configurations of interceptor and explicit fields works fine
8839 // (those cases are special cased to get better performance).
8840 
8841 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8842  const AccessorInfo& info) {
8844  return v8_str("x")->Equals(name)
8845  ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8846 }
8847 
8848 
8849 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8850  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8851  "var result = 0;"
8852  "o.y = 239;"
8853  "for (var i = 0; i < 1000; i++) {"
8854  " result = o.y;"
8855  "}",
8856  239);
8857 }
8858 
8859 
8860 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8861  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8862  "var result = 0;"
8863  "o.__proto__ = { 'y': 239 };"
8864  "for (var i = 0; i < 1000; i++) {"
8865  " result = o.y + o.x;"
8866  "}",
8867  239 + 42);
8868 }
8869 
8870 
8871 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8872  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8873  "var result = 0;"
8874  "o.__proto__.y = 239;"
8875  "for (var i = 0; i < 1000; i++) {"
8876  " result = o.y + o.x;"
8877  "}",
8878  239 + 42);
8879 }
8880 
8881 
8882 THREADED_TEST(InterceptorLoadICUndefined) {
8883  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8884  "var result = 0;"
8885  "for (var i = 0; i < 1000; i++) {"
8886  " result = (o.y == undefined) ? 239 : 42;"
8887  "}",
8888  239);
8889 }
8890 
8891 
8892 THREADED_TEST(InterceptorLoadICWithOverride) {
8893  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8894  "fst = new Object(); fst.__proto__ = o;"
8895  "snd = new Object(); snd.__proto__ = fst;"
8896  "var result1 = 0;"
8897  "for (var i = 0; i < 1000; i++) {"
8898  " result1 = snd.x;"
8899  "}"
8900  "fst.x = 239;"
8901  "var result = 0;"
8902  "for (var i = 0; i < 1000; i++) {"
8903  " result = snd.x;"
8904  "}"
8905  "result + result1",
8906  239 + 42);
8907 }
8908 
8909 
8910 // Test the case when we stored field into
8911 // a stub, but interceptor produced value on its own.
8912 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8913  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8914  "proto = new Object();"
8915  "o.__proto__ = proto;"
8916  "proto.x = 239;"
8917  "for (var i = 0; i < 1000; i++) {"
8918  " o.x;"
8919  // Now it should be ICed and keep a reference to x defined on proto
8920  "}"
8921  "var result = 0;"
8922  "for (var i = 0; i < 1000; i++) {"
8923  " result += o.x;"
8924  "}"
8925  "result;",
8926  42 * 1000);
8927 }
8928 
8929 
8930 // Test the case when we stored field into
8931 // a stub, but it got invalidated later on.
8932 THREADED_TEST(InterceptorLoadICInvalidatedField) {
8933  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8934  "proto1 = new Object();"
8935  "proto2 = new Object();"
8936  "o.__proto__ = proto1;"
8937  "proto1.__proto__ = proto2;"
8938  "proto2.y = 239;"
8939  "for (var i = 0; i < 1000; i++) {"
8940  " o.y;"
8941  // Now it should be ICed and keep a reference to y defined on proto2
8942  "}"
8943  "proto1.y = 42;"
8944  "var result = 0;"
8945  "for (var i = 0; i < 1000; i++) {"
8946  " result += o.y;"
8947  "}"
8948  "result;",
8949  42 * 1000);
8950 }
8951 
8952 
8953 static int interceptor_load_not_handled_calls = 0;
8954 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8955  const AccessorInfo& info) {
8956  ++interceptor_load_not_handled_calls;
8957  return v8::Handle<v8::Value>();
8958 }
8959 
8960 
8961 // Test how post-interceptor lookups are done in the non-cacheable
8962 // case: the interceptor should not be invoked during this lookup.
8963 THREADED_TEST(InterceptorLoadICPostInterceptor) {
8964  interceptor_load_not_handled_calls = 0;
8965  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8966  "receiver = new Object();"
8967  "receiver.__proto__ = o;"
8968  "proto = new Object();"
8969  "/* Make proto a slow-case object. */"
8970  "for (var i = 0; i < 1000; i++) {"
8971  " proto[\"xxxxxxxx\" + i] = [];"
8972  "}"
8973  "proto.x = 17;"
8974  "o.__proto__ = proto;"
8975  "var result = 0;"
8976  "for (var i = 0; i < 1000; i++) {"
8977  " result += receiver.x;"
8978  "}"
8979  "result;",
8980  17 * 1000);
8981  CHECK_EQ(1000, interceptor_load_not_handled_calls);
8982 }
8983 
8984 
8985 // Test the case when we stored field into
8986 // a stub, but it got invalidated later on due to override on
8987 // global object which is between interceptor and fields' holders.
8988 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8989  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8990  "o.__proto__ = this;" // set a global to be a proto of o.
8991  "this.__proto__.y = 239;"
8992  "for (var i = 0; i < 10; i++) {"
8993  " if (o.y != 239) throw 'oops: ' + o.y;"
8994  // Now it should be ICed and keep a reference to y defined on field_holder.
8995  "}"
8996  "this.y = 42;" // Assign on a global.
8997  "var result = 0;"
8998  "for (var i = 0; i < 10; i++) {"
8999  " result += o.y;"
9000  "}"
9001  "result;",
9002  42 * 10);
9003 }
9004 
9005 
9006 static void SetOnThis(Local<String> name,
9007  Local<Value> value,
9008  const AccessorInfo& info) {
9009  info.This()->ForceSet(name, value);
9010 }
9011 
9012 
9013 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9014  v8::HandleScope scope;
9015  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9016  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9017  templ->SetAccessor(v8_str("y"), Return239);
9018  LocalContext context;
9019  context->Global()->Set(v8_str("o"), templ->NewInstance());
9020 
9021  // Check the case when receiver and interceptor's holder
9022  // are the same objects.
9023  v8::Handle<Value> value = CompileRun(
9024  "var result = 0;"
9025  "for (var i = 0; i < 7; i++) {"
9026  " result = o.y;"
9027  "}");
9028  CHECK_EQ(239, value->Int32Value());
9029 
9030  // Check the case when interceptor's holder is in proto chain
9031  // of receiver.
9032  value = CompileRun(
9033  "r = { __proto__: o };"
9034  "var result = 0;"
9035  "for (var i = 0; i < 7; i++) {"
9036  " result = r.y;"
9037  "}");
9038  CHECK_EQ(239, value->Int32Value());
9039 }
9040 
9041 
9042 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9043  v8::HandleScope scope;
9044  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9045  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9046  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9047  templ_p->SetAccessor(v8_str("y"), Return239);
9048 
9049  LocalContext context;
9050  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9051  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9052 
9053  // Check the case when receiver and interceptor's holder
9054  // are the same objects.
9055  v8::Handle<Value> value = CompileRun(
9056  "o.__proto__ = p;"
9057  "var result = 0;"
9058  "for (var i = 0; i < 7; i++) {"
9059  " result = o.x + o.y;"
9060  "}");
9061  CHECK_EQ(239 + 42, value->Int32Value());
9062 
9063  // Check the case when interceptor's holder is in proto chain
9064  // of receiver.
9065  value = CompileRun(
9066  "r = { __proto__: o };"
9067  "var result = 0;"
9068  "for (var i = 0; i < 7; i++) {"
9069  " result = r.x + r.y;"
9070  "}");
9071  CHECK_EQ(239 + 42, value->Int32Value());
9072 }
9073 
9074 
9075 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9076  v8::HandleScope scope;
9077  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9078  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9079  templ->SetAccessor(v8_str("y"), Return239);
9080 
9081  LocalContext context;
9082  context->Global()->Set(v8_str("o"), templ->NewInstance());
9083 
9084  v8::Handle<Value> value = CompileRun(
9085  "fst = new Object(); fst.__proto__ = o;"
9086  "snd = new Object(); snd.__proto__ = fst;"
9087  "var result1 = 0;"
9088  "for (var i = 0; i < 7; i++) {"
9089  " result1 = snd.x;"
9090  "}"
9091  "fst.x = 239;"
9092  "var result = 0;"
9093  "for (var i = 0; i < 7; i++) {"
9094  " result = snd.x;"
9095  "}"
9096  "result + result1");
9097  CHECK_EQ(239 + 42, value->Int32Value());
9098 }
9099 
9100 
9101 // Test the case when we stored callback into
9102 // a stub, but interceptor produced value on its own.
9103 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9104  v8::HandleScope scope;
9105  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9106  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9107  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9108  templ_p->SetAccessor(v8_str("y"), Return239);
9109 
9110  LocalContext context;
9111  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9112  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9113 
9114  v8::Handle<Value> value = CompileRun(
9115  "o.__proto__ = p;"
9116  "for (var i = 0; i < 7; i++) {"
9117  " o.x;"
9118  // Now it should be ICed and keep a reference to x defined on p
9119  "}"
9120  "var result = 0;"
9121  "for (var i = 0; i < 7; i++) {"
9122  " result += o.x;"
9123  "}"
9124  "result");
9125  CHECK_EQ(42 * 7, value->Int32Value());
9126 }
9127 
9128 
9129 // Test the case when we stored callback into
9130 // a stub, but it got invalidated later on.
9131 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9132  v8::HandleScope scope;
9133  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9134  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9135  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9136  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9137 
9138  LocalContext context;
9139  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9140  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9141 
9142  v8::Handle<Value> value = CompileRun(
9143  "inbetween = new Object();"
9144  "o.__proto__ = inbetween;"
9145  "inbetween.__proto__ = p;"
9146  "for (var i = 0; i < 10; i++) {"
9147  " o.y;"
9148  // Now it should be ICed and keep a reference to y defined on p
9149  "}"
9150  "inbetween.y = 42;"
9151  "var result = 0;"
9152  "for (var i = 0; i < 10; i++) {"
9153  " result += o.y;"
9154  "}"
9155  "result");
9156  CHECK_EQ(42 * 10, value->Int32Value());
9157 }
9158 
9159 
9160 // Test the case when we stored callback into
9161 // a stub, but it got invalidated later on due to override on
9162 // global object which is between interceptor and callbacks' holders.
9163 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9164  v8::HandleScope scope;
9165  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9166  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9167  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9168  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9169 
9170  LocalContext context;
9171  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9172  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9173 
9174  v8::Handle<Value> value = CompileRun(
9175  "o.__proto__ = this;"
9176  "this.__proto__ = p;"
9177  "for (var i = 0; i < 10; i++) {"
9178  " if (o.y != 239) throw 'oops: ' + o.y;"
9179  // Now it should be ICed and keep a reference to y defined on p
9180  "}"
9181  "this.y = 42;"
9182  "var result = 0;"
9183  "for (var i = 0; i < 10; i++) {"
9184  " result += o.y;"
9185  "}"
9186  "result");
9187  CHECK_EQ(42 * 10, value->Int32Value());
9188 }
9189 
9190 
9191 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9192  const AccessorInfo& info) {
9194  CHECK(v8_str("x")->Equals(name));
9195  return v8::Integer::New(0);
9196 }
9197 
9198 
9199 THREADED_TEST(InterceptorReturningZero) {
9200  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9201  "o.x == undefined ? 1 : 0",
9202  0);
9203 }
9204 
9205 
9206 static v8::Handle<Value> InterceptorStoreICSetter(
9207  Local<String> key, Local<Value> value, const AccessorInfo&) {
9208  CHECK(v8_str("x")->Equals(key));
9209  CHECK_EQ(42, value->Int32Value());
9210  return value;
9211 }
9212 
9213 
9214 // This test should hit the store IC for the interceptor case.
9215 THREADED_TEST(InterceptorStoreIC) {
9216  v8::HandleScope scope;
9217  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9218  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
9219  InterceptorStoreICSetter,
9220  0, 0, 0, v8_str("data"));
9221  LocalContext context;
9222  context->Global()->Set(v8_str("o"), templ->NewInstance());
9223  CompileRun(
9224  "for (var i = 0; i < 1000; i++) {"
9225  " o.x = 42;"
9226  "}");
9227 }
9228 
9229 
9230 THREADED_TEST(InterceptorStoreICWithNoSetter) {
9231  v8::HandleScope scope;
9232  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9233  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9234  LocalContext context;
9235  context->Global()->Set(v8_str("o"), templ->NewInstance());
9236  v8::Handle<Value> value = CompileRun(
9237  "for (var i = 0; i < 1000; i++) {"
9238  " o.y = 239;"
9239  "}"
9240  "42 + o.y");
9241  CHECK_EQ(239 + 42, value->Int32Value());
9242 }
9243 
9244 
9245 
9246 
9250 
9251 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9252  const AccessorInfo& info) {
9254  CHECK(v8_str("x")->Equals(name));
9255  return call_ic_function;
9256 }
9257 
9258 
9259 // This test should hit the call IC for the interceptor case.
9260 THREADED_TEST(InterceptorCallIC) {
9261  v8::HandleScope scope;
9262  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9263  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9264  LocalContext context;
9265  context->Global()->Set(v8_str("o"), templ->NewInstance());
9266  call_ic_function =
9267  v8_compile("function f(x) { return x + 1; }; f")->Run();
9268  v8::Handle<Value> value = CompileRun(
9269  "var result = 0;"
9270  "for (var i = 0; i < 1000; i++) {"
9271  " result = o.x(41);"
9272  "}");
9273  CHECK_EQ(42, value->Int32Value());
9274 }
9275 
9276 
9277 // This test checks that if interceptor doesn't provide
9278 // a value, we can fetch regular value.
9279 THREADED_TEST(InterceptorCallICSeesOthers) {
9280  v8::HandleScope scope;
9281  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9282  templ->SetNamedPropertyHandler(NoBlockGetterX);
9283  LocalContext context;
9284  context->Global()->Set(v8_str("o"), templ->NewInstance());
9285  v8::Handle<Value> value = CompileRun(
9286  "o.x = function f(x) { return x + 1; };"
9287  "var result = 0;"
9288  "for (var i = 0; i < 7; i++) {"
9289  " result = o.x(41);"
9290  "}");
9291  CHECK_EQ(42, value->Int32Value());
9292 }
9293 
9294 
9295 static v8::Handle<Value> call_ic_function4;
9296 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9297  const AccessorInfo& info) {
9299  CHECK(v8_str("x")->Equals(name));
9300  return call_ic_function4;
9301 }
9302 
9303 
9304 // This test checks that if interceptor provides a function,
9305 // even if we cached shadowed variant, interceptor's function
9306 // is invoked
9307 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9308  v8::HandleScope scope;
9309  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9310  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9311  LocalContext context;
9312  context->Global()->Set(v8_str("o"), templ->NewInstance());
9313  call_ic_function4 =
9314  v8_compile("function f(x) { return x - 1; }; f")->Run();
9315  v8::Handle<Value> value = CompileRun(
9316  "o.__proto__.x = function(x) { return x + 1; };"
9317  "var result = 0;"
9318  "for (var i = 0; i < 1000; i++) {"
9319  " result = o.x(42);"
9320  "}");
9321  CHECK_EQ(41, value->Int32Value());
9322 }
9323 
9324 
9325 // Test the case when we stored cacheable lookup into
9326 // a stub, but it got invalidated later on
9327 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9328  v8::HandleScope scope;
9329  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9330  templ->SetNamedPropertyHandler(NoBlockGetterX);
9331  LocalContext context;
9332  context->Global()->Set(v8_str("o"), templ->NewInstance());
9333  v8::Handle<Value> value = CompileRun(
9334  "proto1 = new Object();"
9335  "proto2 = new Object();"
9336  "o.__proto__ = proto1;"
9337  "proto1.__proto__ = proto2;"
9338  "proto2.y = function(x) { return x + 1; };"
9339  // Invoke it many times to compile a stub
9340  "for (var i = 0; i < 7; i++) {"
9341  " o.y(42);"
9342  "}"
9343  "proto1.y = function(x) { return x - 1; };"
9344  "var result = 0;"
9345  "for (var i = 0; i < 7; i++) {"
9346  " result += o.y(42);"
9347  "}");
9348  CHECK_EQ(41 * 7, value->Int32Value());
9349 }
9350 
9351 
9352 // This test checks that if interceptor doesn't provide a function,
9353 // cached constant function is used
9354 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9355  v8::HandleScope scope;
9356  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9357  templ->SetNamedPropertyHandler(NoBlockGetterX);
9358  LocalContext context;
9359  context->Global()->Set(v8_str("o"), templ->NewInstance());
9360  v8::Handle<Value> value = CompileRun(
9361  "function inc(x) { return x + 1; };"
9362  "inc(1);"
9363  "o.x = inc;"
9364  "var result = 0;"
9365  "for (var i = 0; i < 1000; i++) {"
9366  " result = o.x(42);"
9367  "}");
9368  CHECK_EQ(43, value->Int32Value());
9369 }
9370 
9371 
9372 static v8::Handle<Value> call_ic_function5;
9373 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9374  const AccessorInfo& info) {
9376  if (v8_str("x")->Equals(name))
9377  return call_ic_function5;
9378  else
9379  return Local<Value>();
9380 }
9381 
9382 
9383 // This test checks that if interceptor provides a function,
9384 // even if we cached constant function, interceptor's function
9385 // is invoked
9386 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9387  v8::HandleScope scope;
9388  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9389  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9390  LocalContext context;
9391  context->Global()->Set(v8_str("o"), templ->NewInstance());
9392  call_ic_function5 =
9393  v8_compile("function f(x) { return x - 1; }; f")->Run();
9394  v8::Handle<Value> value = CompileRun(
9395  "function inc(x) { return x + 1; };"
9396  "inc(1);"
9397  "o.x = inc;"
9398  "var result = 0;"
9399  "for (var i = 0; i < 1000; i++) {"
9400  " result = o.x(42);"
9401  "}");
9402  CHECK_EQ(41, value->Int32Value());
9403 }
9404 
9405 
9406 static v8::Handle<Value> call_ic_function6;
9407 static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9408  const AccessorInfo& info) {
9410  if (v8_str("x")->Equals(name))
9411  return call_ic_function6;
9412  else
9413  return Local<Value>();
9414 }
9415 
9416 
9417 // Same test as above, except the code is wrapped in a function
9418 // to test the optimized compiler.
9419 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9420  i::FLAG_allow_natives_syntax = true;
9421  v8::HandleScope scope;
9422  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9423  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9424  LocalContext context;
9425  context->Global()->Set(v8_str("o"), templ->NewInstance());
9426  call_ic_function6 =
9427  v8_compile("function f(x) { return x - 1; }; f")->Run();
9428  v8::Handle<Value> value = CompileRun(
9429  "function inc(x) { return x + 1; };"
9430  "inc(1);"
9431  "o.x = inc;"
9432  "function test() {"
9433  " var result = 0;"
9434  " for (var i = 0; i < 1000; i++) {"
9435  " result = o.x(42);"
9436  " }"
9437  " return result;"
9438  "};"
9439  "test();"
9440  "test();"
9441  "test();"
9442  "%OptimizeFunctionOnNextCall(test);"
9443  "test()");
9444  CHECK_EQ(41, value->Int32Value());
9445 }
9446 
9447 
9448 // Test the case when we stored constant function into
9449 // a stub, but it got invalidated later on
9450 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9451  v8::HandleScope scope;
9452  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9453  templ->SetNamedPropertyHandler(NoBlockGetterX);
9454  LocalContext context;
9455  context->Global()->Set(v8_str("o"), templ->NewInstance());
9456  v8::Handle<Value> value = CompileRun(
9457  "function inc(x) { return x + 1; };"
9458  "inc(1);"
9459  "proto1 = new Object();"
9460  "proto2 = new Object();"
9461  "o.__proto__ = proto1;"
9462  "proto1.__proto__ = proto2;"
9463  "proto2.y = inc;"
9464  // Invoke it many times to compile a stub
9465  "for (var i = 0; i < 7; i++) {"
9466  " o.y(42);"
9467  "}"
9468  "proto1.y = function(x) { return x - 1; };"
9469  "var result = 0;"
9470  "for (var i = 0; i < 7; i++) {"
9471  " result += o.y(42);"
9472  "}");
9473  CHECK_EQ(41 * 7, value->Int32Value());
9474 }
9475 
9476 
9477 // Test the case when we stored constant function into
9478 // a stub, but it got invalidated later on due to override on
9479 // global object which is between interceptor and constant function' holders.
9480 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9481  v8::HandleScope scope;
9482  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9483  templ->SetNamedPropertyHandler(NoBlockGetterX);
9484  LocalContext context;
9485  context->Global()->Set(v8_str("o"), templ->NewInstance());
9486  v8::Handle<Value> value = CompileRun(
9487  "function inc(x) { return x + 1; };"
9488  "inc(1);"
9489  "o.__proto__ = this;"
9490  "this.__proto__.y = inc;"
9491  // Invoke it many times to compile a stub
9492  "for (var i = 0; i < 7; i++) {"
9493  " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9494  "}"
9495  "this.y = function(x) { return x - 1; };"
9496  "var result = 0;"
9497  "for (var i = 0; i < 7; i++) {"
9498  " result += o.y(42);"
9499  "}");
9500  CHECK_EQ(41 * 7, value->Int32Value());
9501 }
9502 
9503 
9504 // Test the case when actual function to call sits on global object.
9505 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9506  v8::HandleScope scope;
9507  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9508  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9509 
9510  LocalContext context;
9511  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9512 
9513  v8::Handle<Value> value = CompileRun(
9514  "try {"
9515  " o.__proto__ = this;"
9516  " for (var i = 0; i < 10; i++) {"
9517  " var v = o.parseFloat('239');"
9518  " if (v != 239) throw v;"
9519  // Now it should be ICed and keep a reference to parseFloat.
9520  " }"
9521  " var result = 0;"
9522  " for (var i = 0; i < 10; i++) {"
9523  " result += o.parseFloat('239');"
9524  " }"
9525  " result"
9526  "} catch(e) {"
9527  " e"
9528  "};");
9529  CHECK_EQ(239 * 10, value->Int32Value());
9530 }
9531 
9532 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9533  const AccessorInfo& info) {
9535  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9536  ++(*call_count);
9537  if ((*call_count) % 20 == 0) {
9538  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
9539  }
9540  return v8::Handle<Value>();
9541 }
9542 
9543 static v8::Handle<Value> FastApiCallback_TrivialSignature(
9544  const v8::Arguments& args) {
9546  v8::Isolate* isolate = v8::Isolate::GetCurrent();
9547  CHECK_EQ(isolate, args.GetIsolate());
9548  CHECK_EQ(args.This(), args.Holder());
9549  CHECK(args.Data()->Equals(v8_str("method_data")));
9550  return v8::Integer::New(args[0]->Int32Value() + 1);
9551 }
9552 
9553 static v8::Handle<Value> FastApiCallback_SimpleSignature(
9554  const v8::Arguments& args) {
9556  v8::Isolate* isolate = v8::Isolate::GetCurrent();
9557  CHECK_EQ(isolate, args.GetIsolate());
9558  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9559  CHECK(args.Data()->Equals(v8_str("method_data")));
9560  // Note, we're using HasRealNamedProperty instead of Has to avoid
9561  // invoking the interceptor again.
9562  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9563  return v8::Integer::New(args[0]->Int32Value() + 1);
9564 }
9565 
9566 // Helper to maximize the odds of object moving.
9567 static void GenerateSomeGarbage() {
9568  CompileRun(
9569  "var garbage;"
9570  "for (var i = 0; i < 1000; i++) {"
9571  " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9572  "}"
9573  "garbage = undefined;");
9574 }
9575 
9576 
9578  static int count = 0;
9579  if (count++ % 3 == 0) {
9580  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9581  // This should move the stub
9582  GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9583  }
9584  return v8::Handle<v8::Value>();
9585 }
9586 
9587 
9588 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9589  v8::HandleScope scope;
9590  LocalContext context;
9592  nativeobject_templ->Set("callback",
9594  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9595  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9596  // call the api function multiple times to ensure direct call stub creation.
9597  CompileRun(
9598  "function f() {"
9599  " for (var i = 1; i <= 30; i++) {"
9600  " nativeobject.callback();"
9601  " }"
9602  "}"
9603  "f();");
9604 }
9605 
9606 
9608  return v8::ThrowException(v8_str("g"));
9609 }
9610 
9611 
9612 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9613  v8::HandleScope scope;
9614  LocalContext context;
9616  nativeobject_templ->Set("callback",
9618  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9619  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9620  // call the api function multiple times to ensure direct call stub creation.
9621  v8::Handle<Value> result = CompileRun(
9622  "var result = '';"
9623  "function f() {"
9624  " for (var i = 1; i <= 5; i++) {"
9625  " try { nativeobject.callback(); } catch (e) { result += e; }"
9626  " }"
9627  "}"
9628  "f(); result;");
9629  CHECK_EQ(v8_str("ggggg"), result);
9630 }
9631 
9632 
9634  const v8::AccessorInfo& info) {
9635  if (++p_getter_count % 3 == 0) {
9636  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9637  GenerateSomeGarbage();
9638  }
9639  return v8::Handle<v8::Value>();
9640 }
9641 
9642 
9643 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9644  v8::HandleScope scope;
9645  LocalContext context;
9647  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9648  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9649  p_getter_count = 0;
9650  CompileRun(
9651  "function f() {"
9652  " for (var i = 0; i < 30; i++) o1.p1;"
9653  "}"
9654  "f();");
9655  CHECK_EQ(30, p_getter_count);
9656 }
9657 
9658 
9660  Local<String> name, const v8::AccessorInfo& info) {
9661  return v8::ThrowException(v8_str("g"));
9662 }
9663 
9664 
9665 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9666  v8::HandleScope scope;
9667  LocalContext context;
9669  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9670  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9671  v8::Handle<Value> result = CompileRun(
9672  "var result = '';"
9673  "for (var i = 0; i < 5; i++) {"
9674  " try { o1.p1; } catch (e) { result += e; }"
9675  "}"
9676  "result;");
9677  CHECK_EQ(v8_str("ggggg"), result);
9678 }
9679 
9680 
9681 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9682  int interceptor_call_count = 0;
9683  v8::HandleScope scope;
9685  v8::Handle<v8::FunctionTemplate> method_templ =
9686  v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9687  v8_str("method_data"),
9689  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9690  proto_templ->Set(v8_str("method"), method_templ);
9691  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9692  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9693  NULL, NULL, NULL, NULL,
9694  v8::External::Wrap(&interceptor_call_count));
9695  LocalContext context;
9696  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9697  GenerateSomeGarbage();
9698  context->Global()->Set(v8_str("o"), fun->NewInstance());
9699  CompileRun(
9700  "var result = 0;"
9701  "for (var i = 0; i < 100; i++) {"
9702  " result = o.method(41);"
9703  "}");
9704  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9705  CHECK_EQ(100, interceptor_call_count);
9706 }
9707 
9708 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9709  int interceptor_call_count = 0;
9710  v8::HandleScope scope;
9712  v8::Handle<v8::FunctionTemplate> method_templ =
9713  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9714  v8_str("method_data"),
9715  v8::Signature::New(fun_templ));
9716  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9717  proto_templ->Set(v8_str("method"), method_templ);
9718  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9719  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9720  NULL, NULL, NULL, NULL,
9721  v8::External::Wrap(&interceptor_call_count));
9722  LocalContext context;
9723  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9724  GenerateSomeGarbage();
9725  context->Global()->Set(v8_str("o"), fun->NewInstance());
9726  CompileRun(
9727  "o.foo = 17;"
9728  "var receiver = {};"
9729  "receiver.__proto__ = o;"
9730  "var result = 0;"
9731  "for (var i = 0; i < 100; i++) {"
9732  " result = receiver.method(41);"
9733  "}");
9734  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9735  CHECK_EQ(100, interceptor_call_count);
9736 }
9737 
9738 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9739  int interceptor_call_count = 0;
9740  v8::HandleScope scope;
9742  v8::Handle<v8::FunctionTemplate> method_templ =
9743  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9744  v8_str("method_data"),
9745  v8::Signature::New(fun_templ));
9746  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9747  proto_templ->Set(v8_str("method"), method_templ);
9748  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9749  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9750  NULL, NULL, NULL, NULL,
9751  v8::External::Wrap(&interceptor_call_count));
9752  LocalContext context;
9753  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9754  GenerateSomeGarbage();
9755  context->Global()->Set(v8_str("o"), fun->NewInstance());
9756  CompileRun(
9757  "o.foo = 17;"
9758  "var receiver = {};"
9759  "receiver.__proto__ = o;"
9760  "var result = 0;"
9761  "var saved_result = 0;"
9762  "for (var i = 0; i < 100; i++) {"
9763  " result = receiver.method(41);"
9764  " if (i == 50) {"
9765  " saved_result = result;"
9766  " receiver = {method: function(x) { return x - 1 }};"
9767  " }"
9768  "}");
9769  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9770  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9771  CHECK_GE(interceptor_call_count, 50);
9772 }
9773 
9774 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9775  int interceptor_call_count = 0;
9776  v8::HandleScope scope;
9778  v8::Handle<v8::FunctionTemplate> method_templ =
9779  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9780  v8_str("method_data"),
9781  v8::Signature::New(fun_templ));
9782  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9783  proto_templ->Set(v8_str("method"), method_templ);
9784  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9785  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9786  NULL, NULL, NULL, NULL,
9787  v8::External::Wrap(&interceptor_call_count));
9788  LocalContext context;
9789  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9790  GenerateSomeGarbage();
9791  context->Global()->Set(v8_str("o"), fun->NewInstance());
9792  CompileRun(
9793  "o.foo = 17;"
9794  "var receiver = {};"
9795  "receiver.__proto__ = o;"
9796  "var result = 0;"
9797  "var saved_result = 0;"
9798  "for (var i = 0; i < 100; i++) {"
9799  " result = receiver.method(41);"
9800  " if (i == 50) {"
9801  " saved_result = result;"
9802  " o.method = function(x) { return x - 1 };"
9803  " }"
9804  "}");
9805  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9806  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9807  CHECK_GE(interceptor_call_count, 50);
9808 }
9809 
9810 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9811  int interceptor_call_count = 0;
9812  v8::HandleScope scope;
9814  v8::Handle<v8::FunctionTemplate> method_templ =
9815  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9816  v8_str("method_data"),
9817  v8::Signature::New(fun_templ));
9818  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9819  proto_templ->Set(v8_str("method"), method_templ);
9820  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9821  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9822  NULL, NULL, NULL, NULL,
9823  v8::External::Wrap(&interceptor_call_count));
9824  LocalContext context;
9825  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9826  GenerateSomeGarbage();
9827  context->Global()->Set(v8_str("o"), fun->NewInstance());
9828  v8::TryCatch try_catch;
9829  CompileRun(
9830  "o.foo = 17;"
9831  "var receiver = {};"
9832  "receiver.__proto__ = o;"
9833  "var result = 0;"
9834  "var saved_result = 0;"
9835  "for (var i = 0; i < 100; i++) {"
9836  " result = receiver.method(41);"
9837  " if (i == 50) {"
9838  " saved_result = result;"
9839  " receiver = 333;"
9840  " }"
9841  "}");
9842  CHECK(try_catch.HasCaught());
9843  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9844  try_catch.Exception()->ToString());
9845  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9846  CHECK_GE(interceptor_call_count, 50);
9847 }
9848 
9849 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9850  int interceptor_call_count = 0;
9851  v8::HandleScope scope;
9853  v8::Handle<v8::FunctionTemplate> method_templ =
9854  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9855  v8_str("method_data"),
9856  v8::Signature::New(fun_templ));
9857  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9858  proto_templ->Set(v8_str("method"), method_templ);
9859  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9860  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9861  NULL, NULL, NULL, NULL,
9862  v8::External::Wrap(&interceptor_call_count));
9863  LocalContext context;
9864  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9865  GenerateSomeGarbage();
9866  context->Global()->Set(v8_str("o"), fun->NewInstance());
9867  v8::TryCatch try_catch;
9868  CompileRun(
9869  "o.foo = 17;"
9870  "var receiver = {};"
9871  "receiver.__proto__ = o;"
9872  "var result = 0;"
9873  "var saved_result = 0;"
9874  "for (var i = 0; i < 100; i++) {"
9875  " result = receiver.method(41);"
9876  " if (i == 50) {"
9877  " saved_result = result;"
9878  " receiver = {method: receiver.method};"
9879  " }"
9880  "}");
9881  CHECK(try_catch.HasCaught());
9882  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9883  try_catch.Exception()->ToString());
9884  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9885  CHECK_GE(interceptor_call_count, 50);
9886 }
9887 
9888 THREADED_TEST(CallICFastApi_TrivialSignature) {
9889  v8::HandleScope scope;
9891  v8::Handle<v8::FunctionTemplate> method_templ =
9892  v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9893  v8_str("method_data"),
9895  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9896  proto_templ->Set(v8_str("method"), method_templ);
9898  USE(templ);
9899  LocalContext context;
9900  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9901  GenerateSomeGarbage();
9902  context->Global()->Set(v8_str("o"), fun->NewInstance());
9903  CompileRun(
9904  "var result = 0;"
9905  "for (var i = 0; i < 100; i++) {"
9906  " result = o.method(41);"
9907  "}");
9908 
9909  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9910 }
9911 
9912 THREADED_TEST(CallICFastApi_SimpleSignature) {
9913  v8::HandleScope scope;
9915  v8::Handle<v8::FunctionTemplate> method_templ =
9916  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9917  v8_str("method_data"),
9918  v8::Signature::New(fun_templ));
9919  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9920  proto_templ->Set(v8_str("method"), method_templ);
9922  CHECK(!templ.IsEmpty());
9923  LocalContext context;
9924  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9925  GenerateSomeGarbage();
9926  context->Global()->Set(v8_str("o"), fun->NewInstance());
9927  CompileRun(
9928  "o.foo = 17;"
9929  "var receiver = {};"
9930  "receiver.__proto__ = o;"
9931  "var result = 0;"
9932  "for (var i = 0; i < 100; i++) {"
9933  " result = receiver.method(41);"
9934  "}");
9935 
9936  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9937 }
9938 
9939 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9940  v8::HandleScope scope;
9942  v8::Handle<v8::FunctionTemplate> method_templ =
9943  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9944  v8_str("method_data"),
9945  v8::Signature::New(fun_templ));
9946  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9947  proto_templ->Set(v8_str("method"), method_templ);
9949  CHECK(!templ.IsEmpty());
9950  LocalContext context;
9951  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9952  GenerateSomeGarbage();
9953  context->Global()->Set(v8_str("o"), fun->NewInstance());
9954  CompileRun(
9955  "o.foo = 17;"
9956  "var receiver = {};"
9957  "receiver.__proto__ = o;"
9958  "var result = 0;"
9959  "var saved_result = 0;"
9960  "for (var i = 0; i < 100; i++) {"
9961  " result = receiver.method(41);"
9962  " if (i == 50) {"
9963  " saved_result = result;"
9964  " receiver = {method: function(x) { return x - 1 }};"
9965  " }"
9966  "}");
9967  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9968  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9969 }
9970 
9971 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9972  v8::HandleScope scope;
9974  v8::Handle<v8::FunctionTemplate> method_templ =
9975  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9976  v8_str("method_data"),
9977  v8::Signature::New(fun_templ));
9978  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9979  proto_templ->Set(v8_str("method"), method_templ);
9981  CHECK(!templ.IsEmpty());
9982  LocalContext context;
9983  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9984  GenerateSomeGarbage();
9985  context->Global()->Set(v8_str("o"), fun->NewInstance());
9986  v8::TryCatch try_catch;
9987  CompileRun(
9988  "o.foo = 17;"
9989  "var receiver = {};"
9990  "receiver.__proto__ = o;"
9991  "var result = 0;"
9992  "var saved_result = 0;"
9993  "for (var i = 0; i < 100; i++) {"
9994  " result = receiver.method(41);"
9995  " if (i == 50) {"
9996  " saved_result = result;"
9997  " receiver = 333;"
9998  " }"
9999  "}");
10000  CHECK(try_catch.HasCaught());
10001  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10002  try_catch.Exception()->ToString());
10003  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10004 }
10005 
10006 
10008 
10009 static v8::Handle<Value> InterceptorKeyedCallICGetter(
10010  Local<String> name, const AccessorInfo& info) {
10012  if (v8_str("x")->Equals(name)) {
10013  return keyed_call_ic_function;
10014  }
10015  return v8::Handle<Value>();
10016 }
10017 
10018 
10019 // Test the case when we stored cacheable lookup into
10020 // a stub, but the function name changed (to another cacheable function).
10021 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10022  v8::HandleScope scope;
10023  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10024  templ->SetNamedPropertyHandler(NoBlockGetterX);
10025  LocalContext context;
10026  context->Global()->Set(v8_str("o"), templ->NewInstance());
10027  CompileRun(
10028  "proto = new Object();"
10029  "proto.y = function(x) { return x + 1; };"
10030  "proto.z = function(x) { return x - 1; };"
10031  "o.__proto__ = proto;"
10032  "var result = 0;"
10033  "var method = 'y';"
10034  "for (var i = 0; i < 10; i++) {"
10035  " if (i == 5) { method = 'z'; };"
10036  " result += o[method](41);"
10037  "}");
10038  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10039 }
10040 
10041 
10042 // Test the case when we stored cacheable lookup into
10043 // a stub, but the function name changed (and the new function is present
10044 // both before and after the interceptor in the prototype chain).
10045 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10046  v8::HandleScope scope;
10047  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10048  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10049  LocalContext context;
10050  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10051  keyed_call_ic_function =
10052  v8_compile("function f(x) { return x - 1; }; f")->Run();
10053  CompileRun(
10054  "o = new Object();"
10055  "proto2 = new Object();"
10056  "o.y = function(x) { return x + 1; };"
10057  "proto2.y = function(x) { return x + 2; };"
10058  "o.__proto__ = proto1;"
10059  "proto1.__proto__ = proto2;"
10060  "var result = 0;"
10061  "var method = 'x';"
10062  "for (var i = 0; i < 10; i++) {"
10063  " if (i == 5) { method = 'y'; };"
10064  " result += o[method](41);"
10065  "}");
10066  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10067 }
10068 
10069 
10070 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10071 // on the global object.
10072 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10073  v8::HandleScope scope;
10074  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10075  templ->SetNamedPropertyHandler(NoBlockGetterX);
10076  LocalContext context;
10077  context->Global()->Set(v8_str("o"), templ->NewInstance());
10078  CompileRun(
10079  "function inc(x) { return x + 1; };"
10080  "inc(1);"
10081  "function dec(x) { return x - 1; };"
10082  "dec(1);"
10083  "o.__proto__ = this;"
10084  "this.__proto__.x = inc;"
10085  "this.__proto__.y = dec;"
10086  "var result = 0;"
10087  "var method = 'x';"
10088  "for (var i = 0; i < 10; i++) {"
10089  " if (i == 5) { method = 'y'; };"
10090  " result += o[method](41);"
10091  "}");
10092  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10093 }
10094 
10095 
10096 // Test the case when actual function to call sits on global object.
10097 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10098  v8::HandleScope scope;
10099  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10100  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10101  LocalContext context;
10102  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10103 
10104  CompileRun(
10105  "function len(x) { return x.length; };"
10106  "o.__proto__ = this;"
10107  "var m = 'parseFloat';"
10108  "var result = 0;"
10109  "for (var i = 0; i < 10; i++) {"
10110  " if (i == 5) {"
10111  " m = 'len';"
10112  " saved_result = result;"
10113  " };"
10114  " result = o[m]('239');"
10115  "}");
10116  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10117  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10118 }
10119 
10120 // Test the map transition before the interceptor.
10121 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10122  v8::HandleScope scope;
10123  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10124  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10125  LocalContext context;
10126  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10127 
10128  CompileRun(
10129  "var o = new Object();"
10130  "o.__proto__ = proto;"
10131  "o.method = function(x) { return x + 1; };"
10132  "var m = 'method';"
10133  "var result = 0;"
10134  "for (var i = 0; i < 10; i++) {"
10135  " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10136  " result += o[m](41);"
10137  "}");
10138  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10139 }
10140 
10141 
10142 // Test the map transition after the interceptor.
10143 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10144  v8::HandleScope scope;
10145  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10146  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10147  LocalContext context;
10148  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10149 
10150  CompileRun(
10151  "var proto = new Object();"
10152  "o.__proto__ = proto;"
10153  "proto.method = function(x) { return x + 1; };"
10154  "var m = 'method';"
10155  "var result = 0;"
10156  "for (var i = 0; i < 10; i++) {"
10157  " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10158  " result += o[m](41);"
10159  "}");
10160  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10161 }
10162 
10163 
10164 static int interceptor_call_count = 0;
10165 
10166 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10167  const AccessorInfo& info) {
10169  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10170  return call_ic_function2;
10171  }
10172  return v8::Handle<Value>();
10173 }
10174 
10175 
10176 // This test should hit load and call ICs for the interceptor case.
10177 // Once in a while, the interceptor will reply that a property was not
10178 // found in which case we should get a reference error.
10179 THREADED_TEST(InterceptorICReferenceErrors) {
10180  v8::HandleScope scope;
10181  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10182  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10183  LocalContext context(0, templ, v8::Handle<Value>());
10184  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10185  v8::Handle<Value> value = CompileRun(
10186  "function f() {"
10187  " for (var i = 0; i < 1000; i++) {"
10188  " try { x; } catch(e) { return true; }"
10189  " }"
10190  " return false;"
10191  "};"
10192  "f();");
10193  CHECK_EQ(true, value->BooleanValue());
10194  interceptor_call_count = 0;
10195  value = CompileRun(
10196  "function g() {"
10197  " for (var i = 0; i < 1000; i++) {"
10198  " try { x(42); } catch(e) { return true; }"
10199  " }"
10200  " return false;"
10201  "};"
10202  "g();");
10203  CHECK_EQ(true, value->BooleanValue());
10204 }
10205 
10206 
10207 static int interceptor_ic_exception_get_count = 0;
10208 
10209 static v8::Handle<Value> InterceptorICExceptionGetter(
10210  Local<String> name,
10211  const AccessorInfo& info) {
10213  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10214  return call_ic_function3;
10215  }
10216  if (interceptor_ic_exception_get_count == 20) {
10217  return v8::ThrowException(v8_num(42));
10218  }
10219  // Do not handle get for properties other than x.
10220  return v8::Handle<Value>();
10221 }
10222 
10223 // Test interceptor load/call IC where the interceptor throws an
10224 // exception once in a while.
10225 THREADED_TEST(InterceptorICGetterExceptions) {
10226  interceptor_ic_exception_get_count = 0;
10227  v8::HandleScope scope;
10228  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10229  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10230  LocalContext context(0, templ, v8::Handle<Value>());
10231  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10232  v8::Handle<Value> value = CompileRun(
10233  "function f() {"
10234  " for (var i = 0; i < 100; i++) {"
10235  " try { x; } catch(e) { return true; }"
10236  " }"
10237  " return false;"
10238  "};"
10239  "f();");
10240  CHECK_EQ(true, value->BooleanValue());
10241  interceptor_ic_exception_get_count = 0;
10242  value = CompileRun(
10243  "function f() {"
10244  " for (var i = 0; i < 100; i++) {"
10245  " try { x(42); } catch(e) { return true; }"
10246  " }"
10247  " return false;"
10248  "};"
10249  "f();");
10250  CHECK_EQ(true, value->BooleanValue());
10251 }
10252 
10253 
10254 static int interceptor_ic_exception_set_count = 0;
10255 
10256 static v8::Handle<Value> InterceptorICExceptionSetter(
10257  Local<String> key, Local<Value> value, const AccessorInfo&) {
10259  if (++interceptor_ic_exception_set_count > 20) {
10260  return v8::ThrowException(v8_num(42));
10261  }
10262  // Do not actually handle setting.
10263  return v8::Handle<Value>();
10264 }
10265 
10266 // Test interceptor store IC where the interceptor throws an exception
10267 // once in a while.
10268 THREADED_TEST(InterceptorICSetterExceptions) {
10269  interceptor_ic_exception_set_count = 0;
10270  v8::HandleScope scope;
10271  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10272  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10273  LocalContext context(0, templ, v8::Handle<Value>());
10274  v8::Handle<Value> value = CompileRun(
10275  "function f() {"
10276  " for (var i = 0; i < 100; i++) {"
10277  " try { x = 42; } catch(e) { return true; }"
10278  " }"
10279  " return false;"
10280  "};"
10281  "f();");
10282  CHECK_EQ(true, value->BooleanValue());
10283 }
10284 
10285 
10286 // Test that we ignore null interceptors.
10287 THREADED_TEST(NullNamedInterceptor) {
10288  v8::HandleScope scope;
10289  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10290  templ->SetNamedPropertyHandler(0);
10291  LocalContext context;
10292  templ->Set("x", v8_num(42));
10293  v8::Handle<v8::Object> obj = templ->NewInstance();
10294  context->Global()->Set(v8_str("obj"), obj);
10295  v8::Handle<Value> value = CompileRun("obj.x");
10296  CHECK(value->IsInt32());
10297  CHECK_EQ(42, value->Int32Value());
10298 }
10299 
10300 
10301 // Test that we ignore null interceptors.
10302 THREADED_TEST(NullIndexedInterceptor) {
10303  v8::HandleScope scope;
10304  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10305  templ->SetIndexedPropertyHandler(0);
10306  LocalContext context;
10307  templ->Set("42", v8_num(42));
10308  v8::Handle<v8::Object> obj = templ->NewInstance();
10309  context->Global()->Set(v8_str("obj"), obj);
10310  v8::Handle<Value> value = CompileRun("obj[42]");
10311  CHECK(value->IsInt32());
10312  CHECK_EQ(42, value->Int32Value());
10313 }
10314 
10315 
10316 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10317  v8::HandleScope scope;
10319  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10320  LocalContext env;
10321  env->Global()->Set(v8_str("obj"),
10322  templ->GetFunction()->NewInstance());
10323  ExpectTrue("obj.x === 42");
10324  ExpectTrue("!obj.propertyIsEnumerable('x')");
10325 }
10326 
10327 
10328 static Handle<Value> ThrowingGetter(Local<String> name,
10329  const AccessorInfo& info) {
10331  ThrowException(Handle<Value>());
10332  return Undefined();
10333 }
10334 
10335 
10336 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10337  HandleScope scope;
10338  LocalContext context;
10339 
10340  Local<FunctionTemplate> templ = FunctionTemplate::New();
10341  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10342  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10343 
10344  Local<Object> instance = templ->GetFunction()->NewInstance();
10345 
10346  Local<Object> another = Object::New();
10347  another->SetPrototype(instance);
10348 
10349  Local<Object> with_js_getter = CompileRun(
10350  "o = {};\n"
10351  "o.__defineGetter__('f', function() { throw undefined; });\n"
10352  "o\n").As<Object>();
10353  CHECK(!with_js_getter.IsEmpty());
10354 
10355  TryCatch try_catch;
10356 
10357  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10358  CHECK(try_catch.HasCaught());
10359  try_catch.Reset();
10360  CHECK(result.IsEmpty());
10361 
10362  result = another->GetRealNamedProperty(v8_str("f"));
10363  CHECK(try_catch.HasCaught());
10364  try_catch.Reset();
10365  CHECK(result.IsEmpty());
10366 
10367  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10368  CHECK(try_catch.HasCaught());
10369  try_catch.Reset();
10370  CHECK(result.IsEmpty());
10371 
10372  result = another->Get(v8_str("f"));
10373  CHECK(try_catch.HasCaught());
10374  try_catch.Reset();
10375  CHECK(result.IsEmpty());
10376 
10377  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10378  CHECK(try_catch.HasCaught());
10379  try_catch.Reset();
10380  CHECK(result.IsEmpty());
10381 
10382  result = with_js_getter->Get(v8_str("f"));
10383  CHECK(try_catch.HasCaught());
10384  try_catch.Reset();
10385  CHECK(result.IsEmpty());
10386 }
10387 
10388 
10389 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10390  TryCatch try_catch;
10391  // Verboseness is important: it triggers message delivery which can call into
10392  // external code.
10393  try_catch.SetVerbose(true);
10394  CompileRun("throw 'from JS';");
10395  CHECK(try_catch.HasCaught());
10396  CHECK(!i::Isolate::Current()->has_pending_exception());
10397  CHECK(!i::Isolate::Current()->has_scheduled_exception());
10398  return Undefined();
10399 }
10400 
10401 
10402 static int call_depth;
10403 
10404 
10405 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10406  TryCatch try_catch;
10407 }
10408 
10409 
10410 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10411  if (--call_depth) CompileRun("throw 'ThrowInJS';");
10412 }
10413 
10414 
10415 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10416  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
10417 }
10418 
10419 
10420 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10421  Handle<String> errorMessageString = message->Get();
10422  CHECK(!errorMessageString.IsEmpty());
10423  message->GetStackTrace();
10424  message->GetScriptResourceName();
10425 }
10426 
10427 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10428  HandleScope scope;
10429  LocalContext context;
10430 
10431  Local<Function> func =
10432  FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10433  context->Global()->Set(v8_str("func"), func);
10434 
10435  MessageCallback callbacks[] =
10436  { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10437  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10438  MessageCallback callback = callbacks[i];
10439  if (callback != NULL) {
10440  V8::AddMessageListener(callback);
10441  }
10442  // Some small number to control number of times message handler should
10443  // throw an exception.
10444  call_depth = 5;
10445  ExpectFalse(
10446  "var thrown = false;\n"
10447  "try { func(); } catch(e) { thrown = true; }\n"
10448  "thrown\n");
10449  if (callback != NULL) {
10450  V8::RemoveMessageListeners(callback);
10451  }
10452  }
10453 }
10454 
10455 
10456 static v8::Handle<Value> ParentGetter(Local<String> name,
10457  const AccessorInfo& info) {
10459  return v8_num(1);
10460 }
10461 
10462 
10463 static v8::Handle<Value> ChildGetter(Local<String> name,
10464  const AccessorInfo& info) {
10466  return v8_num(42);
10467 }
10468 
10469 
10470 THREADED_TEST(Overriding) {
10471  i::FLAG_es5_readonly = true;
10472  v8::HandleScope scope;
10473  LocalContext context;
10474 
10475  // Parent template.
10476  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10477  Local<ObjectTemplate> parent_instance_templ =
10478  parent_templ->InstanceTemplate();
10479  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10480 
10481  // Template that inherits from the parent template.
10482  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10483  Local<ObjectTemplate> child_instance_templ =
10484  child_templ->InstanceTemplate();
10485  child_templ->Inherit(parent_templ);
10486  // Override 'f'. The child version of 'f' should get called for child
10487  // instances.
10488  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10489  // Add 'g' twice. The 'g' added last should get called for instances.
10490  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10491  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10492 
10493  // Add 'h' as an accessor to the proto template with ReadOnly attributes
10494  // so 'h' can be shadowed on the instance object.
10495  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10496  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10498 
10499  // Add 'i' as an accessor to the instance template with ReadOnly attributes
10500  // but the attribute does not have effect because it is duplicated with
10501  // NULL setter.
10502  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10504 
10505 
10506 
10507  // Instantiate the child template.
10508  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10509 
10510  // Check that the child function overrides the parent one.
10511  context->Global()->Set(v8_str("o"), instance);
10512  Local<Value> value = v8_compile("o.f")->Run();
10513  // Check that the 'g' that was added last is hit.
10514  CHECK_EQ(42, value->Int32Value());
10515  value = v8_compile("o.g")->Run();
10516  CHECK_EQ(42, value->Int32Value());
10517 
10518  // Check that 'h' cannot be shadowed.
10519  value = v8_compile("o.h = 3; o.h")->Run();
10520  CHECK_EQ(1, value->Int32Value());
10521 
10522  // Check that 'i' cannot be shadowed or changed.
10523  value = v8_compile("o.i = 3; o.i")->Run();
10524  CHECK_EQ(42, value->Int32Value());
10525 }
10526 
10527 
10528 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10530  return v8::Boolean::New(args.IsConstructCall());
10531 }
10532 
10533 
10534 THREADED_TEST(IsConstructCall) {
10535  v8::HandleScope scope;
10536 
10537  // Function template with call handler.
10538  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10539  templ->SetCallHandler(IsConstructHandler);
10540 
10541  LocalContext context;
10542 
10543  context->Global()->Set(v8_str("f"), templ->GetFunction());
10544  Local<Value> value = v8_compile("f()")->Run();
10545  CHECK(!value->BooleanValue());
10546  value = v8_compile("new f()")->Run();
10547  CHECK(value->BooleanValue());
10548 }
10549 
10550 
10551 THREADED_TEST(ObjectProtoToString) {
10552  v8::HandleScope scope;
10553  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10554  templ->SetClassName(v8_str("MyClass"));
10555 
10556  LocalContext context;
10557 
10558  Local<String> customized_tostring = v8_str("customized toString");
10559 
10560  // Replace Object.prototype.toString
10561  v8_compile("Object.prototype.toString = function() {"
10562  " return 'customized toString';"
10563  "}")->Run();
10564 
10565  // Normal ToString call should call replaced Object.prototype.toString
10566  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10567  Local<String> value = instance->ToString();
10568  CHECK(value->IsString() && value->Equals(customized_tostring));
10569 
10570  // ObjectProtoToString should not call replace toString function.
10571  value = instance->ObjectProtoToString();
10572  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10573 
10574  // Check global
10575  value = context->Global()->ObjectProtoToString();
10576  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10577 
10578  // Check ordinary object
10579  Local<Value> object = v8_compile("new Object()")->Run();
10580  value = object.As<v8::Object>()->ObjectProtoToString();
10581  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10582 }
10583 
10584 
10585 THREADED_TEST(ObjectGetConstructorName) {
10586  v8::HandleScope scope;
10587  LocalContext context;
10588  v8_compile("function Parent() {};"
10589  "function Child() {};"
10590  "Child.prototype = new Parent();"
10591  "var outer = { inner: function() { } };"
10592  "var p = new Parent();"
10593  "var c = new Child();"
10594  "var x = new outer.inner();")->Run();
10595 
10596  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10597  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10598  v8_str("Parent")));
10599 
10600  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10601  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10602  v8_str("Child")));
10603 
10604  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10605  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10606  v8_str("outer.inner")));
10607 }
10608 
10609 
10610 bool ApiTestFuzzer::fuzzing_ = false;
10611 i::Semaphore* ApiTestFuzzer::all_tests_done_=
10613 int ApiTestFuzzer::active_tests_;
10614 int ApiTestFuzzer::tests_being_run_;
10615 int ApiTestFuzzer::current_;
10616 
10617 
10618 // We are in a callback and want to switch to another thread (if we
10619 // are currently running the thread fuzzing test).
10621  if (!fuzzing_) return;
10622  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10623  test->ContextSwitch();
10624 }
10625 
10626 
10627 // Let the next thread go. Since it is also waiting on the V8 lock it may
10628 // not start immediately.
10629 bool ApiTestFuzzer::NextThread() {
10630  int test_position = GetNextTestNumber();
10631  const char* test_name = RegisterThreadedTest::nth(current_)->name();
10632  if (test_position == current_) {
10633  if (kLogThreading)
10634  printf("Stay with %s\n", test_name);
10635  return false;
10636  }
10637  if (kLogThreading) {
10638  printf("Switch from %s to %s\n",
10639  test_name,
10640  RegisterThreadedTest::nth(test_position)->name());
10641  }
10642  current_ = test_position;
10643  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10644  return true;
10645 }
10646 
10647 
10649  // When it is our turn...
10650  gate_->Wait();
10651  {
10652  // ... get the V8 lock and start running the test.
10653  v8::Locker locker;
10654  CallTest();
10655  }
10656  // This test finished.
10657  active_ = false;
10658  active_tests_--;
10659  // If it was the last then signal that fact.
10660  if (active_tests_ == 0) {
10661  all_tests_done_->Signal();
10662  } else {
10663  // Otherwise select a new test and start that.
10664  NextThread();
10665  }
10666 }
10667 
10668 
10669 static unsigned linear_congruential_generator;
10670 
10671 
10673  linear_congruential_generator = i::FLAG_testing_prng_seed;
10674  fuzzing_ = true;
10675  int count = RegisterThreadedTest::count();
10676  int start = count * part / (LAST_PART + 1);
10677  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10678  active_tests_ = tests_being_run_ = end - start + 1;
10679  for (int i = 0; i < tests_being_run_; i++) {
10680  RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10681  }
10682  for (int i = 0; i < active_tests_; i++) {
10684  }
10685 }
10686 
10687 
10688 static void CallTestNumber(int test_number) {
10689  (RegisterThreadedTest::nth(test_number)->callback())();
10690 }
10691 
10692 
10694  // Set off the first test.
10695  current_ = -1;
10696  NextThread();
10697  // Wait till they are all done.
10698  all_tests_done_->Wait();
10699 }
10700 
10701 
10702 int ApiTestFuzzer::GetNextTestNumber() {
10703  int next_test;
10704  do {
10705  next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10706  linear_congruential_generator *= 1664525u;
10707  linear_congruential_generator += 1013904223u;
10708  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10709  return next_test;
10710 }
10711 
10712 
10713 void ApiTestFuzzer::ContextSwitch() {
10714  // If the new thread is the same as the current thread there is nothing to do.
10715  if (NextThread()) {
10716  // Now it can start.
10717  v8::Unlocker unlocker;
10718  // Wait till someone starts us again.
10719  gate_->Wait();
10720  // And we're off.
10721  }
10722 }
10723 
10724 
10726  fuzzing_ = false;
10727  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10729  if (fuzzer != NULL) fuzzer->Join();
10730  }
10731 }
10732 
10733 
10734 // Lets not be needlessly self-referential.
10735 TEST(Threading) {
10739 }
10740 
10741 TEST(Threading2) {
10745 }
10746 
10747 TEST(Threading3) {
10751 }
10752 
10753 TEST(Threading4) {
10757 }
10758 
10760  if (kLogThreading)
10761  printf("Start test %d\n", test_number_);
10762  CallTestNumber(test_number_);
10763  if (kLogThreading)
10764  printf("End test %d\n", test_number_);
10765 }
10766 
10767 
10768 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10771  v8::Unlocker unlocker;
10772  const char* code = "throw 7;";
10773  {
10774  v8::Locker nested_locker;
10775  v8::HandleScope scope;
10776  v8::Handle<Value> exception;
10777  { v8::TryCatch try_catch;
10778  v8::Handle<Value> value = CompileRun(code);
10779  CHECK(value.IsEmpty());
10780  CHECK(try_catch.HasCaught());
10781  // Make sure to wrap the exception in a new handle because
10782  // the handle returned from the TryCatch is destroyed
10783  // when the TryCatch is destroyed.
10784  exception = Local<Value>::New(try_catch.Exception());
10785  }
10786  return v8::ThrowException(exception);
10787  }
10788 }
10789 
10790 
10791 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10794  v8::Unlocker unlocker;
10795  const char* code = "throw 7;";
10796  {
10797  v8::Locker nested_locker;
10798  v8::HandleScope scope;
10799  v8::Handle<Value> value = CompileRun(code);
10800  CHECK(value.IsEmpty());
10801  return v8_str("foo");
10802  }
10803 }
10804 
10805 
10806 // These are locking tests that don't need to be run again
10807 // as part of the locking aggregation tests.
10808 TEST(NestedLockers) {
10809  v8::Locker locker;
10811  v8::HandleScope scope;
10812  LocalContext env;
10813  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10814  Local<Function> fun = fun_templ->GetFunction();
10815  env->Global()->Set(v8_str("throw_in_js"), fun);
10816  Local<Script> script = v8_compile("(function () {"
10817  " try {"
10818  " throw_in_js();"
10819  " return 42;"
10820  " } catch (e) {"
10821  " return e * 13;"
10822  " }"
10823  "})();");
10824  CHECK_EQ(91, script->Run()->Int32Value());
10825 }
10826 
10827 
10828 // These are locking tests that don't need to be run again
10829 // as part of the locking aggregation tests.
10830 TEST(NestedLockersNoTryCatch) {
10831  v8::Locker locker;
10832  v8::HandleScope scope;
10833  LocalContext env;
10834  Local<v8::FunctionTemplate> fun_templ =
10835  v8::FunctionTemplate::New(ThrowInJSNoCatch);
10836  Local<Function> fun = fun_templ->GetFunction();
10837  env->Global()->Set(v8_str("throw_in_js"), fun);
10838  Local<Script> script = v8_compile("(function () {"
10839  " try {"
10840  " throw_in_js();"
10841  " return 42;"
10842  " } catch (e) {"
10843  " return e * 13;"
10844  " }"
10845  "})();");
10846  CHECK_EQ(91, script->Run()->Int32Value());
10847 }
10848 
10849 
10850 THREADED_TEST(RecursiveLocking) {
10851  v8::Locker locker;
10852  {
10853  v8::Locker locker2;
10855  }
10856 }
10857 
10858 
10859 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10861  v8::Unlocker unlocker;
10862  return v8::Undefined();
10863 }
10864 
10865 
10866 THREADED_TEST(LockUnlockLock) {
10867  {
10868  v8::Locker locker;
10869  v8::HandleScope scope;
10870  LocalContext env;
10871  Local<v8::FunctionTemplate> fun_templ =
10872  v8::FunctionTemplate::New(UnlockForAMoment);
10873  Local<Function> fun = fun_templ->GetFunction();
10874  env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10875  Local<Script> script = v8_compile("(function () {"
10876  " unlock_for_a_moment();"
10877  " return 42;"
10878  "})();");
10879  CHECK_EQ(42, script->Run()->Int32Value());
10880  }
10881  {
10882  v8::Locker locker;
10883  v8::HandleScope scope;
10884  LocalContext env;
10885  Local<v8::FunctionTemplate> fun_templ =
10886  v8::FunctionTemplate::New(UnlockForAMoment);
10887  Local<Function> fun = fun_templ->GetFunction();
10888  env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10889  Local<Script> script = v8_compile("(function () {"
10890  " unlock_for_a_moment();"
10891  " return 42;"
10892  "})();");
10893  CHECK_EQ(42, script->Run()->Int32Value());
10894  }
10895 }
10896 
10897 
10898 static int GetGlobalObjectsCount() {
10899  i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10900  int count = 0;
10901  i::HeapIterator it;
10902  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10903  if (object->IsJSGlobalObject()) count++;
10904  return count;
10905 }
10906 
10907 
10908 static void CheckSurvivingGlobalObjectsCount(int expected) {
10909  // We need to collect all garbage twice to be sure that everything
10910  // has been collected. This is because inline caches are cleared in
10911  // the first garbage collection but some of the maps have already
10912  // been marked at that point. Therefore some of the maps are not
10913  // collected until the second garbage collection.
10914  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10915  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10916  int count = GetGlobalObjectsCount();
10917 #ifdef DEBUG
10918  if (count != expected) HEAP->TracePathToGlobal();
10919 #endif
10920  CHECK_EQ(expected, count);
10921 }
10922 
10923 
10924 TEST(DontLeakGlobalObjects) {
10925  // Regression test for issues 1139850 and 1174891.
10926 
10928 
10929  for (int i = 0; i < 5; i++) {
10930  { v8::HandleScope scope;
10931  LocalContext context;
10932  }
10934  CheckSurvivingGlobalObjectsCount(0);
10935 
10936  { v8::HandleScope scope;
10937  LocalContext context;
10938  v8_compile("Date")->Run();
10939  }
10941  CheckSurvivingGlobalObjectsCount(0);
10942 
10943  { v8::HandleScope scope;
10944  LocalContext context;
10945  v8_compile("/aaa/")->Run();
10946  }
10948  CheckSurvivingGlobalObjectsCount(0);
10949 
10950  { v8::HandleScope scope;
10951  const char* extension_list[] = { "v8/gc" };
10952  v8::ExtensionConfiguration extensions(1, extension_list);
10953  LocalContext context(&extensions);
10954  v8_compile("gc();")->Run();
10955  }
10957  CheckSurvivingGlobalObjectsCount(0);
10958  }
10959 }
10960 
10961 
10964 
10966  v8::HandleScope scope;
10967  bad_handle = v8::Persistent<v8::Object>::New(some_object);
10968  handle.Dispose();
10969 }
10970 
10971 
10972 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10973  LocalContext context;
10974 
10975  v8::Persistent<v8::Object> handle1, handle2;
10976  {
10977  v8::HandleScope scope;
10981  }
10982  // Note: order is implementation dependent alas: currently
10983  // global handle nodes are processed by PostGarbageCollectionProcessing
10984  // in reverse allocation order, so if second allocated handle is deleted,
10985  // weak callback of the first handle would be able to 'reallocate' it.
10987  handle2.Dispose();
10988  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10989 }
10990 
10991 
10993 
10995  to_be_disposed.Dispose();
10996  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10997  handle.Dispose();
10998 }
10999 
11000 
11001 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11002  LocalContext context;
11003 
11004  v8::Persistent<v8::Object> handle1, handle2;
11005  {
11006  v8::HandleScope scope;
11009  }
11011  to_be_disposed = handle2;
11012  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11013 }
11014 
11016  handle.Dispose();
11017 }
11018 
11020  v8::HandleScope scope;
11022  handle.Dispose();
11023 }
11024 
11025 
11026 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11027  LocalContext context;
11028 
11029  v8::Persistent<v8::Object> handle1, handle2, handle3;
11030  {
11031  v8::HandleScope scope;
11035  }
11036  handle2.MakeWeak(NULL, DisposingCallback);
11038  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11039 }
11040 
11041 
11042 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11044 
11045  const int nof = 2;
11046  const char* sources[nof] = {
11047  "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11048  "Object()"
11049  };
11050 
11051  for (int i = 0; i < nof; i++) {
11052  const char* source = sources[i];
11053  { v8::HandleScope scope;
11054  LocalContext context;
11055  CompileRun(source);
11056  }
11057  { v8::HandleScope scope;
11058  LocalContext context;
11059  CompileRun(source);
11060  }
11061  }
11062 }
11063 
11064 
11065 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11066  v8::HandleScope inner;
11067  env->Enter();
11068  v8::Handle<Value> three = v8_num(3);
11069  v8::Handle<Value> value = inner.Close(three);
11070  env->Exit();
11071  return value;
11072 }
11073 
11074 
11075 THREADED_TEST(NestedHandleScopeAndContexts) {
11076  v8::HandleScope outer;
11077  v8::Persistent<Context> env = Context::New();
11078  env->Enter();
11079  v8::Handle<Value> value = NestedScope(env);
11080  v8::Handle<String> str(value->ToString());
11081  CHECK(!str.IsEmpty());
11082  env->Exit();
11083  env.Dispose();
11084 }
11085 
11086 
11087 static i::Handle<i::JSFunction>* foo_ptr = NULL;
11088 static int foo_count = 0;
11089 static i::Handle<i::JSFunction>* bar_ptr = NULL;
11090 static int bar_count = 0;
11091 
11092 
11093 static void entry_hook(uintptr_t function,
11094  uintptr_t return_addr_location) {
11096  reinterpret_cast<i::Address>(function));
11097  CHECK(code != NULL);
11098 
11099  if (bar_ptr != NULL && code == (*bar_ptr)->code())
11100  ++bar_count;
11101 
11102  if (foo_ptr != NULL && code == (*foo_ptr)->code())
11103  ++foo_count;
11104 
11105  // TODO(siggi): Verify return_addr_location.
11106  // This can be done by capturing JitCodeEvents, but requires an ordered
11107  // collection.
11108 }
11109 
11110 
11111 static void RunLoopInNewEnv() {
11112  bar_ptr = NULL;
11113  foo_ptr = NULL;
11114 
11115  v8::HandleScope outer;
11116  v8::Persistent<Context> env = Context::New();
11117  env->Enter();
11118 
11119  const char* script =
11120  "function bar() {"
11121  " var sum = 0;"
11122  " for (i = 0; i < 100; ++i)"
11123  " sum = foo(i);"
11124  " return sum;"
11125  "}"
11126  "function foo(i) { return i * i; }";
11127  CompileRun(script);
11130  v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11131  ASSERT(*bar);
11132 
11135  v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11136  ASSERT(*foo);
11137 
11138  bar_ptr = &bar;
11139  foo_ptr = &foo;
11140 
11141  v8::Handle<v8::Value> value = CompileRun("bar();");
11142  CHECK(value->IsNumber());
11143  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11144 
11145  // Test the optimized codegen path.
11146  value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11147  "bar();");
11148  CHECK(value->IsNumber());
11149  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11150 
11151  env->Exit();
11152 }
11153 
11154 
11155 TEST(SetFunctionEntryHook) {
11156  i::FLAG_allow_natives_syntax = true;
11157 
11158  // Test setting and resetting the entry hook.
11159  // Nulling it should always succeed.
11161 
11162  CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11163  // Setting a hook while one's active should fail.
11164  CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11165 
11167 
11168  // Reset the entry count to zero and set the entry hook.
11169  bar_count = 0;
11170  foo_count = 0;
11171  CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11172  RunLoopInNewEnv();
11173 
11174  CHECK_EQ(2, bar_count);
11175  CHECK_EQ(200, foo_count);
11176 
11177  // Clear the entry hook and count.
11178  bar_count = 0;
11179  foo_count = 0;
11181 
11182  // Clear the compilation cache to make sure we don't reuse the
11183  // functions from the previous invocation.
11184  v8::internal::Isolate::Current()->compilation_cache()->Clear();
11185 
11186  // Verify that entry hooking is now disabled.
11187  RunLoopInNewEnv();
11188  CHECK_EQ(0u, bar_count);
11189  CHECK_EQ(0u, foo_count);
11190 }
11191 
11192 
11193 static i::HashMap* code_map = NULL;
11194 static int saw_bar = 0;
11195 static int move_events = 0;
11196 
11197 
11198 static bool FunctionNameIs(const char* expected,
11199  const v8::JitCodeEvent* event) {
11200  // Log lines for functions are of the general form:
11201  // "LazyCompile:<type><function_name>", where the type is one of
11202  // "*", "~" or "".
11203  static const char kPreamble[] = "LazyCompile:";
11204  static size_t kPreambleLen = sizeof(kPreamble) - 1;
11205 
11206  if (event->name.len < sizeof(kPreamble) - 1 ||
11207  strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11208  return false;
11209  }
11210 
11211  const char* tail = event->name.str + kPreambleLen;
11212  size_t tail_len = event->name.len - kPreambleLen;
11213  size_t expected_len = strlen(expected);
11214  if (tail_len == expected_len + 1) {
11215  if (*tail == '*' || *tail == '~') {
11216  --tail_len;
11217  ++tail;
11218  } else {
11219  return false;
11220  }
11221  }
11222 
11223  if (tail_len != expected_len)
11224  return false;
11225 
11226  return strncmp(tail, expected, expected_len) == 0;
11227 }
11228 
11229 
11230 static void event_handler(const v8::JitCodeEvent* event) {
11231  CHECK(event != NULL);
11232  CHECK(code_map != NULL);
11233 
11234  switch (event->type) {
11236  CHECK(event->code_start != NULL);
11237  CHECK_NE(0, static_cast<int>(event->code_len));
11238  CHECK(event->name.str != NULL);
11239  i::HashMap::Entry* entry =
11240  code_map->Lookup(event->code_start,
11242  true);
11243  entry->value = reinterpret_cast<void*>(event->code_len);
11244 
11245  if (FunctionNameIs("bar", event)) {
11246  ++saw_bar;
11247  }
11248  }
11249  break;
11250 
11252  uint32_t hash = i::ComputePointerHash(event->code_start);
11253  // We would like to never see code move that we haven't seen before,
11254  // but the code creation event does not happen until the line endings
11255  // have been calculated (this is so that we can report the line in the
11256  // script at which the function source is found, see
11257  // Compiler::RecordFunctionCompilation) and the line endings
11258  // calculations can cause a GC, which can move the newly created code
11259  // before its existence can be logged.
11260  i::HashMap::Entry* entry =
11261  code_map->Lookup(event->code_start, hash, false);
11262  if (entry != NULL) {
11263  ++move_events;
11264 
11265  CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11266  code_map->Remove(event->code_start, hash);
11267 
11268  entry = code_map->Lookup(event->new_code_start,
11270  true);
11271  CHECK(entry != NULL);
11272  entry->value = reinterpret_cast<void*>(event->code_len);
11273  }
11274  }
11275  break;
11276 
11278  // Object/code removal events are currently not dispatched from the GC.
11279  CHECK(false);
11280  break;
11281  default:
11282  // Impossible event.
11283  CHECK(false);
11284  break;
11285  }
11286 }
11287 
11288 
11289 // Implemented in the test-alloc.cc test suite.
11290 void SimulateFullSpace(i::PagedSpace* space);
11291 
11292 
11293 static bool MatchPointers(void* key1, void* key2) {
11294  return key1 == key2;
11295 }
11296 
11297 
11298 TEST(SetJitCodeEventHandler) {
11299  const char* script =
11300  "function bar() {"
11301  " var sum = 0;"
11302  " for (i = 0; i < 100; ++i)"
11303  " sum = foo(i);"
11304  " return sum;"
11305  "}"
11306  "function foo(i) { return i * i; };"
11307  "bar();";
11308 
11309  // Run this test in a new isolate to make sure we don't
11310  // have remnants of state from other code.
11311  v8::Isolate* isolate = v8::Isolate::New();
11312  isolate->Enter();
11313 
11314  {
11315  i::HashMap code(MatchPointers);
11316  code_map = &code;
11317 
11318  saw_bar = 0;
11319  move_events = 0;
11320 
11321  i::FLAG_stress_compaction = true;
11322  V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11323 
11324  v8::HandleScope scope;
11325  // Generate new code objects sparsely distributed across several
11326  // different fragmented code-space pages.
11327  const int kIterations = 10;
11328  for (int i = 0; i < kIterations; ++i) {
11329  LocalContext env;
11330 
11331  v8::Handle<v8::Script> compiled_script;
11332  {
11333  i::AlwaysAllocateScope always_allocate;
11334  SimulateFullSpace(HEAP->code_space());
11335  compiled_script = v8_compile(script);
11336  }
11337  compiled_script->Run();
11338 
11339  // Clear the compilation cache to get more wastage.
11340  ISOLATE->compilation_cache()->Clear();
11341  }
11342 
11343  // Force code movement.
11344  HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11345 
11346  CHECK_LE(kIterations, saw_bar);
11347  CHECK_NE(0, move_events);
11348 
11349  code_map = NULL;
11350  V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11351  }
11352 
11353  isolate->Exit();
11354  isolate->Dispose();
11355 
11356  // Do this in a new isolate.
11357  isolate = v8::Isolate::New();
11358  isolate->Enter();
11359 
11360  // Verify that we get callbacks for existing code objects when we
11361  // request enumeration of existing code.
11362  {
11363  v8::HandleScope scope;
11364  LocalContext env;
11365  CompileRun(script);
11366 
11367  // Now get code through initial iteration.
11368  i::HashMap code(MatchPointers);
11369  code_map = &code;
11370 
11371  V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11372  V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11373 
11374  code_map = NULL;
11375 
11376  // We expect that we got some events. Note that if we could get code removal
11377  // notifications, we could compare two collections, one created by listening
11378  // from the time of creation of an isolate, and the other by subscribing
11379  // with EnumExisting.
11380  CHECK_NE(0, code.occupancy());
11381  }
11382 
11383  isolate->Exit();
11384  isolate->Dispose();
11385 }
11386 
11387 
11388 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11389 
11390 
11391 THREADED_TEST(ExternalAllocatedMemory) {
11392  v8::HandleScope outer;
11393  v8::Persistent<Context> env(Context::New());
11394  CHECK(!env.IsEmpty());
11395  const intptr_t kSize = 1024*1024;
11397  cast(kSize));
11399  cast(0));
11400 }
11401 
11402 
11403 THREADED_TEST(DisposeEnteredContext) {
11404  v8::HandleScope scope;
11405  LocalContext outer;
11407  inner->Enter();
11408  inner.Dispose();
11409  inner.Clear();
11410  inner->Exit();
11411  }
11412 }
11413 
11414 
11415 // Regression test for issue 54, object templates with internal fields
11416 // but no accessors or interceptors did not get their internal field
11417 // count set on instances.
11418 THREADED_TEST(Regress54) {
11419  v8::HandleScope outer;
11420  LocalContext context;
11422  if (templ.IsEmpty()) {
11423  v8::HandleScope inner;
11425  local->SetInternalFieldCount(1);
11426  templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11427  }
11428  v8::Handle<v8::Object> result = templ->NewInstance();
11429  CHECK_EQ(1, result->InternalFieldCount());
11430 }
11431 
11432 
11433 // If part of the threaded tests, this test makes ThreadingTest fail
11434 // on mac.
11435 TEST(CatchStackOverflow) {
11436  v8::HandleScope scope;
11437  LocalContext context;
11438  v8::TryCatch try_catch;
11440  "function f() {"
11441  " return f();"
11442  "}"
11443  ""
11444  "f();"));
11445  v8::Handle<v8::Value> result = script->Run();
11446  CHECK(result.IsEmpty());
11447 }
11448 
11449 
11450 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11451  const char* resource_name,
11452  int line_offset) {
11453  v8::HandleScope scope;
11454  v8::TryCatch try_catch;
11455  v8::Handle<v8::Value> result = script->Run();
11456  CHECK(result.IsEmpty());
11457  CHECK(try_catch.HasCaught());
11458  v8::Handle<v8::Message> message = try_catch.Message();
11459  CHECK(!message.IsEmpty());
11460  CHECK_EQ(10 + line_offset, message->GetLineNumber());
11461  CHECK_EQ(91, message->GetStartPosition());
11462  CHECK_EQ(92, message->GetEndPosition());
11463  CHECK_EQ(2, message->GetStartColumn());
11464  CHECK_EQ(3, message->GetEndColumn());
11465  v8::String::AsciiValue line(message->GetSourceLine());
11466  CHECK_EQ(" throw 'nirk';", *line);
11467  v8::String::AsciiValue name(message->GetScriptResourceName());
11468  CHECK_EQ(resource_name, *name);
11469 }
11470 
11471 
11472 THREADED_TEST(TryCatchSourceInfo) {
11473  v8::HandleScope scope;
11474  LocalContext context;
11476  "function Foo() {\n"
11477  " return Bar();\n"
11478  "}\n"
11479  "\n"
11480  "function Bar() {\n"
11481  " return Baz();\n"
11482  "}\n"
11483  "\n"
11484  "function Baz() {\n"
11485  " throw 'nirk';\n"
11486  "}\n"
11487  "\n"
11488  "Foo();\n");
11489 
11490  const char* resource_name;
11491  v8::Handle<v8::Script> script;
11492  resource_name = "test.js";
11493  script = v8::Script::Compile(source, v8::String::New(resource_name));
11494  CheckTryCatchSourceInfo(script, resource_name, 0);
11495 
11496  resource_name = "test1.js";
11497  v8::ScriptOrigin origin1(v8::String::New(resource_name));
11498  script = v8::Script::Compile(source, &origin1);
11499  CheckTryCatchSourceInfo(script, resource_name, 0);
11500 
11501  resource_name = "test2.js";
11502  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11503  script = v8::Script::Compile(source, &origin2);
11504  CheckTryCatchSourceInfo(script, resource_name, 7);
11505 }
11506 
11507 
11508 THREADED_TEST(CompilationCache) {
11509  v8::HandleScope scope;
11510  LocalContext context;
11511  v8::Handle<v8::String> source0 = v8::String::New("1234");
11512  v8::Handle<v8::String> source1 = v8::String::New("1234");
11513  v8::Handle<v8::Script> script0 =
11514  v8::Script::Compile(source0, v8::String::New("test.js"));
11515  v8::Handle<v8::Script> script1 =
11516  v8::Script::Compile(source1, v8::String::New("test.js"));
11517  v8::Handle<v8::Script> script2 =
11518  v8::Script::Compile(source0); // different origin
11519  CHECK_EQ(1234, script0->Run()->Int32Value());
11520  CHECK_EQ(1234, script1->Run()->Int32Value());
11521  CHECK_EQ(1234, script2->Run()->Int32Value());
11522 }
11523 
11524 
11525 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11527  return v8_num(42);
11528 }
11529 
11530 
11531 THREADED_TEST(CallbackFunctionName) {
11532  v8::HandleScope scope;
11533  LocalContext context;
11534  Local<ObjectTemplate> t = ObjectTemplate::New();
11535  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11536  context->Global()->Set(v8_str("obj"), t->NewInstance());
11537  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11538  CHECK(value->IsString());
11539  v8::String::AsciiValue name(value);
11540  CHECK_EQ("asdf", *name);
11541 }
11542 
11543 
11544 THREADED_TEST(DateAccess) {
11545  v8::HandleScope scope;
11546  LocalContext context;
11547  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11548  CHECK(date->IsDate());
11549  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
11550 }
11551 
11552 
11553 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
11554  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11555  v8::Handle<v8::Array> props = obj->GetPropertyNames();
11556  CHECK_EQ(elmc, props->Length());
11557  for (int i = 0; i < elmc; i++) {
11558  v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11559  CHECK_EQ(elmv[i], *elm);
11560  }
11561 }
11562 
11563 
11565  int elmc,
11566  const char* elmv[]) {
11567  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11569  CHECK_EQ(elmc, props->Length());
11570  for (int i = 0; i < elmc; i++) {
11571  v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11572  CHECK_EQ(elmv[i], *elm);
11573  }
11574 }
11575 
11576 
11577 THREADED_TEST(PropertyEnumeration) {
11578  v8::HandleScope scope;
11579  LocalContext context;
11581  "var result = [];"
11582  "result[0] = {};"
11583  "result[1] = {a: 1, b: 2};"
11584  "result[2] = [1, 2, 3];"
11585  "var proto = {x: 1, y: 2, z: 3};"
11586  "var x = { __proto__: proto, w: 0, z: 1 };"
11587  "result[3] = x;"
11588  "result;"))->Run();
11589  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11590  CHECK_EQ(4, elms->Length());
11591  int elmc0 = 0;
11592  const char** elmv0 = NULL;
11593  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11594  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11595  int elmc1 = 2;
11596  const char* elmv1[] = {"a", "b"};
11597  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11598  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11599  int elmc2 = 3;
11600  const char* elmv2[] = {"0", "1", "2"};
11601  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11602  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11603  int elmc3 = 4;
11604  const char* elmv3[] = {"w", "z", "x", "y"};
11605  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
11606  int elmc4 = 2;
11607  const char* elmv4[] = {"w", "z"};
11608  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
11609 }
11610 
11611 THREADED_TEST(PropertyEnumeration2) {
11612  v8::HandleScope scope;
11613  LocalContext context;
11615  "var result = [];"
11616  "result[0] = {};"
11617  "result[1] = {a: 1, b: 2};"
11618  "result[2] = [1, 2, 3];"
11619  "var proto = {x: 1, y: 2, z: 3};"
11620  "var x = { __proto__: proto, w: 0, z: 1 };"
11621  "result[3] = x;"
11622  "result;"))->Run();
11623  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11624  CHECK_EQ(4, elms->Length());
11625  int elmc0 = 0;
11626  const char** elmv0 = NULL;
11627  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11628 
11629  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11630  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11631  CHECK_EQ(0, props->Length());
11632  for (uint32_t i = 0; i < props->Length(); i++) {
11633  printf("p[%d]\n", i);
11634  }
11635 }
11636 
11637 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11638  Local<Value> name,
11639  v8::AccessType type,
11640  Local<Value> data) {
11641  return type != v8::ACCESS_SET;
11642 }
11643 
11644 
11645 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11646  uint32_t key,
11647  v8::AccessType type,
11648  Local<Value> data) {
11649  return type != v8::ACCESS_SET;
11650 }
11651 
11652 
11653 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11654  v8::HandleScope scope;
11655  LocalContext context;
11656  Local<ObjectTemplate> templ = ObjectTemplate::New();
11657  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11658  IndexedSetAccessBlocker);
11659  templ->Set(v8_str("x"), v8::True());
11660  Local<v8::Object> instance = templ->NewInstance();
11661  context->Global()->Set(v8_str("obj"), instance);
11662  Local<Value> value = CompileRun("obj.x");
11663  CHECK(value->BooleanValue());
11664 }
11665 
11666 
11667 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11668  Local<Value> name,
11669  v8::AccessType type,
11670  Local<Value> data) {
11671  return false;
11672 }
11673 
11674 
11675 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11676  uint32_t key,
11677  v8::AccessType type,
11678  Local<Value> data) {
11679  return false;
11680 }
11681 
11682 
11683 
11684 THREADED_TEST(AccessChecksReenabledCorrectly) {
11685  v8::HandleScope scope;
11686  LocalContext context;
11687  Local<ObjectTemplate> templ = ObjectTemplate::New();
11688  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11689  IndexedGetAccessBlocker);
11690  templ->Set(v8_str("a"), v8_str("a"));
11691  // Add more than 8 (see kMaxFastProperties) properties
11692  // so that the constructor will force copying map.
11693  // Cannot sprintf, gcc complains unsafety.
11694  char buf[4];
11695  for (char i = '0'; i <= '9' ; i++) {
11696  buf[0] = i;
11697  for (char j = '0'; j <= '9'; j++) {
11698  buf[1] = j;
11699  for (char k = '0'; k <= '9'; k++) {
11700  buf[2] = k;
11701  buf[3] = 0;
11702  templ->Set(v8_str(buf), v8::Number::New(k));
11703  }
11704  }
11705  }
11706 
11707  Local<v8::Object> instance_1 = templ->NewInstance();
11708  context->Global()->Set(v8_str("obj_1"), instance_1);
11709 
11710  Local<Value> value_1 = CompileRun("obj_1.a");
11711  CHECK(value_1->IsUndefined());
11712 
11713  Local<v8::Object> instance_2 = templ->NewInstance();
11714  context->Global()->Set(v8_str("obj_2"), instance_2);
11715 
11716  Local<Value> value_2 = CompileRun("obj_2.a");
11717  CHECK(value_2->IsUndefined());
11718 }
11719 
11720 
11721 // This tests that access check information remains on the global
11722 // object template when creating contexts.
11723 THREADED_TEST(AccessControlRepeatedContextCreation) {
11724  v8::HandleScope handle_scope;
11726  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11727  IndexedSetAccessBlocker);
11728  i::Handle<i::ObjectTemplateInfo> internal_template =
11729  v8::Utils::OpenHandle(*global_template);
11730  CHECK(!internal_template->constructor()->IsUndefined());
11732  i::FunctionTemplateInfo::cast(internal_template->constructor()));
11733  CHECK(!constructor->access_check_info()->IsUndefined());
11734  v8::Persistent<Context> context0(Context::New(NULL, global_template));
11735  CHECK(!context0.IsEmpty());
11736  CHECK(!constructor->access_check_info()->IsUndefined());
11737 }
11738 
11739 
11740 THREADED_TEST(TurnOnAccessCheck) {
11741  v8::HandleScope handle_scope;
11742 
11743  // Create an environment with access check to the global object disabled by
11744  // default.
11746  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11747  IndexedGetAccessBlocker,
11749  false);
11750  v8::Persistent<Context> context = Context::New(NULL, global_template);
11751  Context::Scope context_scope(context);
11752 
11753  // Set up a property and a number of functions.
11754  context->Global()->Set(v8_str("a"), v8_num(1));
11755  CompileRun("function f1() {return a;}"
11756  "function f2() {return a;}"
11757  "function g1() {return h();}"
11758  "function g2() {return h();}"
11759  "function h() {return 1;}");
11760  Local<Function> f1 =
11761  Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11762  Local<Function> f2 =
11763  Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11764  Local<Function> g1 =
11765  Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11766  Local<Function> g2 =
11767  Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11768  Local<Function> h =
11769  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11770 
11771  // Get the global object.
11772  v8::Handle<v8::Object> global = context->Global();
11773 
11774  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11775  // uses the runtime system to retreive property a whereas f2 uses global load
11776  // inline cache.
11777  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11778  for (int i = 0; i < 4; i++) {
11779  CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11780  }
11781 
11782  // Same for g1 and g2.
11783  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11784  for (int i = 0; i < 4; i++) {
11785  CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11786  }
11787 
11788  // Detach the global and turn on access check.
11789  context->DetachGlobal();
11790  context->Global()->TurnOnAccessCheck();
11791 
11792  // Failing access check to property get results in undefined.
11793  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11794  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11795 
11796  // Failing access check to function call results in exception.
11797  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11798  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11799 
11800  // No failing access check when just returning a constant.
11801  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11802 }
11803 
11804 
11805 static const char* kPropertyA = "a";
11806 static const char* kPropertyH = "h";
11807 
11808 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11809  Local<Value> name,
11810  v8::AccessType type,
11811  Local<Value> data) {
11812  if (!name->IsString()) return false;
11813  i::Handle<i::String> name_handle =
11814  v8::Utils::OpenHandle(String::Cast(*name));
11815  return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11816  && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
11817 }
11818 
11819 
11820 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11821  v8::HandleScope handle_scope;
11822 
11823  // Create an environment with access check to the global object disabled by
11824  // default. When the registered access checker will block access to properties
11825  // a and h.
11827  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11828  IndexedGetAccessBlocker,
11830  false);
11831  v8::Persistent<Context> context = Context::New(NULL, global_template);
11832  Context::Scope context_scope(context);
11833 
11834  // Set up a property and a number of functions.
11835  context->Global()->Set(v8_str("a"), v8_num(1));
11836  static const char* source = "function f1() {return a;}"
11837  "function f2() {return a;}"
11838  "function g1() {return h();}"
11839  "function g2() {return h();}"
11840  "function h() {return 1;}";
11841 
11842  CompileRun(source);
11843  Local<Function> f1;
11844  Local<Function> f2;
11845  Local<Function> g1;
11846  Local<Function> g2;
11847  Local<Function> h;
11848  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11849  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11850  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11851  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11852  h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11853 
11854  // Get the global object.
11855  v8::Handle<v8::Object> global = context->Global();
11856 
11857  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11858  // uses the runtime system to retreive property a whereas f2 uses global load
11859  // inline cache.
11860  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11861  for (int i = 0; i < 4; i++) {
11862  CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11863  }
11864 
11865  // Same for g1 and g2.
11866  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11867  for (int i = 0; i < 4; i++) {
11868  CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11869  }
11870 
11871  // Detach the global and turn on access check now blocking access to property
11872  // a and function h.
11873  context->DetachGlobal();
11874  context->Global()->TurnOnAccessCheck();
11875 
11876  // Failing access check to property get results in undefined.
11877  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11878  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11879 
11880  // Failing access check to function call results in exception.
11881  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11882  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11883 
11884  // No failing access check when just returning a constant.
11885  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11886 
11887  // Now compile the source again. And get the newly compiled functions, except
11888  // for h for which access is blocked.
11889  CompileRun(source);
11890  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11891  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11892  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11893  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11894  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11895 
11896  // Failing access check to property get results in undefined.
11897  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11898  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11899 
11900  // Failing access check to function call results in exception.
11901  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11902  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11903 }
11904 
11905 
11906 // This test verifies that pre-compilation (aka preparsing) can be called
11907 // without initializing the whole VM. Thus we cannot run this test in a
11908 // multi-threaded setup.
11909 TEST(PreCompile) {
11910  // TODO(155): This test would break without the initialization of V8. This is
11911  // a workaround for now to make this test not fail.
11913  const char* script = "function foo(a) { return a+1; }";
11914  v8::ScriptData* sd =
11915  v8::ScriptData::PreCompile(script, i::StrLength(script));
11916  CHECK_NE(sd->Length(), 0);
11917  CHECK_NE(sd->Data(), NULL);
11918  CHECK(!sd->HasError());
11919  delete sd;
11920 }
11921 
11922 
11923 TEST(PreCompileWithError) {
11925  const char* script = "function foo(a) { return 1 * * 2; }";
11926  v8::ScriptData* sd =
11927  v8::ScriptData::PreCompile(script, i::StrLength(script));
11928  CHECK(sd->HasError());
11929  delete sd;
11930 }
11931 
11932 
11933 TEST(Regress31661) {
11935  const char* script = " The Definintive Guide";
11936  v8::ScriptData* sd =
11937  v8::ScriptData::PreCompile(script, i::StrLength(script));
11938  CHECK(sd->HasError());
11939  delete sd;
11940 }
11941 
11942 
11943 // Tests that ScriptData can be serialized and deserialized.
11944 TEST(PreCompileSerialization) {
11946  const char* script = "function foo(a) { return a+1; }";
11947  v8::ScriptData* sd =
11948  v8::ScriptData::PreCompile(script, i::StrLength(script));
11949 
11950  // Serialize.
11951  int serialized_data_length = sd->Length();
11952  char* serialized_data = i::NewArray<char>(serialized_data_length);
11953  memcpy(serialized_data, sd->Data(), serialized_data_length);
11954 
11955  // Deserialize.
11956  v8::ScriptData* deserialized_sd =
11957  v8::ScriptData::New(serialized_data, serialized_data_length);
11958 
11959  // Verify that the original is the same as the deserialized.
11960  CHECK_EQ(sd->Length(), deserialized_sd->Length());
11961  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11962  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11963 
11964  delete sd;
11965  delete deserialized_sd;
11966 }
11967 
11968 
11969 // Attempts to deserialize bad data.
11970 TEST(PreCompileDeserializationError) {
11972  const char* data = "DONT CARE";
11973  int invalid_size = 3;
11974  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11975 
11976  CHECK_EQ(0, sd->Length());
11977 
11978  delete sd;
11979 }
11980 
11981 
11982 // Attempts to deserialize bad data.
11983 TEST(PreCompileInvalidPreparseDataError) {
11985  v8::HandleScope scope;
11986  LocalContext context;
11987 
11988  const char* script = "function foo(){ return 5;}\n"
11989  "function bar(){ return 6 + 7;} foo();";
11990  v8::ScriptData* sd =
11991  v8::ScriptData::PreCompile(script, i::StrLength(script));
11992  CHECK(!sd->HasError());
11993  // ScriptDataImpl private implementation details
11994  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11995  const int kFunctionEntrySize = i::FunctionEntry::kSize;
11996  const int kFunctionEntryStartOffset = 0;
11997  const int kFunctionEntryEndOffset = 1;
11998  unsigned* sd_data =
11999  reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
12000 
12001  // Overwrite function bar's end position with 0.
12002  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12003  v8::TryCatch try_catch;
12004 
12005  Local<String> source = String::New(script);
12006  Local<Script> compiled_script = Script::New(source, NULL, sd);
12007  CHECK(try_catch.HasCaught());
12008  String::AsciiValue exception_value(try_catch.Message()->Get());
12009  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12010  *exception_value);
12011 
12012  try_catch.Reset();
12013 
12014  // Overwrite function bar's start position with 200. The function entry
12015  // will not be found when searching for it by position and we should fall
12016  // back on eager compilation.
12017  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12018  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
12019  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12020  200;
12021  compiled_script = Script::New(source, NULL, sd);
12022  CHECK(!try_catch.HasCaught());
12023 
12024  delete sd;
12025 }
12026 
12027 
12028 // Verifies that the Handle<String> and const char* versions of the API produce
12029 // the same results (at least for one trivial case).
12030 TEST(PreCompileAPIVariationsAreSame) {
12032  v8::HandleScope scope;
12033 
12034  const char* cstring = "function foo(a) { return a+1; }";
12035 
12036  v8::ScriptData* sd_from_cstring =
12037  v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12038 
12039  TestAsciiResource* resource = new TestAsciiResource(cstring);
12040  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
12041  v8::String::NewExternal(resource));
12042 
12043  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12044  v8::String::New(cstring));
12045 
12046  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
12047  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12048  sd_from_external_string->Data(),
12049  sd_from_cstring->Length()));
12050 
12051  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12052  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12053  sd_from_string->Data(),
12054  sd_from_cstring->Length()));
12055 
12056 
12057  delete sd_from_cstring;
12058  delete sd_from_external_string;
12059  delete sd_from_string;
12060 }
12061 
12062 
12063 // This tests that we do not allow dictionary load/call inline caches
12064 // to use functions that have not yet been compiled. The potential
12065 // problem of loading a function that has not yet been compiled can
12066 // arise because we share code between contexts via the compilation
12067 // cache.
12068 THREADED_TEST(DictionaryICLoadedFunction) {
12069  v8::HandleScope scope;
12070  // Test LoadIC.
12071  for (int i = 0; i < 2; i++) {
12072  LocalContext context;
12073  context->Global()->Set(v8_str("tmp"), v8::True());
12074  context->Global()->Delete(v8_str("tmp"));
12075  CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12076  }
12077  // Test CallIC.
12078  for (int i = 0; i < 2; i++) {
12079  LocalContext context;
12080  context->Global()->Set(v8_str("tmp"), v8::True());
12081  context->Global()->Delete(v8_str("tmp"));
12082  CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12083  }
12084 }
12085 
12086 
12087 // Test that cross-context new calls use the context of the callee to
12088 // create the new JavaScript object.
12089 THREADED_TEST(CrossContextNew) {
12090  v8::HandleScope scope;
12091  v8::Persistent<Context> context0 = Context::New();
12092  v8::Persistent<Context> context1 = Context::New();
12093 
12094  // Allow cross-domain access.
12095  Local<String> token = v8_str("<security token>");
12096  context0->SetSecurityToken(token);
12097  context1->SetSecurityToken(token);
12098 
12099  // Set an 'x' property on the Object prototype and define a
12100  // constructor function in context0.
12101  context0->Enter();
12102  CompileRun("Object.prototype.x = 42; function C() {};");
12103  context0->Exit();
12104 
12105  // Call the constructor function from context0 and check that the
12106  // result has the 'x' property.
12107  context1->Enter();
12108  context1->Global()->Set(v8_str("other"), context0->Global());
12109  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12110  CHECK(value->IsInt32());
12111  CHECK_EQ(42, value->Int32Value());
12112  context1->Exit();
12113 
12114  // Dispose the contexts to allow them to be garbage collected.
12115  context0.Dispose();
12116  context1.Dispose();
12117 }
12118 
12119 
12121  public:
12122  RegExpInterruptTest() : block_(NULL) {}
12123  ~RegExpInterruptTest() { delete block_; }
12124  void RunTest() {
12125  block_ = i::OS::CreateSemaphore(0);
12126  gc_count_ = 0;
12127  gc_during_regexp_ = 0;
12128  regexp_success_ = false;
12129  gc_success_ = false;
12130  GCThread gc_thread(this);
12131  gc_thread.Start();
12133 
12134  LongRunningRegExp();
12135  {
12136  v8::Unlocker unlock;
12137  gc_thread.Join();
12138  }
12140  CHECK(regexp_success_);
12141  CHECK(gc_success_);
12142  }
12143 
12144  private:
12145  // Number of garbage collections required.
12146  static const int kRequiredGCs = 5;
12147 
12148  class GCThread : public i::Thread {
12149  public:
12150  explicit GCThread(RegExpInterruptTest* test)
12151  : Thread("GCThread"), test_(test) {}
12152  virtual void Run() {
12153  test_->CollectGarbage();
12154  }
12155  private:
12156  RegExpInterruptTest* test_;
12157  };
12158 
12159  void CollectGarbage() {
12160  block_->Wait();
12161  while (gc_during_regexp_ < kRequiredGCs) {
12162  {
12163  v8::Locker lock;
12164  // TODO(lrn): Perhaps create some garbage before collecting.
12165  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12166  gc_count_++;
12167  }
12168  i::OS::Sleep(1);
12169  }
12170  gc_success_ = true;
12171  }
12172 
12173  void LongRunningRegExp() {
12174  block_->Signal(); // Enable garbage collection thread on next preemption.
12175  int rounds = 0;
12176  while (gc_during_regexp_ < kRequiredGCs) {
12177  int gc_before = gc_count_;
12178  {
12179  // Match 15-30 "a"'s against 14 and a "b".
12180  const char* c_source =
12181  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12182  ".exec('aaaaaaaaaaaaaaab') === null";
12183  Local<String> source = String::New(c_source);
12184  Local<Script> script = Script::Compile(source);
12185  Local<Value> result = script->Run();
12186  if (!result->BooleanValue()) {
12187  gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12188  return;
12189  }
12190  }
12191  {
12192  // Match 15-30 "a"'s against 15 and a "b".
12193  const char* c_source =
12194  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12195  ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12196  Local<String> source = String::New(c_source);
12197  Local<Script> script = Script::Compile(source);
12198  Local<Value> result = script->Run();
12199  if (!result->BooleanValue()) {
12200  gc_during_regexp_ = kRequiredGCs;
12201  return;
12202  }
12203  }
12204  int gc_after = gc_count_;
12205  gc_during_regexp_ += gc_after - gc_before;
12206  rounds++;
12207  i::OS::Sleep(1);
12208  }
12209  regexp_success_ = true;
12210  }
12211 
12212  i::Semaphore* block_;
12213  int gc_count_;
12214  int gc_during_regexp_;
12215  bool regexp_success_;
12216  bool gc_success_;
12217 };
12218 
12219 
12220 // Test that a regular expression execution can be interrupted and
12221 // survive a garbage collection.
12222 TEST(RegExpInterruption) {
12223  v8::Locker lock;
12225  v8::HandleScope scope;
12226  Local<Context> local_env;
12227  {
12228  LocalContext env;
12229  local_env = env.local();
12230  }
12231 
12232  // Local context should still be live.
12233  CHECK(!local_env.IsEmpty());
12234  local_env->Enter();
12235 
12236  // Should complete without problems.
12238 
12239  local_env->Exit();
12240 }
12241 
12242 
12244  public:
12245  ApplyInterruptTest() : block_(NULL) {}
12246  ~ApplyInterruptTest() { delete block_; }
12247  void RunTest() {
12248  block_ = i::OS::CreateSemaphore(0);
12249  gc_count_ = 0;
12250  gc_during_apply_ = 0;
12251  apply_success_ = false;
12252  gc_success_ = false;
12253  GCThread gc_thread(this);
12254  gc_thread.Start();
12256 
12257  LongRunningApply();
12258  {
12259  v8::Unlocker unlock;
12260  gc_thread.Join();
12261  }
12263  CHECK(apply_success_);
12264  CHECK(gc_success_);
12265  }
12266 
12267  private:
12268  // Number of garbage collections required.
12269  static const int kRequiredGCs = 2;
12270 
12271  class GCThread : public i::Thread {
12272  public:
12273  explicit GCThread(ApplyInterruptTest* test)
12274  : Thread("GCThread"), test_(test) {}
12275  virtual void Run() {
12276  test_->CollectGarbage();
12277  }
12278  private:
12279  ApplyInterruptTest* test_;
12280  };
12281 
12282  void CollectGarbage() {
12283  block_->Wait();
12284  while (gc_during_apply_ < kRequiredGCs) {
12285  {
12286  v8::Locker lock;
12287  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12288  gc_count_++;
12289  }
12290  i::OS::Sleep(1);
12291  }
12292  gc_success_ = true;
12293  }
12294 
12295  void LongRunningApply() {
12296  block_->Signal();
12297  int rounds = 0;
12298  while (gc_during_apply_ < kRequiredGCs) {
12299  int gc_before = gc_count_;
12300  {
12301  const char* c_source =
12302  "function do_very_little(bar) {"
12303  " this.foo = bar;"
12304  "}"
12305  "for (var i = 0; i < 100000; i++) {"
12306  " do_very_little.apply(this, ['bar']);"
12307  "}";
12308  Local<String> source = String::New(c_source);
12309  Local<Script> script = Script::Compile(source);
12310  Local<Value> result = script->Run();
12311  // Check that no exception was thrown.
12312  CHECK(!result.IsEmpty());
12313  }
12314  int gc_after = gc_count_;
12315  gc_during_apply_ += gc_after - gc_before;
12316  rounds++;
12317  }
12318  apply_success_ = true;
12319  }
12320 
12321  i::Semaphore* block_;
12322  int gc_count_;
12323  int gc_during_apply_;
12324  bool apply_success_;
12325  bool gc_success_;
12326 };
12327 
12328 
12329 // Test that nothing bad happens if we get a preemption just when we were
12330 // about to do an apply().
12331 TEST(ApplyInterruption) {
12332  v8::Locker lock;
12334  v8::HandleScope scope;
12335  Local<Context> local_env;
12336  {
12337  LocalContext env;
12338  local_env = env.local();
12339  }
12340 
12341  // Local context should still be live.
12342  CHECK(!local_env.IsEmpty());
12343  local_env->Enter();
12344 
12345  // Should complete without problems.
12347 
12348  local_env->Exit();
12349 }
12350 
12351 
12352 // Verify that we can clone an object
12353 TEST(ObjectClone) {
12354  v8::HandleScope scope;
12355  LocalContext env;
12356 
12357  const char* sample =
12358  "var rv = {};" \
12359  "rv.alpha = 'hello';" \
12360  "rv.beta = 123;" \
12361  "rv;";
12362 
12363  // Create an object, verify basics.
12364  Local<Value> val = CompileRun(sample);
12365  CHECK(val->IsObject());
12366  Local<v8::Object> obj = val.As<v8::Object>();
12367  obj->Set(v8_str("gamma"), v8_str("cloneme"));
12368 
12369  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12370  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12371  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12372 
12373  // Clone it.
12374  Local<v8::Object> clone = obj->Clone();
12375  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12376  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12377  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12378 
12379  // Set a property on the clone, verify each object.
12380  clone->Set(v8_str("beta"), v8::Integer::New(456));
12381  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12382  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12383 }
12384 
12385 
12387  public:
12389  : data_(vector) {}
12391  virtual size_t length() const { return data_.length(); }
12392  virtual const char* data() const { return data_.start(); }
12393  private:
12394  i::Vector<const char> data_;
12395 };
12396 
12397 
12399  public:
12401  : data_(vector) {}
12402  virtual ~UC16VectorResource() {}
12403  virtual size_t length() const { return data_.length(); }
12404  virtual const i::uc16* data() const { return data_.start(); }
12405  private:
12407 };
12408 
12409 
12410 static void MorphAString(i::String* string,
12411  AsciiVectorResource* ascii_resource,
12412  UC16VectorResource* uc16_resource) {
12413  CHECK(i::StringShape(string).IsExternal());
12414  if (string->IsAsciiRepresentation()) {
12415  // Check old map is not symbol or long.
12416  CHECK(string->map() == HEAP->external_ascii_string_map());
12417  // Morph external string to be TwoByte string.
12418  string->set_map(HEAP->external_string_map());
12419  i::ExternalTwoByteString* morphed =
12421  morphed->set_resource(uc16_resource);
12422  } else {
12423  // Check old map is not symbol or long.
12424  CHECK(string->map() == HEAP->external_string_map());
12425  // Morph external string to be ASCII string.
12426  string->set_map(HEAP->external_ascii_string_map());
12427  i::ExternalAsciiString* morphed =
12429  morphed->set_resource(ascii_resource);
12430  }
12431 }
12432 
12433 
12434 // Test that we can still flatten a string if the components it is built up
12435 // from have been turned into 16 bit strings in the mean time.
12436 THREADED_TEST(MorphCompositeStringTest) {
12437  char utf_buffer[129];
12438  const char* c_string = "Now is the time for all good men"
12439  " to come to the aid of the party";
12440  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12441  {
12442  v8::HandleScope scope;
12443  LocalContext env;
12444  AsciiVectorResource ascii_resource(
12445  i::Vector<const char>(c_string, i::StrLength(c_string)));
12446  UC16VectorResource uc16_resource(
12447  i::Vector<const uint16_t>(two_byte_string,
12448  i::StrLength(c_string)));
12449 
12450  Local<String> lhs(v8::Utils::ToLocal(
12451  FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12452  Local<String> rhs(v8::Utils::ToLocal(
12453  FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12454 
12455  env->Global()->Set(v8_str("lhs"), lhs);
12456  env->Global()->Set(v8_str("rhs"), rhs);
12457 
12458  CompileRun(
12459  "var cons = lhs + rhs;"
12460  "var slice = lhs.substring(1, lhs.length - 1);"
12461  "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12462 
12463  CHECK(!lhs->MayContainNonAscii());
12464  CHECK(!rhs->MayContainNonAscii());
12465 
12466  MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12467  MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12468 
12469  // This should UTF-8 without flattening, since everything is ASCII.
12470  Handle<String> cons = v8_compile("cons")->Run().As<String>();
12471  CHECK_EQ(128, cons->Utf8Length());
12472  int nchars = -1;
12473  CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12474  CHECK_EQ(128, nchars);
12475  CHECK_EQ(0, strcmp(
12476  utf_buffer,
12477  "Now is the time for all good men to come to the aid of the party"
12478  "Now is the time for all good men to come to the aid of the party"));
12479 
12480  // Now do some stuff to make sure the strings are flattened, etc.
12481  CompileRun(
12482  "/[^a-z]/.test(cons);"
12483  "/[^a-z]/.test(slice);"
12484  "/[^a-z]/.test(slice_on_cons);");
12485  const char* expected_cons =
12486  "Now is the time for all good men to come to the aid of the party"
12487  "Now is the time for all good men to come to the aid of the party";
12488  const char* expected_slice =
12489  "ow is the time for all good men to come to the aid of the part";
12490  const char* expected_slice_on_cons =
12491  "ow is the time for all good men to come to the aid of the party"
12492  "Now is the time for all good men to come to the aid of the part";
12493  CHECK_EQ(String::New(expected_cons),
12494  env->Global()->Get(v8_str("cons")));
12495  CHECK_EQ(String::New(expected_slice),
12496  env->Global()->Get(v8_str("slice")));
12497  CHECK_EQ(String::New(expected_slice_on_cons),
12498  env->Global()->Get(v8_str("slice_on_cons")));
12499  }
12500  i::DeleteArray(two_byte_string);
12501 }
12502 
12503 
12504 TEST(CompileExternalTwoByteSource) {
12505  v8::HandleScope scope;
12506  LocalContext context;
12507 
12508  // This is a very short list of sources, which currently is to check for a
12509  // regression caused by r2703.
12510  const char* ascii_sources[] = {
12511  "0.5",
12512  "-0.5", // This mainly testes PushBack in the Scanner.
12513  "--0.5", // This mainly testes PushBack in the Scanner.
12514  NULL
12515  };
12516 
12517  // Compile the sources as external two byte strings.
12518  for (int i = 0; ascii_sources[i] != NULL; i++) {
12519  uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12520  UC16VectorResource uc16_resource(
12521  i::Vector<const uint16_t>(two_byte_string,
12522  i::StrLength(ascii_sources[i])));
12523  v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12524  v8::Script::Compile(source);
12525  i::DeleteArray(two_byte_string);
12526  }
12527 }
12528 
12529 
12531  public:
12533  : block_(i::OS::CreateSemaphore(0)),
12534  morphs_(0),
12535  morphs_during_regexp_(0),
12536  ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12537  uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12538  ~RegExpStringModificationTest() { delete block_; }
12539  void RunTest() {
12540  regexp_success_ = false;
12541  morph_success_ = false;
12542 
12543  // Initialize the contents of two_byte_content_ to be a uc16 representation
12544  // of "aaaaaaaaaaaaaab".
12545  for (int i = 0; i < 14; i++) {
12546  two_byte_content_[i] = 'a';
12547  }
12548  two_byte_content_[14] = 'b';
12549 
12550  // Create the input string for the regexp - the one we are going to change
12551  // properties of.
12552  input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
12553 
12554  // Inject the input as a global variable.
12555  i::Handle<i::String> input_name =
12556  FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
12557  i::Isolate::Current()->native_context()->global_object()->SetProperty(
12558  *input_name,
12559  *input_,
12560  NONE,
12561  i::kNonStrictMode)->ToObjectChecked();
12562 
12563  MorphThread morph_thread(this);
12564  morph_thread.Start();
12566  LongRunningRegExp();
12567  {
12568  v8::Unlocker unlock;
12569  morph_thread.Join();
12570  }
12572  CHECK(regexp_success_);
12573  CHECK(morph_success_);
12574  }
12575 
12576  private:
12577  // Number of string modifications required.
12578  static const int kRequiredModifications = 5;
12579  static const int kMaxModifications = 100;
12580 
12581  class MorphThread : public i::Thread {
12582  public:
12583  explicit MorphThread(RegExpStringModificationTest* test)
12584  : Thread("MorphThread"), test_(test) {}
12585  virtual void Run() {
12586  test_->MorphString();
12587  }
12588  private:
12590  };
12591 
12592  void MorphString() {
12593  block_->Wait();
12594  while (morphs_during_regexp_ < kRequiredModifications &&
12595  morphs_ < kMaxModifications) {
12596  {
12597  v8::Locker lock;
12598  // Swap string between ascii and two-byte representation.
12599  i::String* string = *input_;
12600  MorphAString(string, &ascii_resource_, &uc16_resource_);
12601  morphs_++;
12602  }
12603  i::OS::Sleep(1);
12604  }
12605  morph_success_ = true;
12606  }
12607 
12608  void LongRunningRegExp() {
12609  block_->Signal(); // Enable morphing thread on next preemption.
12610  while (morphs_during_regexp_ < kRequiredModifications &&
12611  morphs_ < kMaxModifications) {
12612  int morphs_before = morphs_;
12613  {
12614  v8::HandleScope scope;
12615  // Match 15-30 "a"'s against 14 and a "b".
12616  const char* c_source =
12617  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12618  ".exec(input) === null";
12619  Local<String> source = String::New(c_source);
12620  Local<Script> script = Script::Compile(source);
12621  Local<Value> result = script->Run();
12622  CHECK(result->IsTrue());
12623  }
12624  int morphs_after = morphs_;
12625  morphs_during_regexp_ += morphs_after - morphs_before;
12626  }
12627  regexp_success_ = true;
12628  }
12629 
12630  i::uc16 two_byte_content_[15];
12631  i::Semaphore* block_;
12632  int morphs_;
12633  int morphs_during_regexp_;
12634  bool regexp_success_;
12635  bool morph_success_;
12636  i::Handle<i::String> input_;
12637  AsciiVectorResource ascii_resource_;
12638  UC16VectorResource uc16_resource_;
12639 };
12640 
12641 
12642 // Test that a regular expression execution can be interrupted and
12643 // the string changed without failing.
12644 TEST(RegExpStringModification) {
12645  v8::Locker lock;
12647  v8::HandleScope scope;
12648  Local<Context> local_env;
12649  {
12650  LocalContext env;
12651  local_env = env.local();
12652  }
12653 
12654  // Local context should still be live.
12655  CHECK(!local_env.IsEmpty());
12656  local_env->Enter();
12657 
12658  // Should complete without problems.
12660 
12661  local_env->Exit();
12662 }
12663 
12664 
12665 // Test that we cannot set a property on the global object if there
12666 // is a read-only property in the prototype chain.
12667 TEST(ReadOnlyPropertyInGlobalProto) {
12668  i::FLAG_es5_readonly = true;
12669  v8::HandleScope scope;
12671  LocalContext context(0, templ);
12672  v8::Handle<v8::Object> global = context->Global();
12673  v8::Handle<v8::Object> global_proto =
12674  v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12675  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12676  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12677  // Check without 'eval' or 'with'.
12678  v8::Handle<v8::Value> res =
12679  CompileRun("function f() { x = 42; return x; }; f()");
12680  CHECK_EQ(v8::Integer::New(0), res);
12681  // Check with 'eval'.
12682  res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12683  CHECK_EQ(v8::Integer::New(0), res);
12684  // Check with 'with'.
12685  res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12686  CHECK_EQ(v8::Integer::New(0), res);
12687 }
12688 
12689 static int force_set_set_count = 0;
12690 static int force_set_get_count = 0;
12691 bool pass_on_get = false;
12692 
12693 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12694  const v8::AccessorInfo& info) {
12695  force_set_get_count++;
12696  if (pass_on_get) {
12697  return v8::Handle<v8::Value>();
12698  } else {
12699  return v8::Int32::New(3);
12700  }
12701 }
12702 
12703 static void ForceSetSetter(v8::Local<v8::String> name,
12704  v8::Local<v8::Value> value,
12705  const v8::AccessorInfo& info) {
12706  force_set_set_count++;
12707 }
12708 
12709 static v8::Handle<v8::Value> ForceSetInterceptSetter(
12710  v8::Local<v8::String> name,
12711  v8::Local<v8::Value> value,
12712  const v8::AccessorInfo& info) {
12713  force_set_set_count++;
12714  return v8::Undefined();
12715 }
12716 
12717 TEST(ForceSet) {
12718  force_set_get_count = 0;
12719  force_set_set_count = 0;
12720  pass_on_get = false;
12721 
12722  v8::HandleScope scope;
12724  v8::Handle<v8::String> access_property = v8::String::New("a");
12725  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12726  LocalContext context(NULL, templ);
12727  v8::Handle<v8::Object> global = context->Global();
12728 
12729  // Ordinary properties
12730  v8::Handle<v8::String> simple_property = v8::String::New("p");
12731  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12732  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12733  // This should fail because the property is read-only
12734  global->Set(simple_property, v8::Int32::New(5));
12735  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12736  // This should succeed even though the property is read-only
12737  global->ForceSet(simple_property, v8::Int32::New(6));
12738  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12739 
12740  // Accessors
12741  CHECK_EQ(0, force_set_set_count);
12742  CHECK_EQ(0, force_set_get_count);
12743  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12744  // CHECK_EQ the property shouldn't override it, just call the setter
12745  // which in this case does nothing.
12746  global->Set(access_property, v8::Int32::New(7));
12747  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12748  CHECK_EQ(1, force_set_set_count);
12749  CHECK_EQ(2, force_set_get_count);
12750  // Forcing the property to be set should override the accessor without
12751  // calling it
12752  global->ForceSet(access_property, v8::Int32::New(8));
12753  CHECK_EQ(8, global->Get(access_property)->Int32Value());
12754  CHECK_EQ(1, force_set_set_count);
12755  CHECK_EQ(2, force_set_get_count);
12756 }
12757 
12758 TEST(ForceSetWithInterceptor) {
12759  force_set_get_count = 0;
12760  force_set_set_count = 0;
12761  pass_on_get = false;
12762 
12763  v8::HandleScope scope;
12765  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12766  LocalContext context(NULL, templ);
12767  v8::Handle<v8::Object> global = context->Global();
12768 
12769  v8::Handle<v8::String> some_property = v8::String::New("a");
12770  CHECK_EQ(0, force_set_set_count);
12771  CHECK_EQ(0, force_set_get_count);
12772  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12773  // Setting the property shouldn't override it, just call the setter
12774  // which in this case does nothing.
12775  global->Set(some_property, v8::Int32::New(7));
12776  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12777  CHECK_EQ(1, force_set_set_count);
12778  CHECK_EQ(2, force_set_get_count);
12779  // Getting the property when the interceptor returns an empty handle
12780  // should yield undefined, since the property isn't present on the
12781  // object itself yet.
12782  pass_on_get = true;
12783  CHECK(global->Get(some_property)->IsUndefined());
12784  CHECK_EQ(1, force_set_set_count);
12785  CHECK_EQ(3, force_set_get_count);
12786  // Forcing the property to be set should cause the value to be
12787  // set locally without calling the interceptor.
12788  global->ForceSet(some_property, v8::Int32::New(8));
12789  CHECK_EQ(8, global->Get(some_property)->Int32Value());
12790  CHECK_EQ(1, force_set_set_count);
12791  CHECK_EQ(4, force_set_get_count);
12792  // Reenabling the interceptor should cause it to take precedence over
12793  // the property
12794  pass_on_get = false;
12795  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12796  CHECK_EQ(1, force_set_set_count);
12797  CHECK_EQ(5, force_set_get_count);
12798  // The interceptor should also work for other properties
12799  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12800  CHECK_EQ(1, force_set_set_count);
12801  CHECK_EQ(6, force_set_get_count);
12802 }
12803 
12804 
12805 THREADED_TEST(ForceDelete) {
12806  v8::HandleScope scope;
12808  LocalContext context(NULL, templ);
12809  v8::Handle<v8::Object> global = context->Global();
12810 
12811  // Ordinary properties
12812  v8::Handle<v8::String> simple_property = v8::String::New("p");
12813  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12814  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12815  // This should fail because the property is dont-delete.
12816  CHECK(!global->Delete(simple_property));
12817  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12818  // This should succeed even though the property is dont-delete.
12819  CHECK(global->ForceDelete(simple_property));
12820  CHECK(global->Get(simple_property)->IsUndefined());
12821 }
12822 
12823 
12824 static int force_delete_interceptor_count = 0;
12825 static bool pass_on_delete = false;
12826 
12827 
12828 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12829  v8::Local<v8::String> name,
12830  const v8::AccessorInfo& info) {
12831  force_delete_interceptor_count++;
12832  if (pass_on_delete) {
12833  return v8::Handle<v8::Boolean>();
12834  } else {
12835  return v8::True();
12836  }
12837 }
12838 
12839 
12840 THREADED_TEST(ForceDeleteWithInterceptor) {
12841  force_delete_interceptor_count = 0;
12842  pass_on_delete = false;
12843 
12844  v8::HandleScope scope;
12846  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12847  LocalContext context(NULL, templ);
12848  v8::Handle<v8::Object> global = context->Global();
12849 
12850  v8::Handle<v8::String> some_property = v8::String::New("a");
12851  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12852 
12853  // Deleting a property should get intercepted and nothing should
12854  // happen.
12855  CHECK_EQ(0, force_delete_interceptor_count);
12856  CHECK(global->Delete(some_property));
12857  CHECK_EQ(1, force_delete_interceptor_count);
12858  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12859  // Deleting the property when the interceptor returns an empty
12860  // handle should not delete the property since it is DontDelete.
12861  pass_on_delete = true;
12862  CHECK(!global->Delete(some_property));
12863  CHECK_EQ(2, force_delete_interceptor_count);
12864  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12865  // Forcing the property to be deleted should delete the value
12866  // without calling the interceptor.
12867  CHECK(global->ForceDelete(some_property));
12868  CHECK(global->Get(some_property)->IsUndefined());
12869  CHECK_EQ(2, force_delete_interceptor_count);
12870 }
12871 
12872 
12873 // Make sure that forcing a delete invalidates any IC stubs, so we
12874 // don't read the hole value.
12875 THREADED_TEST(ForceDeleteIC) {
12876  v8::HandleScope scope;
12877  LocalContext context;
12878  // Create a DontDelete variable on the global object.
12879  CompileRun("this.__proto__ = { foo: 'horse' };"
12880  "var foo = 'fish';"
12881  "function f() { return foo.length; }");
12882  // Initialize the IC for foo in f.
12883  CompileRun("for (var i = 0; i < 4; i++) f();");
12884  // Make sure the value of foo is correct before the deletion.
12885  CHECK_EQ(4, CompileRun("f()")->Int32Value());
12886  // Force the deletion of foo.
12887  CHECK(context->Global()->ForceDelete(v8_str("foo")));
12888  // Make sure the value for foo is read from the prototype, and that
12889  // we don't get in trouble with reading the deleted cell value
12890  // sentinel.
12891  CHECK_EQ(5, CompileRun("f()")->Int32Value());
12892 }
12893 
12894 
12895 TEST(InlinedFunctionAcrossContexts) {
12896  i::FLAG_allow_natives_syntax = true;
12897  v8::HandleScope outer_scope;
12900  ctx1->Enter();
12901 
12902  {
12903  v8::HandleScope inner_scope;
12904  CompileRun("var G = 42; function foo() { return G; }");
12905  v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
12906  ctx2->Enter();
12907  ctx2->Global()->Set(v8_str("o"), foo);
12908  v8::Local<v8::Value> res = CompileRun(
12909  "function f() { return o(); }"
12910  "for (var i = 0; i < 10; ++i) f();"
12911  "%OptimizeFunctionOnNextCall(f);"
12912  "f();");
12913  CHECK_EQ(42, res->Int32Value());
12914  ctx2->Exit();
12915  v8::Handle<v8::String> G_property = v8::String::New("G");
12916  CHECK(ctx1->Global()->ForceDelete(G_property));
12917  ctx2->Enter();
12918  ExpectString(
12919  "(function() {"
12920  " try {"
12921  " return f();"
12922  " } catch(e) {"
12923  " return e.toString();"
12924  " }"
12925  " })()",
12926  "ReferenceError: G is not defined");
12927  ctx2->Exit();
12928  ctx1->Exit();
12929  ctx1.Dispose();
12930  }
12931  ctx2.Dispose();
12932 }
12933 
12934 
12938 
12939 
12940 // Check that the call to the callback is initiated in
12941 // calling_context2, the directly calling context is calling_context1
12942 // and the callback itself is in calling_context0.
12943 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12945  CHECK(Context::GetCurrent() == calling_context0);
12946  CHECK(Context::GetCalling() == calling_context1);
12947  CHECK(Context::GetEntered() == calling_context2);
12948  return v8::Integer::New(42);
12949 }
12950 
12951 
12952 THREADED_TEST(GetCallingContext) {
12953  v8::HandleScope scope;
12954 
12955  calling_context0 = Context::New();
12956  calling_context1 = Context::New();
12957  calling_context2 = Context::New();
12958 
12959  // Allow cross-domain access.
12960  Local<String> token = v8_str("<security token>");
12961  calling_context0->SetSecurityToken(token);
12962  calling_context1->SetSecurityToken(token);
12963  calling_context2->SetSecurityToken(token);
12964 
12965  // Create an object with a C++ callback in context0.
12966  calling_context0->Enter();
12967  Local<v8::FunctionTemplate> callback_templ =
12968  v8::FunctionTemplate::New(GetCallingContextCallback);
12969  calling_context0->Global()->Set(v8_str("callback"),
12970  callback_templ->GetFunction());
12971  calling_context0->Exit();
12972 
12973  // Expose context0 in context1 and set up a function that calls the
12974  // callback function.
12975  calling_context1->Enter();
12976  calling_context1->Global()->Set(v8_str("context0"),
12977  calling_context0->Global());
12978  CompileRun("function f() { context0.callback() }");
12979  calling_context1->Exit();
12980 
12981  // Expose context1 in context2 and call the callback function in
12982  // context0 indirectly through f in context1.
12983  calling_context2->Enter();
12984  calling_context2->Global()->Set(v8_str("context1"),
12985  calling_context1->Global());
12986  CompileRun("context1.f()");
12987  calling_context2->Exit();
12988 
12989  // Dispose the contexts to allow them to be garbage collected.
12990  calling_context0.Dispose();
12991  calling_context1.Dispose();
12992  calling_context2.Dispose();
12993  calling_context0.Clear();
12994  calling_context1.Clear();
12995  calling_context2.Clear();
12996 }
12997 
12998 
12999 // Check that a variable declaration with no explicit initialization
13000 // value does shadow an existing property in the prototype chain.
13001 THREADED_TEST(InitGlobalVarInProtoChain) {
13002  i::FLAG_es52_globals = true;
13003  v8::HandleScope scope;
13004  LocalContext context;
13005  // Introduce a variable in the prototype chain.
13006  CompileRun("__proto__.x = 42");
13007  v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13008  CHECK(!result->IsUndefined());
13009  CHECK_EQ(43, result->Int32Value());
13010 }
13011 
13012 
13013 // Regression test for issue 398.
13014 // If a function is added to an object, creating a constant function
13015 // field, and the result is cloned, replacing the constant function on the
13016 // original should not affect the clone.
13017 // See http://code.google.com/p/v8/issues/detail?id=398
13018 THREADED_TEST(ReplaceConstantFunction) {
13019  v8::HandleScope scope;
13020  LocalContext context;
13023  v8::Handle<v8::String> foo_string = v8::String::New("foo");
13024  obj->Set(foo_string, func_templ->GetFunction());
13025  v8::Handle<v8::Object> obj_clone = obj->Clone();
13026  obj_clone->Set(foo_string, v8::String::New("Hello"));
13027  CHECK(!obj->Get(foo_string)->IsUndefined());
13028 }
13029 
13030 
13031 // Regression test for http://crbug.com/16276.
13032 THREADED_TEST(Regress16276) {
13033  v8::HandleScope scope;
13034  LocalContext context;
13035  // Force the IC in f to be a dictionary load IC.
13036  CompileRun("function f(obj) { return obj.x; }\n"
13037  "var obj = { x: { foo: 42 }, y: 87 };\n"
13038  "var x = obj.x;\n"
13039  "delete obj.y;\n"
13040  "for (var i = 0; i < 5; i++) f(obj);");
13041  // Detach the global object to make 'this' refer directly to the
13042  // global object (not the proxy), and make sure that the dictionary
13043  // load IC doesn't mess up loading directly from the global object.
13044  context->DetachGlobal();
13045  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13046 }
13047 
13048 
13049 THREADED_TEST(PixelArray) {
13050  v8::HandleScope scope;
13051  LocalContext context;
13052  const int kElementCount = 260;
13053  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13056  FACTORY->NewExternalArray(kElementCount,
13058  pixel_data));
13059  // Force GC to trigger verification.
13060  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13061  for (int i = 0; i < kElementCount; i++) {
13062  pixels->set(i, i % 256);
13063  }
13064  // Force GC to trigger verification.
13065  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13066  for (int i = 0; i < kElementCount; i++) {
13067  CHECK_EQ(i % 256, pixels->get_scalar(i));
13068  CHECK_EQ(i % 256, pixel_data[i]);
13069  }
13070 
13072  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13073  // Set the elements to be the pixels.
13074  // jsobj->set_elements(*pixels);
13075  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13076  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13077  obj->Set(v8_str("field"), v8::Int32::New(1503));
13078  context->Global()->Set(v8_str("pixels"), obj);
13079  v8::Handle<v8::Value> result = CompileRun("pixels.field");
13080  CHECK_EQ(1503, result->Int32Value());
13081  result = CompileRun("pixels[1]");
13082  CHECK_EQ(1, result->Int32Value());
13083 
13084  result = CompileRun("var sum = 0;"
13085  "for (var i = 0; i < 8; i++) {"
13086  " sum += pixels[i] = pixels[i] = -i;"
13087  "}"
13088  "sum;");
13089  CHECK_EQ(-28, result->Int32Value());
13090 
13091  result = CompileRun("var sum = 0;"
13092  "for (var i = 0; i < 8; i++) {"
13093  " sum += pixels[i] = pixels[i] = 0;"
13094  "}"
13095  "sum;");
13096  CHECK_EQ(0, result->Int32Value());
13097 
13098  result = CompileRun("var sum = 0;"
13099  "for (var i = 0; i < 8; i++) {"
13100  " sum += pixels[i] = pixels[i] = 255;"
13101  "}"
13102  "sum;");
13103  CHECK_EQ(8 * 255, result->Int32Value());
13104 
13105  result = CompileRun("var sum = 0;"
13106  "for (var i = 0; i < 8; i++) {"
13107  " sum += pixels[i] = pixels[i] = 256 + i;"
13108  "}"
13109  "sum;");
13110  CHECK_EQ(2076, result->Int32Value());
13111 
13112  result = CompileRun("var sum = 0;"
13113  "for (var i = 0; i < 8; i++) {"
13114  " sum += pixels[i] = pixels[i] = i;"
13115  "}"
13116  "sum;");
13117  CHECK_EQ(28, result->Int32Value());
13118 
13119  result = CompileRun("var sum = 0;"
13120  "for (var i = 0; i < 8; i++) {"
13121  " sum += pixels[i];"
13122  "}"
13123  "sum;");
13124  CHECK_EQ(28, result->Int32Value());
13125 
13127  i::Handle<i::Object> no_failure;
13128  no_failure =
13129  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13130  ASSERT(!no_failure.is_null());
13131  i::USE(no_failure);
13132  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13133  *value.location() = i::Smi::FromInt(256);
13134  no_failure =
13135  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13136  ASSERT(!no_failure.is_null());
13137  i::USE(no_failure);
13138  CHECK_EQ(255,
13139  i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13140  *value.location() = i::Smi::FromInt(-1);
13141  no_failure =
13142  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13143  ASSERT(!no_failure.is_null());
13144  i::USE(no_failure);
13145  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13146 
13147  result = CompileRun("for (var i = 0; i < 8; i++) {"
13148  " pixels[i] = (i * 65) - 109;"
13149  "}"
13150  "pixels[1] + pixels[6];");
13151  CHECK_EQ(255, result->Int32Value());
13152  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13153  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13154  CHECK_EQ(21,
13155  i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13156  CHECK_EQ(86,
13157  i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13158  CHECK_EQ(151,
13159  i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13160  CHECK_EQ(216,
13161  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13162  CHECK_EQ(255,
13163  i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13164  CHECK_EQ(255,
13165  i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13166  result = CompileRun("var sum = 0;"
13167  "for (var i = 0; i < 8; i++) {"
13168  " sum += pixels[i];"
13169  "}"
13170  "sum;");
13171  CHECK_EQ(984, result->Int32Value());
13172 
13173  result = CompileRun("for (var i = 0; i < 8; i++) {"
13174  " pixels[i] = (i * 1.1);"
13175  "}"
13176  "pixels[1] + pixels[6];");
13177  CHECK_EQ(8, result->Int32Value());
13178  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13179  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13180  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13181  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13182  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13183  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13184  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13185  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13186 
13187  result = CompileRun("for (var i = 0; i < 8; i++) {"
13188  " pixels[7] = undefined;"
13189  "}"
13190  "pixels[7];");
13191  CHECK_EQ(0, result->Int32Value());
13192  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13193 
13194  result = CompileRun("for (var i = 0; i < 8; i++) {"
13195  " pixels[6] = '2.3';"
13196  "}"
13197  "pixels[6];");
13198  CHECK_EQ(2, result->Int32Value());
13199  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13200 
13201  result = CompileRun("for (var i = 0; i < 8; i++) {"
13202  " pixels[5] = NaN;"
13203  "}"
13204  "pixels[5];");
13205  CHECK_EQ(0, result->Int32Value());
13206  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13207 
13208  result = CompileRun("for (var i = 0; i < 8; i++) {"
13209  " pixels[8] = Infinity;"
13210  "}"
13211  "pixels[8];");
13212  CHECK_EQ(255, result->Int32Value());
13213  CHECK_EQ(255,
13214  i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
13215 
13216  result = CompileRun("for (var i = 0; i < 8; i++) {"
13217  " pixels[9] = -Infinity;"
13218  "}"
13219  "pixels[9];");
13220  CHECK_EQ(0, result->Int32Value());
13221  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
13222 
13223  result = CompileRun("pixels[3] = 33;"
13224  "delete pixels[3];"
13225  "pixels[3];");
13226  CHECK_EQ(33, result->Int32Value());
13227 
13228  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13229  "pixels[2] = 12; pixels[3] = 13;"
13230  "pixels.__defineGetter__('2',"
13231  "function() { return 120; });"
13232  "pixels[2];");
13233  CHECK_EQ(12, result->Int32Value());
13234 
13235  result = CompileRun("var js_array = new Array(40);"
13236  "js_array[0] = 77;"
13237  "js_array;");
13238  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13239 
13240  result = CompileRun("pixels[1] = 23;"
13241  "pixels.__proto__ = [];"
13242  "js_array.__proto__ = pixels;"
13243  "js_array.concat(pixels);");
13244  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13245  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13246 
13247  result = CompileRun("pixels[1] = 23;");
13248  CHECK_EQ(23, result->Int32Value());
13249 
13250  // Test for index greater than 255. Regression test for:
13251  // http://code.google.com/p/chromium/issues/detail?id=26337.
13252  result = CompileRun("pixels[256] = 255;");
13253  CHECK_EQ(255, result->Int32Value());
13254  result = CompileRun("var i = 0;"
13255  "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13256  "i");
13257  CHECK_EQ(255, result->Int32Value());
13258 
13259  // Make sure that pixel array ICs recognize when a non-pixel array
13260  // is passed to it.
13261  result = CompileRun("function pa_load(p) {"
13262  " var sum = 0;"
13263  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13264  " return sum;"
13265  "}"
13266  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13267  "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13268  "just_ints = new Object();"
13269  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13270  "for (var i = 0; i < 10; ++i) {"
13271  " result = pa_load(just_ints);"
13272  "}"
13273  "result");
13274  CHECK_EQ(32640, result->Int32Value());
13275 
13276  // Make sure that pixel array ICs recognize out-of-bound accesses.
13277  result = CompileRun("function pa_load(p, start) {"
13278  " var sum = 0;"
13279  " for (var j = start; j < 256; j++) { sum += p[j]; }"
13280  " return sum;"
13281  "}"
13282  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13283  "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13284  "for (var i = 0; i < 10; ++i) {"
13285  " result = pa_load(pixels,-10);"
13286  "}"
13287  "result");
13288  CHECK_EQ(0, result->Int32Value());
13289 
13290  // Make sure that generic ICs properly handles a pixel array.
13291  result = CompileRun("function pa_load(p) {"
13292  " var sum = 0;"
13293  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13294  " return sum;"
13295  "}"
13296  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13297  "just_ints = new Object();"
13298  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13299  "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13300  "for (var i = 0; i < 10; ++i) {"
13301  " result = pa_load(pixels);"
13302  "}"
13303  "result");
13304  CHECK_EQ(32640, result->Int32Value());
13305 
13306  // Make sure that generic load ICs recognize out-of-bound accesses in
13307  // pixel arrays.
13308  result = CompileRun("function pa_load(p, start) {"
13309  " var sum = 0;"
13310  " for (var j = start; j < 256; j++) { sum += p[j]; }"
13311  " return sum;"
13312  "}"
13313  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13314  "just_ints = new Object();"
13315  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13316  "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13317  "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13318  "for (var i = 0; i < 10; ++i) {"
13319  " result = pa_load(pixels,-10);"
13320  "}"
13321  "result");
13322  CHECK_EQ(0, result->Int32Value());
13323 
13324  // Make sure that generic ICs properly handles other types than pixel
13325  // arrays (that the inlined fast pixel array test leaves the right information
13326  // in the right registers).
13327  result = CompileRun("function pa_load(p) {"
13328  " var sum = 0;"
13329  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13330  " return sum;"
13331  "}"
13332  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13333  "just_ints = new Object();"
13334  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13335  "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13336  "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13337  "sparse_array = new Object();"
13338  "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13339  "sparse_array[1000000] = 3;"
13340  "for (var i = 0; i < 10; ++i) {"
13341  " result = pa_load(sparse_array);"
13342  "}"
13343  "result");
13344  CHECK_EQ(32640, result->Int32Value());
13345 
13346  // Make sure that pixel array store ICs clamp values correctly.
13347  result = CompileRun("function pa_store(p) {"
13348  " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13349  "}"
13350  "pa_store(pixels);"
13351  "var sum = 0;"
13352  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13353  "sum");
13354  CHECK_EQ(48896, result->Int32Value());
13355 
13356  // Make sure that pixel array stores correctly handle accesses outside
13357  // of the pixel array..
13358  result = CompileRun("function pa_store(p,start) {"
13359  " for (var j = 0; j < 256; j++) {"
13360  " p[j+start] = j * 2;"
13361  " }"
13362  "}"
13363  "pa_store(pixels,0);"
13364  "pa_store(pixels,-128);"
13365  "var sum = 0;"
13366  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13367  "sum");
13368  CHECK_EQ(65280, result->Int32Value());
13369 
13370  // Make sure that the generic store stub correctly handle accesses outside
13371  // of the pixel array..
13372  result = CompileRun("function pa_store(p,start) {"
13373  " for (var j = 0; j < 256; j++) {"
13374  " p[j+start] = j * 2;"
13375  " }"
13376  "}"
13377  "pa_store(pixels,0);"
13378  "just_ints = new Object();"
13379  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13380  "pa_store(just_ints, 0);"
13381  "pa_store(pixels,-128);"
13382  "var sum = 0;"
13383  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13384  "sum");
13385  CHECK_EQ(65280, result->Int32Value());
13386 
13387  // Make sure that the generic keyed store stub clamps pixel array values
13388  // correctly.
13389  result = CompileRun("function pa_store(p) {"
13390  " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13391  "}"
13392  "pa_store(pixels);"
13393  "just_ints = new Object();"
13394  "pa_store(just_ints);"
13395  "pa_store(pixels);"
13396  "var sum = 0;"
13397  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13398  "sum");
13399  CHECK_EQ(48896, result->Int32Value());
13400 
13401  // Make sure that pixel array loads are optimized by crankshaft.
13402  result = CompileRun("function pa_load(p) {"
13403  " var sum = 0;"
13404  " for (var i=0; i<256; ++i) {"
13405  " sum += p[i];"
13406  " }"
13407  " return sum; "
13408  "}"
13409  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13410  "for (var i = 0; i < 5000; ++i) {"
13411  " result = pa_load(pixels);"
13412  "}"
13413  "result");
13414  CHECK_EQ(32640, result->Int32Value());
13415 
13416  // Make sure that pixel array stores are optimized by crankshaft.
13417  result = CompileRun("function pa_init(p) {"
13418  "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13419  "}"
13420  "function pa_load(p) {"
13421  " var sum = 0;"
13422  " for (var i=0; i<256; ++i) {"
13423  " sum += p[i];"
13424  " }"
13425  " return sum; "
13426  "}"
13427  "for (var i = 0; i < 5000; ++i) {"
13428  " pa_init(pixels);"
13429  "}"
13430  "result = pa_load(pixels);"
13431  "result");
13432  CHECK_EQ(32640, result->Int32Value());
13433 
13434  free(pixel_data);
13435 }
13436 
13437 
13438 THREADED_TEST(PixelArrayInfo) {
13439  v8::HandleScope scope;
13440  LocalContext context;
13441  for (int size = 0; size < 100; size += 10) {
13442  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13444  obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13446  CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13448  free(pixel_data);
13449  }
13450 }
13451 
13452 
13453 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13454  uint32_t index,
13455  const AccessorInfo& info) {
13457  return v8::Handle<Value>();
13458 }
13459 
13460 
13461 static v8::Handle<Value> NotHandledIndexedPropertySetter(
13462  uint32_t index,
13463  Local<Value> value,
13464  const AccessorInfo& info) {
13466  return v8::Handle<Value>();
13467 }
13468 
13469 
13470 THREADED_TEST(PixelArrayWithInterceptor) {
13471  v8::HandleScope scope;
13472  LocalContext context;
13473  const int kElementCount = 260;
13474  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13477  FACTORY->NewExternalArray(kElementCount,
13479  pixel_data));
13480  for (int i = 0; i < kElementCount; i++) {
13481  pixels->set(i, i % 256);
13482  }
13484  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13485  NotHandledIndexedPropertySetter);
13486  v8::Handle<v8::Object> obj = templ->NewInstance();
13487  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13488  context->Global()->Set(v8_str("pixels"), obj);
13489  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13490  CHECK_EQ(1, result->Int32Value());
13491  result = CompileRun("var sum = 0;"
13492  "for (var i = 0; i < 8; i++) {"
13493  " sum += pixels[i] = pixels[i] = -i;"
13494  "}"
13495  "sum;");
13496  CHECK_EQ(-28, result->Int32Value());
13497  result = CompileRun("pixels.hasOwnProperty('1')");
13498  CHECK(result->BooleanValue());
13499  free(pixel_data);
13500 }
13501 
13502 
13503 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13504  switch (array_type) {
13508  return 1;
13509  break;
13512  return 2;
13513  break;
13514  case v8::kExternalIntArray:
13517  return 4;
13518  break;
13520  return 8;
13521  break;
13522  default:
13523  UNREACHABLE();
13524  return -1;
13525  }
13526  UNREACHABLE();
13527  return -1;
13528 }
13529 
13530 
13531 template <class ExternalArrayClass, class ElementType>
13532 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13533  int64_t low,
13534  int64_t high) {
13535  v8::HandleScope scope;
13536  LocalContext context;
13537  const int kElementCount = 40;
13538  int element_size = ExternalArrayElementSize(array_type);
13539  ElementType* array_data =
13540  static_cast<ElementType*>(malloc(kElementCount * element_size));
13543  FACTORY->NewExternalArray(kElementCount, array_type, array_data));
13544  // Force GC to trigger verification.
13545  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13546  for (int i = 0; i < kElementCount; i++) {
13547  array->set(i, static_cast<ElementType>(i));
13548  }
13549  // Force GC to trigger verification.
13550  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13551  for (int i = 0; i < kElementCount; i++) {
13552  CHECK_EQ(static_cast<int64_t>(i),
13553  static_cast<int64_t>(array->get_scalar(i)));
13554  CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13555  }
13556 
13558  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13559  // Set the elements to be the external array.
13561  array_type,
13562  kElementCount);
13563  CHECK_EQ(
13564  1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
13565  obj->Set(v8_str("field"), v8::Int32::New(1503));
13566  context->Global()->Set(v8_str("ext_array"), obj);
13567  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13568  CHECK_EQ(1503, result->Int32Value());
13569  result = CompileRun("ext_array[1]");
13570  CHECK_EQ(1, result->Int32Value());
13571 
13572  // Check pass through of assigned smis
13573  result = CompileRun("var sum = 0;"
13574  "for (var i = 0; i < 8; i++) {"
13575  " sum += ext_array[i] = ext_array[i] = -i;"
13576  "}"
13577  "sum;");
13578  CHECK_EQ(-28, result->Int32Value());
13579 
13580  // Check assigned smis
13581  result = CompileRun("for (var i = 0; i < 8; i++) {"
13582  " ext_array[i] = i;"
13583  "}"
13584  "var sum = 0;"
13585  "for (var i = 0; i < 8; i++) {"
13586  " sum += ext_array[i];"
13587  "}"
13588  "sum;");
13589  CHECK_EQ(28, result->Int32Value());
13590 
13591  // Check assigned smis in reverse order
13592  result = CompileRun("for (var i = 8; --i >= 0; ) {"
13593  " ext_array[i] = i;"
13594  "}"
13595  "var sum = 0;"
13596  "for (var i = 0; i < 8; i++) {"
13597  " sum += ext_array[i];"
13598  "}"
13599  "sum;");
13600  CHECK_EQ(28, result->Int32Value());
13601 
13602  // Check pass through of assigned HeapNumbers
13603  result = CompileRun("var sum = 0;"
13604  "for (var i = 0; i < 16; i+=2) {"
13605  " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13606  "}"
13607  "sum;");
13608  CHECK_EQ(-28, result->Int32Value());
13609 
13610  // Check assigned HeapNumbers
13611  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13612  " ext_array[i] = (i * 0.5);"
13613  "}"
13614  "var sum = 0;"
13615  "for (var i = 0; i < 16; i+=2) {"
13616  " sum += ext_array[i];"
13617  "}"
13618  "sum;");
13619  CHECK_EQ(28, result->Int32Value());
13620 
13621  // Check assigned HeapNumbers in reverse order
13622  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13623  " ext_array[i] = (i * 0.5);"
13624  "}"
13625  "var sum = 0;"
13626  "for (var i = 0; i < 16; i+=2) {"
13627  " sum += ext_array[i];"
13628  "}"
13629  "sum;");
13630  CHECK_EQ(28, result->Int32Value());
13631 
13632  i::ScopedVector<char> test_buf(1024);
13633 
13634  // Check legal boundary conditions.
13635  // The repeated loads and stores ensure the ICs are exercised.
13636  const char* boundary_program =
13637  "var res = 0;"
13638  "for (var i = 0; i < 16; i++) {"
13639  " ext_array[i] = %lld;"
13640  " if (i > 8) {"
13641  " res = ext_array[i];"
13642  " }"
13643  "}"
13644  "res;";
13645  i::OS::SNPrintF(test_buf,
13646  boundary_program,
13647  low);
13648  result = CompileRun(test_buf.start());
13649  CHECK_EQ(low, result->IntegerValue());
13650 
13651  i::OS::SNPrintF(test_buf,
13652  boundary_program,
13653  high);
13654  result = CompileRun(test_buf.start());
13655  CHECK_EQ(high, result->IntegerValue());
13656 
13657  // Check misprediction of type in IC.
13658  result = CompileRun("var tmp_array = ext_array;"
13659  "var sum = 0;"
13660  "for (var i = 0; i < 8; i++) {"
13661  " tmp_array[i] = i;"
13662  " sum += tmp_array[i];"
13663  " if (i == 4) {"
13664  " tmp_array = {};"
13665  " }"
13666  "}"
13667  "sum;");
13668  // Force GC to trigger verification.
13669  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13670  CHECK_EQ(28, result->Int32Value());
13671 
13672  // Make sure out-of-range loads do not throw.
13673  i::OS::SNPrintF(test_buf,
13674  "var caught_exception = false;"
13675  "try {"
13676  " ext_array[%d];"
13677  "} catch (e) {"
13678  " caught_exception = true;"
13679  "}"
13680  "caught_exception;",
13681  kElementCount);
13682  result = CompileRun(test_buf.start());
13683  CHECK_EQ(false, result->BooleanValue());
13684 
13685  // Make sure out-of-range stores do not throw.
13686  i::OS::SNPrintF(test_buf,
13687  "var caught_exception = false;"
13688  "try {"
13689  " ext_array[%d] = 1;"
13690  "} catch (e) {"
13691  " caught_exception = true;"
13692  "}"
13693  "caught_exception;",
13694  kElementCount);
13695  result = CompileRun(test_buf.start());
13696  CHECK_EQ(false, result->BooleanValue());
13697 
13698  // Check other boundary conditions, values and operations.
13699  result = CompileRun("for (var i = 0; i < 8; i++) {"
13700  " ext_array[7] = undefined;"
13701  "}"
13702  "ext_array[7];");
13703  CHECK_EQ(0, result->Int32Value());
13704  if (array_type == v8::kExternalDoubleArray ||
13705  array_type == v8::kExternalFloatArray) {
13706  CHECK_EQ(
13707  static_cast<int>(i::OS::nan_value()),
13708  static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13709  } else {
13710  CHECK_EQ(0, static_cast<int>(
13711  jsobj->GetElement(7)->ToObjectChecked()->Number()));
13712  }
13713 
13714  result = CompileRun("for (var i = 0; i < 8; i++) {"
13715  " ext_array[6] = '2.3';"
13716  "}"
13717  "ext_array[6];");
13718  CHECK_EQ(2, result->Int32Value());
13719  CHECK_EQ(
13720  2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
13721 
13722  if (array_type != v8::kExternalFloatArray &&
13723  array_type != v8::kExternalDoubleArray) {
13724  // Though the specification doesn't state it, be explicit about
13725  // converting NaNs and +/-Infinity to zero.
13726  result = CompileRun("for (var i = 0; i < 8; i++) {"
13727  " ext_array[i] = 5;"
13728  "}"
13729  "for (var i = 0; i < 8; i++) {"
13730  " ext_array[i] = NaN;"
13731  "}"
13732  "ext_array[5];");
13733  CHECK_EQ(0, result->Int32Value());
13734  CHECK_EQ(0,
13735  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13736 
13737  result = CompileRun("for (var i = 0; i < 8; i++) {"
13738  " ext_array[i] = 5;"
13739  "}"
13740  "for (var i = 0; i < 8; i++) {"
13741  " ext_array[i] = Infinity;"
13742  "}"
13743  "ext_array[5];");
13744  int expected_value =
13745  (array_type == v8::kExternalPixelArray) ? 255 : 0;
13746  CHECK_EQ(expected_value, result->Int32Value());
13747  CHECK_EQ(expected_value,
13748  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13749 
13750  result = CompileRun("for (var i = 0; i < 8; i++) {"
13751  " ext_array[i] = 5;"
13752  "}"
13753  "for (var i = 0; i < 8; i++) {"
13754  " ext_array[i] = -Infinity;"
13755  "}"
13756  "ext_array[5];");
13757  CHECK_EQ(0, result->Int32Value());
13758  CHECK_EQ(0,
13759  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13760 
13761  // Check truncation behavior of integral arrays.
13762  const char* unsigned_data =
13763  "var source_data = [0.6, 10.6];"
13764  "var expected_results = [0, 10];";
13765  const char* signed_data =
13766  "var source_data = [0.6, 10.6, -0.6, -10.6];"
13767  "var expected_results = [0, 10, 0, -10];";
13768  const char* pixel_data =
13769  "var source_data = [0.6, 10.6];"
13770  "var expected_results = [1, 11];";
13771  bool is_unsigned =
13772  (array_type == v8::kExternalUnsignedByteArray ||
13773  array_type == v8::kExternalUnsignedShortArray ||
13774  array_type == v8::kExternalUnsignedIntArray);
13775  bool is_pixel_data = array_type == v8::kExternalPixelArray;
13776 
13777  i::OS::SNPrintF(test_buf,
13778  "%s"
13779  "var all_passed = true;"
13780  "for (var i = 0; i < source_data.length; i++) {"
13781  " for (var j = 0; j < 8; j++) {"
13782  " ext_array[j] = source_data[i];"
13783  " }"
13784  " all_passed = all_passed &&"
13785  " (ext_array[5] == expected_results[i]);"
13786  "}"
13787  "all_passed;",
13788  (is_unsigned ?
13789  unsigned_data :
13790  (is_pixel_data ? pixel_data : signed_data)));
13791  result = CompileRun(test_buf.start());
13792  CHECK_EQ(true, result->BooleanValue());
13793  }
13794 
13795  for (int i = 0; i < kElementCount; i++) {
13796  array->set(i, static_cast<ElementType>(i));
13797  }
13798  // Test complex assignments
13799  result = CompileRun("function ee_op_test_complex_func(sum) {"
13800  " for (var i = 0; i < 40; ++i) {"
13801  " sum += (ext_array[i] += 1);"
13802  " sum += (ext_array[i] -= 1);"
13803  " } "
13804  " return sum;"
13805  "}"
13806  "sum=0;"
13807  "for (var i=0;i<10000;++i) {"
13808  " sum=ee_op_test_complex_func(sum);"
13809  "}"
13810  "sum;");
13811  CHECK_EQ(16000000, result->Int32Value());
13812 
13813  // Test count operations
13814  result = CompileRun("function ee_op_test_count_func(sum) {"
13815  " for (var i = 0; i < 40; ++i) {"
13816  " sum += (++ext_array[i]);"
13817  " sum += (--ext_array[i]);"
13818  " } "
13819  " return sum;"
13820  "}"
13821  "sum=0;"
13822  "for (var i=0;i<10000;++i) {"
13823  " sum=ee_op_test_count_func(sum);"
13824  "}"
13825  "sum;");
13826  CHECK_EQ(16000000, result->Int32Value());
13827 
13828  result = CompileRun("ext_array[3] = 33;"
13829  "delete ext_array[3];"
13830  "ext_array[3];");
13831  CHECK_EQ(33, result->Int32Value());
13832 
13833  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13834  "ext_array[2] = 12; ext_array[3] = 13;"
13835  "ext_array.__defineGetter__('2',"
13836  "function() { return 120; });"
13837  "ext_array[2];");
13838  CHECK_EQ(12, result->Int32Value());
13839 
13840  result = CompileRun("var js_array = new Array(40);"
13841  "js_array[0] = 77;"
13842  "js_array;");
13843  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13844 
13845  result = CompileRun("ext_array[1] = 23;"
13846  "ext_array.__proto__ = [];"
13847  "js_array.__proto__ = ext_array;"
13848  "js_array.concat(ext_array);");
13849  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13850  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13851 
13852  result = CompileRun("ext_array[1] = 23;");
13853  CHECK_EQ(23, result->Int32Value());
13854 
13855  // Test more complex manipulations which cause eax to contain values
13856  // that won't be completely overwritten by loads from the arrays.
13857  // This catches bugs in the instructions used for the KeyedLoadIC
13858  // for byte and word types.
13859  {
13860  const int kXSize = 300;
13861  const int kYSize = 300;
13862  const int kLargeElementCount = kXSize * kYSize * 4;
13863  ElementType* large_array_data =
13864  static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
13866  // Set the elements to be the external array.
13867  large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13868  array_type,
13869  kLargeElementCount);
13870  context->Global()->Set(v8_str("large_array"), large_obj);
13871  // Initialize contents of a few rows.
13872  for (int x = 0; x < 300; x++) {
13873  int row = 0;
13874  int offset = row * 300 * 4;
13875  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13876  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13877  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13878  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13879  row = 150;
13880  offset = row * 300 * 4;
13881  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13882  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13883  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13884  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13885  row = 298;
13886  offset = row * 300 * 4;
13887  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13888  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13889  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13890  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13891  }
13892  // The goal of the code below is to make "offset" large enough
13893  // that the computation of the index (which goes into eax) has
13894  // high bits set which will not be overwritten by a byte or short
13895  // load.
13896  result = CompileRun("var failed = false;"
13897  "var offset = 0;"
13898  "for (var i = 0; i < 300; i++) {"
13899  " if (large_array[4 * i] != 127 ||"
13900  " large_array[4 * i + 1] != 0 ||"
13901  " large_array[4 * i + 2] != 0 ||"
13902  " large_array[4 * i + 3] != 127) {"
13903  " failed = true;"
13904  " }"
13905  "}"
13906  "offset = 150 * 300 * 4;"
13907  "for (var i = 0; i < 300; i++) {"
13908  " if (large_array[offset + 4 * i] != 127 ||"
13909  " large_array[offset + 4 * i + 1] != 0 ||"
13910  " large_array[offset + 4 * i + 2] != 0 ||"
13911  " large_array[offset + 4 * i + 3] != 127) {"
13912  " failed = true;"
13913  " }"
13914  "}"
13915  "offset = 298 * 300 * 4;"
13916  "for (var i = 0; i < 300; i++) {"
13917  " if (large_array[offset + 4 * i] != 127 ||"
13918  " large_array[offset + 4 * i + 1] != 0 ||"
13919  " large_array[offset + 4 * i + 2] != 0 ||"
13920  " large_array[offset + 4 * i + 3] != 127) {"
13921  " failed = true;"
13922  " }"
13923  "}"
13924  "!failed;");
13925  CHECK_EQ(true, result->BooleanValue());
13926  free(large_array_data);
13927  }
13928 
13929  // The "" property descriptor is overloaded to store information about
13930  // the external array. Ensure that setting and accessing the "" property
13931  // works (it should overwrite the information cached about the external
13932  // array in the DescriptorArray) in various situations.
13933  result = CompileRun("ext_array[''] = 23; ext_array['']");
13934  CHECK_EQ(23, result->Int32Value());
13935 
13936  // Property "" set after the external array is associated with the object.
13937  {
13939  obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13940  obj2->Set(v8_str(""), v8::Int32::New(1503));
13941  // Set the elements to be the external array.
13942  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13943  array_type,
13944  kElementCount);
13945  context->Global()->Set(v8_str("ext_array"), obj2);
13946  result = CompileRun("ext_array['']");
13947  CHECK_EQ(1503, result->Int32Value());
13948  }
13949 
13950  // Property "" set after the external array is associated with the object.
13951  {
13953  obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13954  // Set the elements to be the external array.
13955  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13956  array_type,
13957  kElementCount);
13958  obj2->Set(v8_str(""), v8::Int32::New(1503));
13959  context->Global()->Set(v8_str("ext_array"), obj2);
13960  result = CompileRun("ext_array['']");
13961  CHECK_EQ(1503, result->Int32Value());
13962  }
13963 
13964  // Should reuse the map from previous test.
13965  {
13967  obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13968  // Set the elements to be the external array. Should re-use the map
13969  // from previous test.
13970  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13971  array_type,
13972  kElementCount);
13973  context->Global()->Set(v8_str("ext_array"), obj2);
13974  result = CompileRun("ext_array['']");
13975  }
13976 
13977  // Property "" is a constant function that shouldn't not be interfered with
13978  // when an external array is set.
13979  {
13981  // Start
13982  obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13983 
13984  // Add a constant function to an object.
13985  context->Global()->Set(v8_str("ext_array"), obj2);
13986  result = CompileRun("ext_array[''] = function() {return 1503;};"
13987  "ext_array['']();");
13988 
13989  // Add an external array transition to the same map that
13990  // has the constant transition.
13992  obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13993  obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13994  array_type,
13995  kElementCount);
13996  context->Global()->Set(v8_str("ext_array"), obj3);
13997  }
13998 
13999  // If a external array transition is in the map, it should get clobbered
14000  // by a constant function.
14001  {
14002  // Add an external array transition.
14004  obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14005  obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14006  array_type,
14007  kElementCount);
14008 
14009  // Add a constant function to the same map that just got an external array
14010  // transition.
14012  obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14013  context->Global()->Set(v8_str("ext_array"), obj2);
14014  result = CompileRun("ext_array[''] = function() {return 1503;};"
14015  "ext_array['']();");
14016  }
14017 
14018  free(array_data);
14019 }
14020 
14021 
14022 THREADED_TEST(ExternalByteArray) {
14023  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
14025  -128,
14026  127);
14027 }
14028 
14029 
14030 THREADED_TEST(ExternalUnsignedByteArray) {
14031  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
14033  0,
14034  255);
14035 }
14036 
14037 
14038 THREADED_TEST(ExternalPixelArray) {
14039  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14041  0,
14042  255);
14043 }
14044 
14045 
14046 THREADED_TEST(ExternalShortArray) {
14047  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
14049  -32768,
14050  32767);
14051 }
14052 
14053 
14054 THREADED_TEST(ExternalUnsignedShortArray) {
14055  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
14057  0,
14058  65535);
14059 }
14060 
14061 
14062 THREADED_TEST(ExternalIntArray) {
14063  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
14065  INT_MIN, // -2147483648
14066  INT_MAX); // 2147483647
14067 }
14068 
14069 
14070 THREADED_TEST(ExternalUnsignedIntArray) {
14071  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
14073  0,
14074  UINT_MAX); // 4294967295
14075 }
14076 
14077 
14078 THREADED_TEST(ExternalFloatArray) {
14079  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
14081  -500,
14082  500);
14083 }
14084 
14085 
14086 THREADED_TEST(ExternalDoubleArray) {
14087  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14089  -500,
14090  500);
14091 }
14092 
14093 
14094 THREADED_TEST(ExternalArrays) {
14095  TestExternalByteArray();
14096  TestExternalUnsignedByteArray();
14097  TestExternalShortArray();
14098  TestExternalUnsignedShortArray();
14099  TestExternalIntArray();
14100  TestExternalUnsignedIntArray();
14101  TestExternalFloatArray();
14102 }
14103 
14104 
14106  v8::HandleScope scope;
14107  LocalContext context;
14108  for (int size = 0; size < 100; size += 10) {
14109  int element_size = ExternalArrayElementSize(array_type);
14110  void* external_data = malloc(size * element_size);
14113  external_data, array_type, size);
14115  CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14118  free(external_data);
14119  }
14120 }
14121 
14122 
14123 THREADED_TEST(ExternalArrayInfo) {
14133 }
14134 
14135 
14139  last_location = last_message = NULL;
14140  obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14142  CHECK_NE(NULL, last_location);
14143  CHECK_NE(NULL, last_message);
14144 }
14145 
14146 
14147 TEST(ExternalArrayLimits) {
14148  v8::HandleScope scope;
14149  LocalContext context;
14168 }
14169 
14170 
14171 THREADED_TEST(ScriptContextDependence) {
14172  v8::HandleScope scope;
14173  LocalContext c1;
14174  const char *source = "foo";
14177  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14178  CHECK_EQ(dep->Run()->Int32Value(), 100);
14179  CHECK_EQ(indep->Run()->Int32Value(), 100);
14180  LocalContext c2;
14181  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14182  CHECK_EQ(dep->Run()->Int32Value(), 100);
14183  CHECK_EQ(indep->Run()->Int32Value(), 101);
14184 }
14185 
14186 
14187 THREADED_TEST(StackTrace) {
14188  v8::HandleScope scope;
14189  LocalContext context;
14190  v8::TryCatch try_catch;
14191  const char *source = "function foo() { FAIL.FAIL; }; foo();";
14193  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14194  v8::Script::New(src, origin)->Run();
14195  CHECK(try_catch.HasCaught());
14196  v8::String::Utf8Value stack(try_catch.StackTrace());
14197  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14198 }
14199 
14200 
14201 // Checks that a StackFrame has certain expected values.
14202 void checkStackFrame(const char* expected_script_name,
14203  const char* expected_func_name, int expected_line_number,
14204  int expected_column, bool is_eval, bool is_constructor,
14206  v8::HandleScope scope;
14207  v8::String::Utf8Value func_name(frame->GetFunctionName());
14208  v8::String::Utf8Value script_name(frame->GetScriptName());
14209  if (*script_name == NULL) {
14210  // The situation where there is no associated script, like for evals.
14211  CHECK(expected_script_name == NULL);
14212  } else {
14213  CHECK(strstr(*script_name, expected_script_name) != NULL);
14214  }
14215  CHECK(strstr(*func_name, expected_func_name) != NULL);
14216  CHECK_EQ(expected_line_number, frame->GetLineNumber());
14217  CHECK_EQ(expected_column, frame->GetColumn());
14218  CHECK_EQ(is_eval, frame->IsEval());
14219  CHECK_EQ(is_constructor, frame->IsConstructor());
14220 }
14221 
14222 
14224  v8::HandleScope scope;
14225  const char* origin = "capture-stack-trace-test";
14226  const int kOverviewTest = 1;
14227  const int kDetailedTest = 2;
14228 
14229  ASSERT(args.Length() == 1);
14230 
14231  int testGroup = args[0]->Int32Value();
14232  if (testGroup == kOverviewTest) {
14233  v8::Handle<v8::StackTrace> stackTrace =
14235  CHECK_EQ(4, stackTrace->GetFrameCount());
14236  checkStackFrame(origin, "bar", 2, 10, false, false,
14237  stackTrace->GetFrame(0));
14238  checkStackFrame(origin, "foo", 6, 3, false, false,
14239  stackTrace->GetFrame(1));
14240  // This is the source string inside the eval which has the call to foo.
14241  checkStackFrame(NULL, "", 1, 5, false, false,
14242  stackTrace->GetFrame(2));
14243  // The last frame is an anonymous function which has the initial eval call.
14244  checkStackFrame(origin, "", 8, 7, false, false,
14245  stackTrace->GetFrame(3));
14246 
14247  CHECK(stackTrace->AsArray()->IsArray());
14248  } else if (testGroup == kDetailedTest) {
14249  v8::Handle<v8::StackTrace> stackTrace =
14251  CHECK_EQ(4, stackTrace->GetFrameCount());
14252  checkStackFrame(origin, "bat", 4, 22, false, false,
14253  stackTrace->GetFrame(0));
14254  checkStackFrame(origin, "baz", 8, 3, false, true,
14255  stackTrace->GetFrame(1));
14256 #ifdef ENABLE_DEBUGGER_SUPPORT
14257  bool is_eval = true;
14258 #else // ENABLE_DEBUGGER_SUPPORT
14259  bool is_eval = false;
14260 #endif // ENABLE_DEBUGGER_SUPPORT
14261 
14262  // This is the source string inside the eval which has the call to baz.
14263  checkStackFrame(NULL, "", 1, 5, is_eval, false,
14264  stackTrace->GetFrame(2));
14265  // The last frame is an anonymous function which has the initial eval call.
14266  checkStackFrame(origin, "", 10, 1, false, false,
14267  stackTrace->GetFrame(3));
14268 
14269  CHECK(stackTrace->AsArray()->IsArray());
14270  }
14271  return v8::Undefined();
14272 }
14273 
14274 
14275 // Tests the C++ StackTrace API.
14276 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14277 // THREADED_TEST(CaptureStackTrace) {
14278 TEST(CaptureStackTrace) {
14279  v8::HandleScope scope;
14280  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14281  Local<ObjectTemplate> templ = ObjectTemplate::New();
14282  templ->Set(v8_str("AnalyzeStackInNativeCode"),
14284  LocalContext context(0, templ);
14285 
14286  // Test getting OVERVIEW information. Should ignore information that is not
14287  // script name, function name, line number, and column offset.
14288  const char *overview_source =
14289  "function bar() {\n"
14290  " var y; AnalyzeStackInNativeCode(1);\n"
14291  "}\n"
14292  "function foo() {\n"
14293  "\n"
14294  " bar();\n"
14295  "}\n"
14296  "var x;eval('new foo();');";
14297  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
14298  v8::Handle<Value> overview_result(
14299  v8::Script::New(overview_src, origin)->Run());
14300  CHECK(!overview_result.IsEmpty());
14301  CHECK(overview_result->IsObject());
14302 
14303  // Test getting DETAILED information.
14304  const char *detailed_source =
14305  "function bat() {AnalyzeStackInNativeCode(2);\n"
14306  "}\n"
14307  "\n"
14308  "function baz() {\n"
14309  " bat();\n"
14310  "}\n"
14311  "eval('new baz();');";
14312  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14313  // Make the script using a non-zero line and column offset.
14314  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14315  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14316  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14317  v8::Handle<v8::Script> detailed_script(
14318  v8::Script::New(detailed_src, &detailed_origin));
14319  v8::Handle<Value> detailed_result(detailed_script->Run());
14320  CHECK(!detailed_result.IsEmpty());
14321  CHECK(detailed_result->IsObject());
14322 }
14323 
14324 
14325 static void StackTraceForUncaughtExceptionListener(
14326  v8::Handle<v8::Message> message,
14328  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14329  CHECK_EQ(2, stack_trace->GetFrameCount());
14330  checkStackFrame("origin", "foo", 2, 3, false, false,
14331  stack_trace->GetFrame(0));
14332  checkStackFrame("origin", "bar", 5, 3, false, false,
14333  stack_trace->GetFrame(1));
14334 }
14335 
14336 TEST(CaptureStackTraceForUncaughtException) {
14337  report_count = 0;
14338  v8::HandleScope scope;
14339  LocalContext env;
14340  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14342 
14343  Script::Compile(v8_str("function foo() {\n"
14344  " throw 1;\n"
14345  "};\n"
14346  "function bar() {\n"
14347  " foo();\n"
14348  "};"),
14349  v8_str("origin"))->Run();
14350  v8::Local<v8::Object> global = env->Global();
14351  Local<Value> trouble = global->Get(v8_str("bar"));
14352  CHECK(trouble->IsFunction());
14353  Function::Cast(*trouble)->Call(global, 0, NULL);
14355  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14356 }
14357 
14358 
14359 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14360  v8::HandleScope scope;
14361  LocalContext env;
14363  1024,
14365 
14366  CompileRun(
14367  "var setters = ['column', 'lineNumber', 'scriptName',\n"
14368  " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14369  " 'isConstructor'];\n"
14370  "for (var i = 0; i < setters.length; i++) {\n"
14371  " var prop = setters[i];\n"
14372  " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14373  "}\n");
14374  CompileRun("throw 'exception';");
14376 }
14377 
14378 
14379 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14380  v8::Handle<v8::Value> data) {
14381  // Use the frame where JavaScript is called from.
14382  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14383  CHECK(!stack_trace.IsEmpty());
14384  int frame_count = stack_trace->GetFrameCount();
14385  CHECK_EQ(3, frame_count);
14386  int line_number[] = {1, 2, 5};
14387  for (int i = 0; i < frame_count; i++) {
14388  CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14389  }
14390 }
14391 
14392 
14393 // Test that we only return the stack trace at the site where the exception
14394 // is first thrown (not where it is rethrown).
14395 TEST(RethrowStackTrace) {
14396  v8::HandleScope scope;
14397  LocalContext env;
14398  // We make sure that
14399  // - the stack trace of the ReferenceError in g() is reported.
14400  // - the stack trace is not overwritten when e1 is rethrown by t().
14401  // - the stack trace of e2 does not overwrite that of e1.
14402  const char* source =
14403  "function g() { error; } \n"
14404  "function f() { g(); } \n"
14405  "function t(e) { throw e; } \n"
14406  "try { \n"
14407  " f(); \n"
14408  "} catch (e1) { \n"
14409  " try { \n"
14410  " error; \n"
14411  " } catch (e2) { \n"
14412  " t(e1); \n"
14413  " } \n"
14414  "} \n";
14415  v8::V8::AddMessageListener(RethrowStackTraceHandler);
14417  CompileRun(source);
14419  v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14420 }
14421 
14422 
14423 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14424  v8::Handle<v8::Value> data) {
14425  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14426  CHECK(!stack_trace.IsEmpty());
14427  int frame_count = stack_trace->GetFrameCount();
14428  CHECK_EQ(2, frame_count);
14429  int line_number[] = {3, 7};
14430  for (int i = 0; i < frame_count; i++) {
14431  CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14432  }
14433 }
14434 
14435 
14436 // Test that we do not recognize identity for primitive exceptions.
14437 TEST(RethrowPrimitiveStackTrace) {
14438  v8::HandleScope scope;
14439  LocalContext env;
14440  // We do not capture stack trace for non Error objects on creation time.
14441  // Instead, we capture the stack trace on last throw.
14442  const char* source =
14443  "function g() { throw 404; } \n"
14444  "function f() { g(); } \n"
14445  "function t(e) { throw e; } \n"
14446  "try { \n"
14447  " f(); \n"
14448  "} catch (e1) { \n"
14449  " t(e1) \n"
14450  "} \n";
14451  v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14453  CompileRun(source);
14455  v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14456 }
14457 
14458 
14459 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14460  v8::Handle<v8::Value> data) {
14461  // Use the frame where JavaScript is called from.
14462  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14463  CHECK(!stack_trace.IsEmpty());
14464  CHECK_EQ(1, stack_trace->GetFrameCount());
14465  CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14466 }
14467 
14468 
14469 // Test that the stack trace is captured when the error object is created and
14470 // not where it is thrown.
14471 TEST(RethrowExistingStackTrace) {
14472  v8::HandleScope scope;
14473  LocalContext env;
14474  const char* source =
14475  "var e = new Error(); \n"
14476  "throw e; \n";
14477  v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14479  CompileRun(source);
14481  v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14482 }
14483 
14484 
14485 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14486  v8::Handle<v8::Value> data) {
14487  // Use the frame where JavaScript is called from.
14488  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14489  CHECK(!stack_trace.IsEmpty());
14490  CHECK_EQ(1, stack_trace->GetFrameCount());
14491  CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14492 }
14493 
14494 
14495 // Test that the stack trace is captured where the bogus Error object is thrown.
14496 TEST(RethrowBogusErrorStackTrace) {
14497  v8::HandleScope scope;
14498  LocalContext env;
14499  const char* source =
14500  "var e = {__proto__: new Error()} \n"
14501  "throw e; \n";
14502  v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14504  CompileRun(source);
14506  v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14507 }
14508 
14509 
14511  v8::HandleScope scope;
14512  v8::Handle<v8::StackTrace> stackTrace =
14514  CHECK_EQ(5, stackTrace->GetFrameCount());
14515  v8::Handle<v8::String> url = v8_str("eval_url");
14516  for (int i = 0; i < 3; i++) {
14517  v8::Handle<v8::String> name =
14518  stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14519  CHECK(!name.IsEmpty());
14520  CHECK_EQ(url, name);
14521  }
14522  return v8::Undefined();
14523 }
14524 
14525 
14526 TEST(SourceURLInStackTrace) {
14527  v8::HandleScope scope;
14528  Local<ObjectTemplate> templ = ObjectTemplate::New();
14529  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14531  LocalContext context(0, templ);
14532 
14533  const char *source =
14534  "function outer() {\n"
14535  "function bar() {\n"
14536  " AnalyzeStackOfEvalWithSourceURL();\n"
14537  "}\n"
14538  "function foo() {\n"
14539  "\n"
14540  " bar();\n"
14541  "}\n"
14542  "foo();\n"
14543  "}\n"
14544  "eval('(' + outer +')()//@ sourceURL=eval_url');";
14545  CHECK(CompileRun(source)->IsUndefined());
14546 }
14547 
14548 
14550  const v8::Arguments& args) {
14551  v8::HandleScope scope;
14552  v8::Handle<v8::StackTrace> stackTrace =
14554  CHECK_EQ(4, stackTrace->GetFrameCount());
14555  v8::Handle<v8::String> url = v8_str("url");
14556  for (int i = 0; i < 3; i++) {
14557  v8::Handle<v8::String> name =
14558  stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14559  CHECK(!name.IsEmpty());
14560  CHECK_EQ(url, name);
14561  }
14562  return v8::Undefined();
14563 }
14564 
14565 
14566 TEST(InlineScriptWithSourceURLInStackTrace) {
14567  v8::HandleScope scope;
14568  Local<ObjectTemplate> templ = ObjectTemplate::New();
14569  templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14572  LocalContext context(0, templ);
14573 
14574  const char *source =
14575  "function outer() {\n"
14576  "function bar() {\n"
14577  " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14578  "}\n"
14579  "function foo() {\n"
14580  "\n"
14581  " bar();\n"
14582  "}\n"
14583  "foo();\n"
14584  "}\n"
14585  "outer()\n"
14586  "//@ sourceURL=source_url";
14587  CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14588 }
14589 
14590 
14592  const v8::Arguments& args) {
14593  v8::HandleScope scope;
14594  v8::Handle<v8::StackTrace> stackTrace =
14596  CHECK_EQ(4, stackTrace->GetFrameCount());
14597  v8::Handle<v8::String> url = v8_str("source_url");
14598  for (int i = 0; i < 3; i++) {
14599  v8::Handle<v8::String> name =
14600  stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14601  CHECK(!name.IsEmpty());
14602  CHECK_EQ(url, name);
14603  }
14604  return v8::Undefined();
14605 }
14606 
14607 
14608 TEST(DynamicWithSourceURLInStackTrace) {
14609  v8::HandleScope scope;
14610  Local<ObjectTemplate> templ = ObjectTemplate::New();
14611  templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14614  LocalContext context(0, templ);
14615 
14616  const char *source =
14617  "function outer() {\n"
14618  "function bar() {\n"
14619  " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14620  "}\n"
14621  "function foo() {\n"
14622  "\n"
14623  " bar();\n"
14624  "}\n"
14625  "foo();\n"
14626  "}\n"
14627  "outer()\n"
14628  "//@ sourceURL=source_url";
14629  CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14630 }
14631 
14632 static void CreateGarbageInOldSpace() {
14633  v8::HandleScope scope;
14634  i::AlwaysAllocateScope always_allocate;
14635  for (int i = 0; i < 1000; i++) {
14636  FACTORY->NewFixedArray(1000, i::TENURED);
14637  }
14638 }
14639 
14640 // Test that idle notification can be handled and eventually returns true.
14641 TEST(IdleNotification) {
14642  const intptr_t MB = 1024 * 1024;
14643  v8::HandleScope scope;
14644  LocalContext env;
14645  intptr_t initial_size = HEAP->SizeOfObjects();
14646  CreateGarbageInOldSpace();
14647  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14648  CHECK_GT(size_with_garbage, initial_size + MB);
14649  bool finished = false;
14650  for (int i = 0; i < 200 && !finished; i++) {
14651  finished = v8::V8::IdleNotification();
14652  }
14653  intptr_t final_size = HEAP->SizeOfObjects();
14654  CHECK(finished);
14655  CHECK_LT(final_size, initial_size + 1);
14656 }
14657 
14658 
14659 // Test that idle notification can be handled and eventually collects garbage.
14660 TEST(IdleNotificationWithSmallHint) {
14661  const intptr_t MB = 1024 * 1024;
14662  const int IdlePauseInMs = 900;
14663  v8::HandleScope scope;
14664  LocalContext env;
14665  intptr_t initial_size = HEAP->SizeOfObjects();
14666  CreateGarbageInOldSpace();
14667  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14668  CHECK_GT(size_with_garbage, initial_size + MB);
14669  bool finished = false;
14670  for (int i = 0; i < 200 && !finished; i++) {
14671  finished = v8::V8::IdleNotification(IdlePauseInMs);
14672  }
14673  intptr_t final_size = HEAP->SizeOfObjects();
14674  CHECK(finished);
14675  CHECK_LT(final_size, initial_size + 1);
14676 }
14677 
14678 
14679 // Test that idle notification can be handled and eventually collects garbage.
14680 TEST(IdleNotificationWithLargeHint) {
14681  const intptr_t MB = 1024 * 1024;
14682  const int IdlePauseInMs = 900;
14683  v8::HandleScope scope;
14684  LocalContext env;
14685  intptr_t initial_size = HEAP->SizeOfObjects();
14686  CreateGarbageInOldSpace();
14687  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14688  CHECK_GT(size_with_garbage, initial_size + MB);
14689  bool finished = false;
14690  for (int i = 0; i < 200 && !finished; i++) {
14691  finished = v8::V8::IdleNotification(IdlePauseInMs);
14692  }
14693  intptr_t final_size = HEAP->SizeOfObjects();
14694  CHECK(finished);
14695  CHECK_LT(final_size, initial_size + 1);
14696 }
14697 
14698 
14699 TEST(Regress2107) {
14700  const intptr_t MB = 1024 * 1024;
14701  const int kShortIdlePauseInMs = 100;
14702  const int kLongIdlePauseInMs = 1000;
14703  v8::HandleScope scope;
14704  LocalContext env;
14705  intptr_t initial_size = HEAP->SizeOfObjects();
14706  // Send idle notification to start a round of incremental GCs.
14707  v8::V8::IdleNotification(kShortIdlePauseInMs);
14708  // Emulate 7 page reloads.
14709  for (int i = 0; i < 7; i++) {
14711  ctx->Enter();
14712  CreateGarbageInOldSpace();
14713  ctx->Exit();
14714  ctx.Dispose();
14716  v8::V8::IdleNotification(kLongIdlePauseInMs);
14717  }
14718  // Create garbage and check that idle notification still collects it.
14719  CreateGarbageInOldSpace();
14720  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14721  CHECK_GT(size_with_garbage, initial_size + MB);
14722  bool finished = false;
14723  for (int i = 0; i < 200 && !finished; i++) {
14724  finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14725  }
14726  intptr_t final_size = HEAP->SizeOfObjects();
14727  CHECK_LT(final_size, initial_size + 1);
14728 }
14729 
14730 static uint32_t* stack_limit;
14731 
14732 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
14733  stack_limit = reinterpret_cast<uint32_t*>(
14734  i::Isolate::Current()->stack_guard()->real_climit());
14735  return v8::Undefined();
14736 }
14737 
14738 
14739 // Uses the address of a local variable to determine the stack top now.
14740 // Given a size, returns an address that is that far from the current
14741 // top of stack.
14742 static uint32_t* ComputeStackLimit(uint32_t size) {
14743  uint32_t* answer = &size - (size / sizeof(size));
14744  // If the size is very large and the stack is very near the bottom of
14745  // memory then the calculation above may wrap around and give an address
14746  // that is above the (downwards-growing) stack. In that case we return
14747  // a very low address.
14748  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14749  return answer;
14750 }
14751 
14752 
14754  static const int K = 1024;
14755  uint32_t* set_limit = ComputeStackLimit(128 * K);
14756 
14757  // Set stack limit.
14758  v8::ResourceConstraints constraints;
14759  constraints.set_stack_limit(set_limit);
14760  CHECK(v8::SetResourceConstraints(&constraints));
14761 
14762  // Execute a script.
14763  v8::HandleScope scope;
14764  LocalContext env;
14765  Local<v8::FunctionTemplate> fun_templ =
14766  v8::FunctionTemplate::New(GetStackLimitCallback);
14767  Local<Function> fun = fun_templ->GetFunction();
14768  env->Global()->Set(v8_str("get_stack_limit"), fun);
14769  CompileRun("get_stack_limit();");
14770 
14771  CHECK(stack_limit == set_limit);
14772 }
14773 
14774 
14775 TEST(SetResourceConstraintsInThread) {
14776  uint32_t* set_limit;
14777  {
14778  v8::Locker locker;
14779  static const int K = 1024;
14780  set_limit = ComputeStackLimit(128 * K);
14781 
14782  // Set stack limit.
14783  v8::ResourceConstraints constraints;
14784  constraints.set_stack_limit(set_limit);
14785  CHECK(v8::SetResourceConstraints(&constraints));
14786 
14787  // Execute a script.
14788  v8::HandleScope scope;
14789  LocalContext env;
14790  Local<v8::FunctionTemplate> fun_templ =
14791  v8::FunctionTemplate::New(GetStackLimitCallback);
14792  Local<Function> fun = fun_templ->GetFunction();
14793  env->Global()->Set(v8_str("get_stack_limit"), fun);
14794  CompileRun("get_stack_limit();");
14795 
14796  CHECK(stack_limit == set_limit);
14797  }
14798  {
14799  v8::Locker locker;
14800  CHECK(stack_limit == set_limit);
14801  }
14802 }
14803 
14804 
14805 THREADED_TEST(GetHeapStatistics) {
14806  v8::HandleScope scope;
14807  LocalContext c1;
14808  v8::HeapStatistics heap_statistics;
14809  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14810  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
14811  v8::V8::GetHeapStatistics(&heap_statistics);
14812  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14813  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
14814 }
14815 
14816 
14818  public:
14820  : resource1_(r1),
14821  resource2_(r2),
14822  found_resource1_(false),
14823  found_resource2_(false) {}
14824  virtual ~VisitorImpl() {}
14826  if (!string->IsExternal()) {
14827  CHECK(string->IsExternalAscii());
14828  return;
14829  }
14831  string->GetExternalStringResource();
14832  CHECK(resource);
14833  if (resource1_ == resource) {
14834  CHECK(!found_resource1_);
14835  found_resource1_ = true;
14836  }
14837  if (resource2_ == resource) {
14838  CHECK(!found_resource2_);
14839  found_resource2_ = true;
14840  }
14841  }
14843  CHECK(found_resource1_);
14844  CHECK(found_resource2_);
14845  }
14846 
14847  private:
14850  bool found_resource1_;
14851  bool found_resource2_;
14852 };
14853 
14854 TEST(VisitExternalStrings) {
14855  v8::HandleScope scope;
14856  LocalContext env;
14857  const char* string = "Some string";
14858  uint16_t* two_byte_string = AsciiToTwoByteString(string);
14859  TestResource* resource1 = new TestResource(two_byte_string);
14860  v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
14861  TestResource* resource2 = new TestResource(two_byte_string);
14862  v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
14863 
14864  // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
14865  CHECK(string1->IsExternal());
14866  CHECK(string2->IsExternal());
14867 
14868  VisitorImpl visitor(resource1, resource2);
14870  visitor.CheckVisitedResources();
14871 }
14872 
14873 
14874 static double DoubleFromBits(uint64_t value) {
14875  double target;
14876  memcpy(&target, &value, sizeof(target));
14877  return target;
14878 }
14879 
14880 
14881 static uint64_t DoubleToBits(double value) {
14882  uint64_t target;
14883  memcpy(&target, &value, sizeof(target));
14884  return target;
14885 }
14886 
14887 
14888 static double DoubleToDateTime(double input) {
14889  double date_limit = 864e13;
14890  if (IsNaN(input) || input < -date_limit || input > date_limit) {
14891  return i::OS::nan_value();
14892  }
14893  return (input < 0) ? -(floor(-input)) : floor(input);
14894 }
14895 
14896 // We don't have a consistent way to write 64-bit constants syntactically, so we
14897 // split them into two 32-bit constants and combine them programmatically.
14898 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
14899  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
14900 }
14901 
14902 
14903 THREADED_TEST(QuietSignalingNaNs) {
14904  v8::HandleScope scope;
14905  LocalContext context;
14906  v8::TryCatch try_catch;
14907 
14908  // Special double values.
14909  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
14910  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
14911  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
14912  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
14913  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
14914  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
14915  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
14916 
14917  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
14918  // on either side of the epoch.
14919  double date_limit = 864e13;
14920 
14921  double test_values[] = {
14922  snan,
14923  qnan,
14924  infinity,
14925  max_normal,
14926  date_limit + 1,
14927  date_limit,
14928  min_normal,
14929  max_denormal,
14930  min_denormal,
14931  0,
14932  -0,
14933  -min_denormal,
14934  -max_denormal,
14935  -min_normal,
14936  -date_limit,
14937  -date_limit - 1,
14938  -max_normal,
14939  -infinity,
14940  -qnan,
14941  -snan
14942  };
14943  int num_test_values = 20;
14944 
14945  for (int i = 0; i < num_test_values; i++) {
14946  double test_value = test_values[i];
14947 
14948  // Check that Number::New preserves non-NaNs and quiets SNaNs.
14949  v8::Handle<v8::Value> number = v8::Number::New(test_value);
14950  double stored_number = number->NumberValue();
14951  if (!IsNaN(test_value)) {
14952  CHECK_EQ(test_value, stored_number);
14953  } else {
14954  uint64_t stored_bits = DoubleToBits(stored_number);
14955  // Check if quiet nan (bits 51..62 all set).
14956 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14957  // Most significant fraction bit for quiet nan is set to 0
14958  // on MIPS architecture. Allowed by IEEE-754.
14959  CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14960 #else
14961  CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14962 #endif
14963  }
14964 
14965  // Check that Date::New preserves non-NaNs in the date range and
14966  // quiets SNaNs.
14967  v8::Handle<v8::Value> date = v8::Date::New(test_value);
14968  double expected_stored_date = DoubleToDateTime(test_value);
14969  double stored_date = date->NumberValue();
14970  if (!IsNaN(expected_stored_date)) {
14971  CHECK_EQ(expected_stored_date, stored_date);
14972  } else {
14973  uint64_t stored_bits = DoubleToBits(stored_date);
14974  // Check if quiet nan (bits 51..62 all set).
14975 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14976  // Most significant fraction bit for quiet nan is set to 0
14977  // on MIPS architecture. Allowed by IEEE-754.
14978  CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14979 #else
14980  CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14981 #endif
14982  }
14983  }
14984 }
14985 
14986 
14987 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14988  v8::HandleScope scope;
14989  v8::TryCatch tc;
14990  v8::Handle<v8::String> str(args[0]->ToString());
14991  USE(str);
14992  if (tc.HasCaught())
14993  return tc.ReThrow();
14994  return v8::Undefined();
14995 }
14996 
14997 
14998 // Test that an exception can be propagated down through a spaghetti
14999 // stack using ReThrow.
15000 THREADED_TEST(SpaghettiStackReThrow) {
15001  v8::HandleScope scope;
15002  LocalContext context;
15003  context->Global()->Set(
15004  v8::String::New("s"),
15005  v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15006  v8::TryCatch try_catch;
15007  CompileRun(
15008  "var i = 0;"
15009  "var o = {"
15010  " toString: function () {"
15011  " if (i == 10) {"
15012  " throw 'Hey!';"
15013  " } else {"
15014  " i++;"
15015  " return s(o);"
15016  " }"
15017  " }"
15018  "};"
15019  "s(o);");
15020  CHECK(try_catch.HasCaught());
15021  v8::String::Utf8Value value(try_catch.Exception());
15022  CHECK_EQ(0, strcmp(*value, "Hey!"));
15023 }
15024 
15025 
15026 TEST(Regress528) {
15028 
15029  v8::HandleScope scope;
15030  v8::Persistent<Context> context;
15031  v8::Persistent<Context> other_context;
15032  int gc_count;
15033 
15034  // Create a context used to keep the code from aging in the compilation
15035  // cache.
15036  other_context = Context::New();
15037 
15038  // Context-dependent context data creates reference from the compilation
15039  // cache to the global object.
15040  const char* source_simple = "1";
15041  context = Context::New();
15042  {
15043  v8::HandleScope scope;
15044 
15045  context->Enter();
15046  Local<v8::String> obj = v8::String::New("");
15047  context->SetData(obj);
15048  CompileRun(source_simple);
15049  context->Exit();
15050  }
15051  context.Dispose();
15053  for (gc_count = 1; gc_count < 10; gc_count++) {
15054  other_context->Enter();
15055  CompileRun(source_simple);
15056  other_context->Exit();
15057  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15058  if (GetGlobalObjectsCount() == 1) break;
15059  }
15060  CHECK_GE(2, gc_count);
15061  CHECK_EQ(1, GetGlobalObjectsCount());
15062 
15063  // Eval in a function creates reference from the compilation cache to the
15064  // global object.
15065  const char* source_eval = "function f(){eval('1')}; f()";
15066  context = Context::New();
15067  {
15068  v8::HandleScope scope;
15069 
15070  context->Enter();
15071  CompileRun(source_eval);
15072  context->Exit();
15073  }
15074  context.Dispose();
15076  for (gc_count = 1; gc_count < 10; gc_count++) {
15077  other_context->Enter();
15078  CompileRun(source_eval);
15079  other_context->Exit();
15080  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15081  if (GetGlobalObjectsCount() == 1) break;
15082  }
15083  CHECK_GE(2, gc_count);
15084  CHECK_EQ(1, GetGlobalObjectsCount());
15085 
15086  // Looking up the line number for an exception creates reference from the
15087  // compilation cache to the global object.
15088  const char* source_exception = "function f(){throw 1;} f()";
15089  context = Context::New();
15090  {
15091  v8::HandleScope scope;
15092 
15093  context->Enter();
15094  v8::TryCatch try_catch;
15095  CompileRun(source_exception);
15096  CHECK(try_catch.HasCaught());
15097  v8::Handle<v8::Message> message = try_catch.Message();
15098  CHECK(!message.IsEmpty());
15099  CHECK_EQ(1, message->GetLineNumber());
15100  context->Exit();
15101  }
15102  context.Dispose();
15104  for (gc_count = 1; gc_count < 10; gc_count++) {
15105  other_context->Enter();
15106  CompileRun(source_exception);
15107  other_context->Exit();
15108  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15109  if (GetGlobalObjectsCount() == 1) break;
15110  }
15111  CHECK_GE(2, gc_count);
15112  CHECK_EQ(1, GetGlobalObjectsCount());
15113 
15114  other_context.Dispose();
15116 }
15117 
15118 
15119 THREADED_TEST(ScriptOrigin) {
15120  v8::HandleScope scope;
15121  LocalContext env;
15124  "function f() {}\n\nfunction g() {}");
15125  v8::Script::Compile(script, &origin)->Run();
15127  env->Global()->Get(v8::String::New("f")));
15129  env->Global()->Get(v8::String::New("g")));
15130 
15131  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15132  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15133  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15134 
15135  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15136  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15137  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15138 }
15139 
15140 THREADED_TEST(FunctionGetInferredName) {
15141  v8::HandleScope scope;
15142  LocalContext env;
15145  "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15146  v8::Script::Compile(script, &origin)->Run();
15148  env->Global()->Get(v8::String::New("f")));
15149  CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15150 }
15151 
15152 THREADED_TEST(ScriptLineNumber) {
15153  v8::HandleScope scope;
15154  LocalContext env;
15157  "function f() {}\n\nfunction g() {}");
15158  v8::Script::Compile(script, &origin)->Run();
15160  env->Global()->Get(v8::String::New("f")));
15162  env->Global()->Get(v8::String::New("g")));
15163  CHECK_EQ(0, f->GetScriptLineNumber());
15164  CHECK_EQ(2, g->GetScriptLineNumber());
15165 }
15166 
15167 
15168 THREADED_TEST(ScriptColumnNumber) {
15169  v8::HandleScope scope;
15170  LocalContext env;
15174  "function foo() {}\n\n function bar() {}");
15175  v8::Script::Compile(script, &origin)->Run();
15177  env->Global()->Get(v8::String::New("foo")));
15179  env->Global()->Get(v8::String::New("bar")));
15180  CHECK_EQ(14, foo->GetScriptColumnNumber());
15181  CHECK_EQ(17, bar->GetScriptColumnNumber());
15182 }
15183 
15184 
15185 THREADED_TEST(FunctionGetScriptId) {
15186  v8::HandleScope scope;
15187  LocalContext env;
15190  v8::Handle<v8::String> scriptSource = v8::String::New(
15191  "function foo() {}\n\n function bar() {}");
15192  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15193  script->Run();
15195  env->Global()->Get(v8::String::New("foo")));
15197  env->Global()->Get(v8::String::New("bar")));
15198  CHECK_EQ(script->Id(), foo->GetScriptId());
15199  CHECK_EQ(script->Id(), bar->GetScriptId());
15200 }
15201 
15202 
15203 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15204  const AccessorInfo& info) {
15205  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15206  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15207  return v8_num(42);
15208 }
15209 
15210 
15211 static void SetterWhichSetsYOnThisTo23(Local<String> name,
15212  Local<Value> value,
15213  const AccessorInfo& info) {
15214  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15215  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15216  info.This()->Set(v8_str("y"), v8_num(23));
15217 }
15218 
15219 
15220 Handle<Value> FooGetInterceptor(Local<String> name,
15221  const AccessorInfo& info) {
15222  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15223  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15224  if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15225  return v8_num(42);
15226 }
15227 
15228 
15229 Handle<Value> FooSetInterceptor(Local<String> name,
15230  Local<Value> value,
15231  const AccessorInfo& info) {
15232  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15233  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15234  if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15235  info.This()->Set(v8_str("y"), v8_num(23));
15236  return v8_num(23);
15237 }
15238 
15239 
15240 TEST(SetterOnConstructorPrototype) {
15241  v8::HandleScope scope;
15242  Local<ObjectTemplate> templ = ObjectTemplate::New();
15243  templ->SetAccessor(v8_str("x"),
15244  GetterWhichReturns42,
15245  SetterWhichSetsYOnThisTo23);
15246  LocalContext context;
15247  context->Global()->Set(v8_str("P"), templ->NewInstance());
15248  CompileRun("function C1() {"
15249  " this.x = 23;"
15250  "};"
15251  "C1.prototype = P;"
15252  "function C2() {"
15253  " this.x = 23"
15254  "};"
15255  "C2.prototype = { };"
15256  "C2.prototype.__proto__ = P;");
15257 
15258  v8::Local<v8::Script> script;
15259  script = v8::Script::Compile(v8_str("new C1();"));
15260  for (int i = 0; i < 10; i++) {
15262  CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15263  CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15264  }
15265 
15266  script = v8::Script::Compile(v8_str("new C2();"));
15267  for (int i = 0; i < 10; i++) {
15269  CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15270  CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15271  }
15272 }
15273 
15274 
15275 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15276  Local<String> name, const AccessorInfo& info) {
15277  return v8_num(42);
15278 }
15279 
15280 
15281 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15282  Local<String> name, Local<Value> value, const AccessorInfo& info) {
15283  if (name->Equals(v8_str("x"))) {
15284  info.This()->Set(v8_str("y"), v8_num(23));
15285  }
15286  return v8::Handle<Value>();
15287 }
15288 
15289 
15290 THREADED_TEST(InterceptorOnConstructorPrototype) {
15291  v8::HandleScope scope;
15292  Local<ObjectTemplate> templ = ObjectTemplate::New();
15293  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15294  NamedPropertySetterWhichSetsYOnThisTo23);
15295  LocalContext context;
15296  context->Global()->Set(v8_str("P"), templ->NewInstance());
15297  CompileRun("function C1() {"
15298  " this.x = 23;"
15299  "};"
15300  "C1.prototype = P;"
15301  "function C2() {"
15302  " this.x = 23"
15303  "};"
15304  "C2.prototype = { };"
15305  "C2.prototype.__proto__ = P;");
15306 
15307  v8::Local<v8::Script> script;
15308  script = v8::Script::Compile(v8_str("new C1();"));
15309  for (int i = 0; i < 10; i++) {
15311  CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15312  CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15313  }
15314 
15315  script = v8::Script::Compile(v8_str("new C2();"));
15316  for (int i = 0; i < 10; i++) {
15318  CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15319  CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15320  }
15321 }
15322 
15323 
15324 TEST(Bug618) {
15325  const char* source = "function C1() {"
15326  " this.x = 23;"
15327  "};"
15328  "C1.prototype = P;";
15329 
15330  v8::HandleScope scope;
15331  LocalContext context;
15332  v8::Local<v8::Script> script;
15333 
15334  // Use a simple object as prototype.
15335  v8::Local<v8::Object> prototype = v8::Object::New();
15336  prototype->Set(v8_str("y"), v8_num(42));
15337  context->Global()->Set(v8_str("P"), prototype);
15338 
15339  // This compile will add the code to the compilation cache.
15340  CompileRun(source);
15341 
15342  script = v8::Script::Compile(v8_str("new C1();"));
15343  // Allow enough iterations for the inobject slack tracking logic
15344  // to finalize instance size and install the fast construct stub.
15345  for (int i = 0; i < 256; i++) {
15347  CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15348  CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15349  }
15350 
15351  // Use an API object with accessors as prototype.
15352  Local<ObjectTemplate> templ = ObjectTemplate::New();
15353  templ->SetAccessor(v8_str("x"),
15354  GetterWhichReturns42,
15355  SetterWhichSetsYOnThisTo23);
15356  context->Global()->Set(v8_str("P"), templ->NewInstance());
15357 
15358  // This compile will get the code from the compilation cache.
15359  CompileRun(source);
15360 
15361  script = v8::Script::Compile(v8_str("new C1();"));
15362  for (int i = 0; i < 10; i++) {
15364  CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15365  CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15366  }
15367 }
15368 
15373 
15376 }
15377 
15380 }
15381 
15384 }
15385 
15388 }
15389 
15390 TEST(GCCallbacks) {
15391  LocalContext context;
15392 
15395  CHECK_EQ(0, prologue_call_count);
15396  CHECK_EQ(0, epilogue_call_count);
15397  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15398  CHECK_EQ(1, prologue_call_count);
15399  CHECK_EQ(1, epilogue_call_count);
15402  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15403  CHECK_EQ(2, prologue_call_count);
15404  CHECK_EQ(2, epilogue_call_count);
15405  CHECK_EQ(1, prologue_call_count_second);
15406  CHECK_EQ(1, epilogue_call_count_second);
15409  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15410  CHECK_EQ(2, prologue_call_count);
15411  CHECK_EQ(2, epilogue_call_count);
15412  CHECK_EQ(2, prologue_call_count_second);
15413  CHECK_EQ(2, epilogue_call_count_second);
15416  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15417  CHECK_EQ(2, prologue_call_count);
15418  CHECK_EQ(2, epilogue_call_count);
15419  CHECK_EQ(2, prologue_call_count_second);
15420  CHECK_EQ(2, epilogue_call_count_second);
15421 }
15422 
15423 
15424 THREADED_TEST(AddToJSFunctionResultCache) {
15425  i::FLAG_allow_natives_syntax = true;
15426  v8::HandleScope scope;
15427 
15428  LocalContext context;
15429 
15430  const char* code =
15431  "(function() {"
15432  " var key0 = 'a';"
15433  " var key1 = 'b';"
15434  " var r0 = %_GetFromCache(0, key0);"
15435  " var r1 = %_GetFromCache(0, key1);"
15436  " var r0_ = %_GetFromCache(0, key0);"
15437  " if (r0 !== r0_)"
15438  " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15439  " var r1_ = %_GetFromCache(0, key1);"
15440  " if (r1 !== r1_)"
15441  " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15442  " return 'PASSED';"
15443  "})()";
15444  HEAP->ClearJSFunctionResultCaches();
15445  ExpectString(code, "PASSED");
15446 }
15447 
15448 
15449 static const int k0CacheSize = 16;
15450 
15451 THREADED_TEST(FillJSFunctionResultCache) {
15452  i::FLAG_allow_natives_syntax = true;
15453  v8::HandleScope scope;
15454 
15455  LocalContext context;
15456 
15457  const char* code =
15458  "(function() {"
15459  " var k = 'a';"
15460  " var r = %_GetFromCache(0, k);"
15461  " for (var i = 0; i < 16; i++) {"
15462  " %_GetFromCache(0, 'a' + i);"
15463  " };"
15464  " if (r === %_GetFromCache(0, k))"
15465  " return 'FAILED: k0CacheSize is too small';"
15466  " return 'PASSED';"
15467  "})()";
15468  HEAP->ClearJSFunctionResultCaches();
15469  ExpectString(code, "PASSED");
15470 }
15471 
15472 
15473 THREADED_TEST(RoundRobinGetFromCache) {
15474  i::FLAG_allow_natives_syntax = true;
15475  v8::HandleScope scope;
15476 
15477  LocalContext context;
15478 
15479  const char* code =
15480  "(function() {"
15481  " var keys = [];"
15482  " for (var i = 0; i < 16; i++) keys.push(i);"
15483  " var values = [];"
15484  " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15485  " for (var i = 0; i < 16; i++) {"
15486  " var v = %_GetFromCache(0, keys[i]);"
15487  " if (v.toString() !== values[i].toString())"
15488  " return 'Wrong value for ' + "
15489  " keys[i] + ': ' + v + ' vs. ' + values[i];"
15490  " };"
15491  " return 'PASSED';"
15492  "})()";
15493  HEAP->ClearJSFunctionResultCaches();
15494  ExpectString(code, "PASSED");
15495 }
15496 
15497 
15498 THREADED_TEST(ReverseGetFromCache) {
15499  i::FLAG_allow_natives_syntax = true;
15500  v8::HandleScope scope;
15501 
15502  LocalContext context;
15503 
15504  const char* code =
15505  "(function() {"
15506  " var keys = [];"
15507  " for (var i = 0; i < 16; i++) keys.push(i);"
15508  " var values = [];"
15509  " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15510  " for (var i = 15; i >= 16; i--) {"
15511  " var v = %_GetFromCache(0, keys[i]);"
15512  " if (v !== values[i])"
15513  " return 'Wrong value for ' + "
15514  " keys[i] + ': ' + v + ' vs. ' + values[i];"
15515  " };"
15516  " return 'PASSED';"
15517  "})()";
15518  HEAP->ClearJSFunctionResultCaches();
15519  ExpectString(code, "PASSED");
15520 }
15521 
15522 
15523 THREADED_TEST(TestEviction) {
15524  i::FLAG_allow_natives_syntax = true;
15525  v8::HandleScope scope;
15526 
15527  LocalContext context;
15528 
15529  const char* code =
15530  "(function() {"
15531  " for (var i = 0; i < 2*16; i++) {"
15532  " %_GetFromCache(0, 'a' + i);"
15533  " };"
15534  " return 'PASSED';"
15535  "})()";
15536  HEAP->ClearJSFunctionResultCaches();
15537  ExpectString(code, "PASSED");
15538 }
15539 
15540 
15541 THREADED_TEST(TwoByteStringInAsciiCons) {
15542  // See Chromium issue 47824.
15543  v8::HandleScope scope;
15544 
15545  LocalContext context;
15546  const char* init_code =
15547  "var str1 = 'abelspendabel';"
15548  "var str2 = str1 + str1 + str1;"
15549  "str2;";
15550  Local<Value> result = CompileRun(init_code);
15551 
15552  Local<Value> indexof = CompileRun("str2.indexOf('els')");
15553  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15554 
15555  CHECK(result->IsString());
15556  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15557  int length = string->length();
15558  CHECK(string->IsAsciiRepresentation());
15559 
15560  FlattenString(string);
15561  i::Handle<i::String> flat_string = FlattenGetString(string);
15562 
15563  CHECK(string->IsAsciiRepresentation());
15564  CHECK(flat_string->IsAsciiRepresentation());
15565 
15566  // Create external resource.
15567  uint16_t* uc16_buffer = new uint16_t[length + 1];
15568 
15569  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15570  uc16_buffer[length] = 0;
15571 
15572  TestResource resource(uc16_buffer);
15573 
15574  flat_string->MakeExternal(&resource);
15575 
15576  CHECK(flat_string->IsTwoByteRepresentation());
15577 
15578  // At this point, we should have a Cons string which is flat and ASCII,
15579  // with a first half that is a two-byte string (although it only contains
15580  // ASCII characters). This is a valid sequence of steps, and it can happen
15581  // in real pages.
15582 
15583  CHECK(string->IsAsciiRepresentation());
15584  i::ConsString* cons = i::ConsString::cast(*string);
15585  CHECK_EQ(0, cons->second()->length());
15586  CHECK(cons->first()->IsTwoByteRepresentation());
15587 
15588  // Check that some string operations work.
15589 
15590  // Atom RegExp.
15591  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15592  CHECK_EQ(6, reresult->Int32Value());
15593 
15594  // Nonatom RegExp.
15595  reresult = CompileRun("str2.match(/abe./g).length;");
15596  CHECK_EQ(6, reresult->Int32Value());
15597 
15598  reresult = CompileRun("str2.search(/bel/g);");
15599  CHECK_EQ(1, reresult->Int32Value());
15600 
15601  reresult = CompileRun("str2.search(/be./g);");
15602  CHECK_EQ(1, reresult->Int32Value());
15603 
15604  ExpectTrue("/bel/g.test(str2);");
15605 
15606  ExpectTrue("/be./g.test(str2);");
15607 
15608  reresult = CompileRun("/bel/g.exec(str2);");
15609  CHECK(!reresult->IsNull());
15610 
15611  reresult = CompileRun("/be./g.exec(str2);");
15612  CHECK(!reresult->IsNull());
15613 
15614  ExpectString("str2.substring(2, 10);", "elspenda");
15615 
15616  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15617 
15618  ExpectString("str2.charAt(2);", "e");
15619 
15620  ExpectObject("str2.indexOf('els');", indexof);
15621 
15622  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15623 
15624  reresult = CompileRun("str2.charCodeAt(2);");
15625  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
15626 }
15627 
15628 
15629 // Failed access check callback that performs a GC on each invocation.
15630 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
15631  v8::AccessType type,
15632  Local<v8::Value> data) {
15633  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15634 }
15635 
15636 
15637 TEST(GCInFailedAccessCheckCallback) {
15638  // Install a failed access check callback that performs a GC on each
15639  // invocation. Then force the callback to be called from va
15640 
15643 
15644  v8::HandleScope scope;
15645 
15646  // Create an ObjectTemplate for global objects and install access
15647  // check callbacks that will block access.
15649  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15650  IndexedGetAccessBlocker,
15652  false);
15653 
15654  // Create a context and set an x property on it's global object.
15655  LocalContext context0(NULL, global_template);
15656  context0->Global()->Set(v8_str("x"), v8_num(42));
15657  v8::Handle<v8::Object> global0 = context0->Global();
15658 
15659  // Create a context with a different security token so that the
15660  // failed access check callback will be called on each access.
15661  LocalContext context1(NULL, global_template);
15662  context1->Global()->Set(v8_str("other"), global0);
15663 
15664  // Get property with failed access check.
15665  ExpectUndefined("other.x");
15666 
15667  // Get element with failed access check.
15668  ExpectUndefined("other[0]");
15669 
15670  // Set property with failed access check.
15671  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15672  CHECK(result->IsObject());
15673 
15674  // Set element with failed access check.
15675  result = CompileRun("other[0] = new Object()");
15676  CHECK(result->IsObject());
15677 
15678  // Get property attribute with failed access check.
15679  ExpectFalse("\'x\' in other");
15680 
15681  // Get property attribute for element with failed access check.
15682  ExpectFalse("0 in other");
15683 
15684  // Delete property.
15685  ExpectFalse("delete other.x");
15686 
15687  // Delete element.
15688  CHECK_EQ(false, global0->Delete(0));
15689 
15690  // DefineAccessor.
15691  CHECK_EQ(false,
15692  global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15693 
15694  // Define JavaScript accessor.
15695  ExpectUndefined("Object.prototype.__defineGetter__.call("
15696  " other, \'x\', function() { return 42; })");
15697 
15698  // LookupAccessor.
15699  ExpectUndefined("Object.prototype.__lookupGetter__.call("
15700  " other, \'x\')");
15701 
15702  // HasLocalElement.
15703  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15704 
15705  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15706  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15707  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15708 
15709  // Reset the failed access check callback so it does not influence
15710  // the other tests.
15712 }
15713 
15714 TEST(DefaultIsolateGetCurrent) {
15716  v8::Isolate* isolate = v8::Isolate::GetCurrent();
15717  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15718  printf("*** %s\n", "DefaultIsolateGetCurrent success");
15719 }
15720 
15721 TEST(IsolateNewDispose) {
15722  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15723  v8::Isolate* isolate = v8::Isolate::New();
15724  CHECK(isolate != NULL);
15725  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15726  CHECK(current_isolate != isolate);
15727  CHECK(current_isolate == v8::Isolate::GetCurrent());
15728 
15730  last_location = last_message = NULL;
15731  isolate->Dispose();
15732  CHECK_EQ(last_location, NULL);
15733  CHECK_EQ(last_message, NULL);
15734 }
15735 
15736 TEST(IsolateEnterExitDefault) {
15737  v8::HandleScope scope;
15738  LocalContext context;
15739  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15740  CHECK(current_isolate != NULL); // Default isolate.
15741  ExpectString("'hello'", "hello");
15742  current_isolate->Enter();
15743  ExpectString("'still working'", "still working");
15744  current_isolate->Exit();
15745  ExpectString("'still working 2'", "still working 2");
15746  current_isolate->Exit();
15747  // Default isolate is always, well, 'default current'.
15748  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15749  // Still working since default isolate is auto-entering any thread
15750  // that has no isolate and attempts to execute V8 APIs.
15751  ExpectString("'still working 3'", "still working 3");
15752 }
15753 
15754 TEST(DisposeDefaultIsolate) {
15756 
15757  // Run some V8 code to trigger default isolate to become 'current'.
15758  v8::HandleScope scope;
15759  LocalContext context;
15760  ExpectString("'run some V8'", "run some V8");
15761 
15762  v8::Isolate* isolate = v8::Isolate::GetCurrent();
15763  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15764  last_location = last_message = NULL;
15765  isolate->Dispose();
15766  // It is not possible to dispose default isolate via Isolate API.
15767  CHECK_NE(last_location, NULL);
15768  CHECK_NE(last_message, NULL);
15769 }
15770 
15771 TEST(RunDefaultAndAnotherIsolate) {
15772  v8::HandleScope scope;
15773  LocalContext context;
15774 
15775  // Enter new isolate.
15776  v8::Isolate* isolate = v8::Isolate::New();
15777  CHECK(isolate);
15778  isolate->Enter();
15779  { // Need this block because subsequent Exit() will deallocate Heap,
15780  // so we need all scope objects to be deconstructed when it happens.
15781  v8::HandleScope scope_new;
15782  LocalContext context_new;
15783 
15784  // Run something in new isolate.
15785  CompileRun("var foo = 153;");
15786  ExpectTrue("function f() { return foo == 153; }; f()");
15787  }
15788  isolate->Exit();
15789 
15790  // This runs automatically in default isolate.
15791  // Variables in another isolate should be not available.
15792  ExpectTrue("function f() {"
15793  " try {"
15794  " foo;"
15795  " return false;"
15796  " } catch(e) {"
15797  " return true;"
15798  " }"
15799  "};"
15800  "var bar = 371;"
15801  "f()");
15802 
15804  last_location = last_message = NULL;
15805  isolate->Dispose();
15806  CHECK_EQ(last_location, NULL);
15807  CHECK_EQ(last_message, NULL);
15808 
15809  // Check that default isolate still runs.
15810  ExpectTrue("function f() { return bar == 371; }; f()");
15811 }
15812 
15813 TEST(DisposeIsolateWhenInUse) {
15814  v8::Isolate* isolate = v8::Isolate::New();
15815  CHECK(isolate);
15816  isolate->Enter();
15817  v8::HandleScope scope;
15818  LocalContext context;
15819  // Run something in this isolate.
15820  ExpectTrue("true");
15822  last_location = last_message = NULL;
15823  // Still entered, should fail.
15824  isolate->Dispose();
15825  CHECK_NE(last_location, NULL);
15826  CHECK_NE(last_message, NULL);
15827 }
15828 
15829 TEST(RunTwoIsolatesOnSingleThread) {
15830  // Run isolate 1.
15831  v8::Isolate* isolate1 = v8::Isolate::New();
15832  isolate1->Enter();
15834 
15835  {
15836  v8::Context::Scope cscope(context1);
15837  v8::HandleScope scope;
15838  // Run something in new isolate.
15839  CompileRun("var foo = 'isolate 1';");
15840  ExpectString("function f() { return foo; }; f()", "isolate 1");
15841  }
15842 
15843  // Run isolate 2.
15844  v8::Isolate* isolate2 = v8::Isolate::New();
15845  v8::Persistent<v8::Context> context2;
15846 
15847  {
15848  v8::Isolate::Scope iscope(isolate2);
15849  context2 = v8::Context::New();
15850  v8::Context::Scope cscope(context2);
15851  v8::HandleScope scope;
15852 
15853  // Run something in new isolate.
15854  CompileRun("var foo = 'isolate 2';");
15855  ExpectString("function f() { return foo; }; f()", "isolate 2");
15856  }
15857 
15858  {
15859  v8::Context::Scope cscope(context1);
15860  v8::HandleScope scope;
15861  // Now again in isolate 1
15862  ExpectString("function f() { return foo; }; f()", "isolate 1");
15863  }
15864 
15865  isolate1->Exit();
15866 
15867  // Run some stuff in default isolate.
15868  v8::Persistent<v8::Context> context_default = v8::Context::New();
15869 
15870  {
15871  v8::Context::Scope cscope(context_default);
15872  v8::HandleScope scope;
15873  // Variables in other isolates should be not available, verify there
15874  // is an exception.
15875  ExpectTrue("function f() {"
15876  " try {"
15877  " foo;"
15878  " return false;"
15879  " } catch(e) {"
15880  " return true;"
15881  " }"
15882  "};"
15883  "var isDefaultIsolate = true;"
15884  "f()");
15885  }
15886 
15887  isolate1->Enter();
15888 
15889  {
15890  v8::Isolate::Scope iscope(isolate2);
15891  v8::Context::Scope cscope(context2);
15892  v8::HandleScope scope;
15893  ExpectString("function f() { return foo; }; f()", "isolate 2");
15894  }
15895 
15896  {
15897  v8::Context::Scope cscope(context1);
15898  v8::HandleScope scope;
15899  ExpectString("function f() { return foo; }; f()", "isolate 1");
15900  }
15901 
15902  {
15903  v8::Isolate::Scope iscope(isolate2);
15904  context2.Dispose();
15905  }
15906 
15907  context1.Dispose();
15908  isolate1->Exit();
15909 
15911  last_location = last_message = NULL;
15912 
15913  isolate1->Dispose();
15914  CHECK_EQ(last_location, NULL);
15915  CHECK_EQ(last_message, NULL);
15916 
15917  isolate2->Dispose();
15918  CHECK_EQ(last_location, NULL);
15919  CHECK_EQ(last_message, NULL);
15920 
15921  // Check that default isolate still runs.
15922  {
15923  v8::Context::Scope cscope(context_default);
15924  v8::HandleScope scope;
15925  ExpectTrue("function f() { return isDefaultIsolate; }; f()");
15926  }
15927 }
15928 
15929 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
15930  v8::Isolate::Scope isolate_scope(isolate);
15931  v8::HandleScope scope;
15932  LocalContext context;
15934  i::OS::SNPrintF(code, "function fib(n) {"
15935  " if (n <= 2) return 1;"
15936  " return fib(n-1) + fib(n-2);"
15937  "}"
15938  "fib(%d)", limit);
15939  Local<Value> value = CompileRun(code.start());
15940  CHECK(value->IsNumber());
15941  return static_cast<int>(value->NumberValue());
15942 }
15943 
15945  public:
15946  IsolateThread(v8::Isolate* isolate, int fib_limit)
15947  : Thread("IsolateThread"),
15948  isolate_(isolate),
15949  fib_limit_(fib_limit),
15950  result_(0) { }
15951 
15952  void Run() {
15953  result_ = CalcFibonacci(isolate_, fib_limit_);
15954  }
15955 
15956  int result() { return result_; }
15957 
15958  private:
15959  v8::Isolate* isolate_;
15960  int fib_limit_;
15961  int result_;
15962 };
15963 
15964 TEST(MultipleIsolatesOnIndividualThreads) {
15965  v8::Isolate* isolate1 = v8::Isolate::New();
15966  v8::Isolate* isolate2 = v8::Isolate::New();
15967 
15968  IsolateThread thread1(isolate1, 21);
15969  IsolateThread thread2(isolate2, 12);
15970 
15971  // Compute some fibonacci numbers on 3 threads in 3 isolates.
15972  thread1.Start();
15973  thread2.Start();
15974 
15975  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15976  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
15977 
15978  thread1.Join();
15979  thread2.Join();
15980 
15981  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
15982  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
15983  CHECK_EQ(result1, 10946);
15984  CHECK_EQ(result2, 144);
15985  CHECK_EQ(result1, thread1.result());
15986  CHECK_EQ(result2, thread2.result());
15987 
15988  isolate1->Dispose();
15989  isolate2->Dispose();
15990 }
15991 
15992 TEST(IsolateDifferentContexts) {
15993  v8::Isolate* isolate = v8::Isolate::New();
15994  Persistent<v8::Context> context;
15995  {
15996  v8::Isolate::Scope isolate_scope(isolate);
15997  v8::HandleScope handle_scope;
15998  context = v8::Context::New();
15999  v8::Context::Scope context_scope(context);
16000  Local<Value> v = CompileRun("2");
16001  CHECK(v->IsNumber());
16002  CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16003  }
16004  {
16005  v8::Isolate::Scope isolate_scope(isolate);
16006  v8::HandleScope handle_scope;
16007  context = v8::Context::New();
16008  v8::Context::Scope context_scope(context);
16009  Local<Value> v = CompileRun("22");
16010  CHECK(v->IsNumber());
16011  CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16012  }
16013 }
16014 
16016  public:
16017  enum TestCase {
16024  };
16025 
16027  : Thread("InitDefaultIsolateThread"),
16028  testCase_(testCase),
16029  result_(false) { }
16030 
16031  void Run() {
16032  switch (testCase_) {
16033  case IgnoreOOM:
16035  break;
16036 
16037  case SetResourceConstraints: {
16038  static const int K = 1024;
16039  v8::ResourceConstraints constraints;
16040  constraints.set_max_young_space_size(256 * K);
16041  constraints.set_max_old_space_size(4 * K * K);
16042  v8::SetResourceConstraints(&constraints);
16043  break;
16044  }
16045 
16046  case SetFatalHandler:
16048  break;
16049 
16050  case SetCounterFunction:
16052  break;
16053 
16056  break;
16057 
16060  break;
16061  }
16062  result_ = true;
16063  }
16064 
16065  bool result() { return result_; }
16066 
16067  private:
16068  TestCase testCase_;
16069  bool result_;
16070 };
16071 
16072 
16073 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16074  InitDefaultIsolateThread thread(testCase);
16075  thread.Start();
16076  thread.Join();
16077  CHECK_EQ(thread.result(), true);
16078 }
16079 
16080 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16081  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16082 }
16083 
16084 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16086 }
16087 
16088 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16089  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16090 }
16091 
16092 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16093  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16094 }
16095 
16096 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16098 }
16099 
16100 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16102 }
16103 
16104 
16105 TEST(StringCheckMultipleContexts) {
16106  const char* code =
16107  "(function() { return \"a\".charAt(0); })()";
16108 
16109  {
16110  // Run the code twice in the first context to initialize the call IC.
16111  v8::HandleScope scope;
16112  LocalContext context1;
16113  ExpectString(code, "a");
16114  ExpectString(code, "a");
16115  }
16116 
16117  {
16118  // Change the String.prototype in the second context and check
16119  // that the right function gets called.
16120  v8::HandleScope scope;
16121  LocalContext context2;
16122  CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16123  ExpectString(code, "not a");
16124  }
16125 }
16126 
16127 
16128 TEST(NumberCheckMultipleContexts) {
16129  const char* code =
16130  "(function() { return (42).toString(); })()";
16131 
16132  {
16133  // Run the code twice in the first context to initialize the call IC.
16134  v8::HandleScope scope;
16135  LocalContext context1;
16136  ExpectString(code, "42");
16137  ExpectString(code, "42");
16138  }
16139 
16140  {
16141  // Change the Number.prototype in the second context and check
16142  // that the right function gets called.
16143  v8::HandleScope scope;
16144  LocalContext context2;
16145  CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16146  ExpectString(code, "not 42");
16147  }
16148 }
16149 
16150 
16151 TEST(BooleanCheckMultipleContexts) {
16152  const char* code =
16153  "(function() { return true.toString(); })()";
16154 
16155  {
16156  // Run the code twice in the first context to initialize the call IC.
16157  v8::HandleScope scope;
16158  LocalContext context1;
16159  ExpectString(code, "true");
16160  ExpectString(code, "true");
16161  }
16162 
16163  {
16164  // Change the Boolean.prototype in the second context and check
16165  // that the right function gets called.
16166  v8::HandleScope scope;
16167  LocalContext context2;
16168  CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16169  ExpectString(code, "");
16170  }
16171 }
16172 
16173 
16174 TEST(DontDeleteCellLoadIC) {
16175  const char* function_code =
16176  "function readCell() { while (true) { return cell; } }";
16177 
16178  {
16179  // Run the code twice in the first context to initialize the load
16180  // IC for a don't delete cell.
16181  v8::HandleScope scope;
16182  LocalContext context1;
16183  CompileRun("var cell = \"first\";");
16184  ExpectBoolean("delete cell", false);
16185  CompileRun(function_code);
16186  ExpectString("readCell()", "first");
16187  ExpectString("readCell()", "first");
16188  }
16189 
16190  {
16191  // Use a deletable cell in the second context.
16192  v8::HandleScope scope;
16193  LocalContext context2;
16194  CompileRun("cell = \"second\";");
16195  CompileRun(function_code);
16196  ExpectString("readCell()", "second");
16197  ExpectBoolean("delete cell", true);
16198  ExpectString("(function() {"
16199  " try {"
16200  " return readCell();"
16201  " } catch(e) {"
16202  " return e.toString();"
16203  " }"
16204  "})()",
16205  "ReferenceError: cell is not defined");
16206  CompileRun("cell = \"new_second\";");
16207  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16208  ExpectString("readCell()", "new_second");
16209  ExpectString("readCell()", "new_second");
16210  }
16211 }
16212 
16213 
16214 TEST(DontDeleteCellLoadICForceDelete) {
16215  const char* function_code =
16216  "function readCell() { while (true) { return cell; } }";
16217 
16218  // Run the code twice to initialize the load IC for a don't delete
16219  // cell.
16220  v8::HandleScope scope;
16221  LocalContext context;
16222  CompileRun("var cell = \"value\";");
16223  ExpectBoolean("delete cell", false);
16224  CompileRun(function_code);
16225  ExpectString("readCell()", "value");
16226  ExpectString("readCell()", "value");
16227 
16228  // Delete the cell using the API and check the inlined code works
16229  // correctly.
16230  CHECK(context->Global()->ForceDelete(v8_str("cell")));
16231  ExpectString("(function() {"
16232  " try {"
16233  " return readCell();"
16234  " } catch(e) {"
16235  " return e.toString();"
16236  " }"
16237  "})()",
16238  "ReferenceError: cell is not defined");
16239 }
16240 
16241 
16242 TEST(DontDeleteCellLoadICAPI) {
16243  const char* function_code =
16244  "function readCell() { while (true) { return cell; } }";
16245 
16246  // Run the code twice to initialize the load IC for a don't delete
16247  // cell created using the API.
16248  v8::HandleScope scope;
16249  LocalContext context;
16250  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16251  ExpectBoolean("delete cell", false);
16252  CompileRun(function_code);
16253  ExpectString("readCell()", "value");
16254  ExpectString("readCell()", "value");
16255 
16256  // Delete the cell using the API and check the inlined code works
16257  // correctly.
16258  CHECK(context->Global()->ForceDelete(v8_str("cell")));
16259  ExpectString("(function() {"
16260  " try {"
16261  " return readCell();"
16262  " } catch(e) {"
16263  " return e.toString();"
16264  " }"
16265  "})()",
16266  "ReferenceError: cell is not defined");
16267 }
16268 
16269 
16271  public:
16273  : counter_(0), object_(object) { }
16274 
16275  virtual void VisitPersistentHandle(Persistent<Value> value,
16276  uint16_t class_id) {
16277  if (class_id == 42) {
16278  CHECK(value->IsObject());
16279  v8::Persistent<v8::Object> visited =
16281  CHECK_EQ(42, visited.WrapperClassId());
16282  CHECK_EQ(object_, visited);
16283  ++counter_;
16284  }
16285  }
16286 
16289 };
16290 
16291 
16292 TEST(PersistentHandleVisitor) {
16293  v8::HandleScope scope;
16294  LocalContext context;
16297  CHECK_EQ(0, object.WrapperClassId());
16298  object.SetWrapperClassId(42);
16299  CHECK_EQ(42, object.WrapperClassId());
16300 
16301  Visitor42 visitor(object);
16303  CHECK_EQ(1, visitor.counter_);
16304 
16305  object.Dispose();
16306 }
16307 
16308 
16309 TEST(RegExp) {
16310  v8::HandleScope scope;
16311  LocalContext context;
16312 
16314  CHECK(re->IsRegExp());
16315  CHECK(re->GetSource()->Equals(v8_str("foo")));
16317 
16318  re = v8::RegExp::New(v8_str("bar"),
16319  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16321  CHECK(re->IsRegExp());
16322  CHECK(re->GetSource()->Equals(v8_str("bar")));
16324  static_cast<int>(re->GetFlags()));
16325 
16326  re = v8::RegExp::New(v8_str("baz"),
16327  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16329  CHECK(re->IsRegExp());
16330  CHECK(re->GetSource()->Equals(v8_str("baz")));
16332  static_cast<int>(re->GetFlags()));
16333 
16334  re = CompileRun("/quux/").As<v8::RegExp>();
16335  CHECK(re->IsRegExp());
16336  CHECK(re->GetSource()->Equals(v8_str("quux")));
16337  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
16338 
16339  re = CompileRun("/quux/gm").As<v8::RegExp>();
16340  CHECK(re->IsRegExp());
16341  CHECK(re->GetSource()->Equals(v8_str("quux")));
16343  static_cast<int>(re->GetFlags()));
16344 
16345  // Override the RegExp constructor and check the API constructor
16346  // still works.
16347  CompileRun("RegExp = function() {}");
16348 
16349  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16350  CHECK(re->IsRegExp());
16351  CHECK(re->GetSource()->Equals(v8_str("foobar")));
16352  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
16353 
16354  re = v8::RegExp::New(v8_str("foobarbaz"),
16355  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16357  CHECK(re->IsRegExp());
16358  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
16360  static_cast<int>(re->GetFlags()));
16361 
16362  context->Global()->Set(v8_str("re"), re);
16363  ExpectTrue("re.test('FoobarbaZ')");
16364 
16365  // RegExps are objects on which you can set properties.
16366  re->Set(v8_str("property"), v8::Integer::New(32));
16367  v8::Handle<v8::Value> value(CompileRun("re.property"));
16368  CHECK_EQ(32, value->Int32Value());
16369 
16370  v8::TryCatch try_catch;
16371  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16372  CHECK(re.IsEmpty());
16373  CHECK(try_catch.HasCaught());
16374  context->Global()->Set(v8_str("ex"), try_catch.Exception());
16375  ExpectTrue("ex instanceof SyntaxError");
16376 }
16377 
16378 
16379 THREADED_TEST(Equals) {
16380  v8::HandleScope handleScope;
16381  LocalContext localContext;
16382 
16383  v8::Handle<v8::Object> globalProxy = localContext->Global();
16384  v8::Handle<Value> global = globalProxy->GetPrototype();
16385 
16386  CHECK(global->StrictEquals(global));
16387  CHECK(!global->StrictEquals(globalProxy));
16388  CHECK(!globalProxy->StrictEquals(global));
16389  CHECK(globalProxy->StrictEquals(globalProxy));
16390 
16391  CHECK(global->Equals(global));
16392  CHECK(!global->Equals(globalProxy));
16393  CHECK(!globalProxy->Equals(global));
16394  CHECK(globalProxy->Equals(globalProxy));
16395 }
16396 
16397 
16398 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16399  const v8::AccessorInfo& info ) {
16400  return v8_str("42!");
16401 }
16402 
16403 
16404 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16406  result->Set(0, v8_str("universalAnswer"));
16407  return result;
16408 }
16409 
16410 
16411 TEST(NamedEnumeratorAndForIn) {
16412  v8::HandleScope handle_scope;
16413  LocalContext context;
16414  v8::Context::Scope context_scope(context.local());
16415 
16417  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16418  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16420  "var result = []; for (var k in o) result.push(k); result"));
16421  CHECK_EQ(1, result->Length());
16422  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16423 }
16424 
16425 
16426 TEST(DefinePropertyPostDetach) {
16427  v8::HandleScope scope;
16428  LocalContext context;
16429  v8::Handle<v8::Object> proxy = context->Global();
16430  v8::Handle<v8::Function> define_property =
16431  CompileRun("(function() {"
16432  " Object.defineProperty("
16433  " this,"
16434  " 1,"
16435  " { configurable: true, enumerable: true, value: 3 });"
16436  "})").As<Function>();
16437  context->DetachGlobal();
16438  define_property->Call(proxy, 0, NULL);
16439 }
16440 
16441 
16442 static void InstallContextId(v8::Handle<Context> context, int id) {
16443  Context::Scope scope(context);
16444  CompileRun("Object.prototype").As<Object>()->
16445  Set(v8_str("context_id"), v8::Integer::New(id));
16446 }
16447 
16448 
16449 static void CheckContextId(v8::Handle<Object> object, int expected) {
16450  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16451 }
16452 
16453 
16454 THREADED_TEST(CreationContext) {
16455  HandleScope handle_scope;
16456  Persistent<Context> context1 = Context::New();
16457  InstallContextId(context1, 1);
16458  Persistent<Context> context2 = Context::New();
16459  InstallContextId(context2, 2);
16460  Persistent<Context> context3 = Context::New();
16461  InstallContextId(context3, 3);
16462 
16463  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16464 
16465  Local<Object> object1;
16466  Local<Function> func1;
16467  {
16468  Context::Scope scope(context1);
16469  object1 = Object::New();
16470  func1 = tmpl->GetFunction();
16471  }
16472 
16473  Local<Object> object2;
16474  Local<Function> func2;
16475  {
16476  Context::Scope scope(context2);
16477  object2 = Object::New();
16478  func2 = tmpl->GetFunction();
16479  }
16480 
16481  Local<Object> instance1;
16482  Local<Object> instance2;
16483 
16484  {
16485  Context::Scope scope(context3);
16486  instance1 = func1->NewInstance();
16487  instance2 = func2->NewInstance();
16488  }
16489 
16490  CHECK(object1->CreationContext() == context1);
16491  CheckContextId(object1, 1);
16492  CHECK(func1->CreationContext() == context1);
16493  CheckContextId(func1, 1);
16494  CHECK(instance1->CreationContext() == context1);
16495  CheckContextId(instance1, 1);
16496  CHECK(object2->CreationContext() == context2);
16497  CheckContextId(object2, 2);
16498  CHECK(func2->CreationContext() == context2);
16499  CheckContextId(func2, 2);
16500  CHECK(instance2->CreationContext() == context2);
16501  CheckContextId(instance2, 2);
16502 
16503  {
16504  Context::Scope scope(context1);
16505  CHECK(object1->CreationContext() == context1);
16506  CheckContextId(object1, 1);
16507  CHECK(func1->CreationContext() == context1);
16508  CheckContextId(func1, 1);
16509  CHECK(instance1->CreationContext() == context1);
16510  CheckContextId(instance1, 1);
16511  CHECK(object2->CreationContext() == context2);
16512  CheckContextId(object2, 2);
16513  CHECK(func2->CreationContext() == context2);
16514  CheckContextId(func2, 2);
16515  CHECK(instance2->CreationContext() == context2);
16516  CheckContextId(instance2, 2);
16517  }
16518 
16519  {
16520  Context::Scope scope(context2);
16521  CHECK(object1->CreationContext() == context1);
16522  CheckContextId(object1, 1);
16523  CHECK(func1->CreationContext() == context1);
16524  CheckContextId(func1, 1);
16525  CHECK(instance1->CreationContext() == context1);
16526  CheckContextId(instance1, 1);
16527  CHECK(object2->CreationContext() == context2);
16528  CheckContextId(object2, 2);
16529  CHECK(func2->CreationContext() == context2);
16530  CheckContextId(func2, 2);
16531  CHECK(instance2->CreationContext() == context2);
16532  CheckContextId(instance2, 2);
16533  }
16534 
16535  context1.Dispose();
16536  context2.Dispose();
16537  context3.Dispose();
16538 }
16539 
16540 
16541 THREADED_TEST(CreationContextOfJsFunction) {
16542  HandleScope handle_scope;
16543  Persistent<Context> context = Context::New();
16544  InstallContextId(context, 1);
16545 
16546  Local<Object> function;
16547  {
16548  Context::Scope scope(context);
16549  function = CompileRun("function foo() {}; foo").As<Object>();
16550  }
16551 
16552  CHECK(function->CreationContext() == context);
16553  CheckContextId(function, 1);
16554 
16555  context.Dispose();
16556 }
16557 
16558 
16559 Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16560  const AccessorInfo& info) {
16561  if (index == 42) return v8_str("yes");
16562  return Handle<v8::Integer>();
16563 }
16564 
16565 
16566 Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16567  const AccessorInfo& info) {
16568  if (property->Equals(v8_str("foo"))) return v8_str("yes");
16569  return Handle<Value>();
16570 }
16571 
16572 
16574  uint32_t index, const AccessorInfo& info) {
16575  if (index == 42) return v8_num(1).As<v8::Integer>();
16576  return Handle<v8::Integer>();
16577 }
16578 
16579 
16581  Local<String> property, const AccessorInfo& info) {
16582  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
16583  return Handle<v8::Integer>();
16584 }
16585 
16586 
16588  Local<String> property, const AccessorInfo& info) {
16589  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
16590  return Handle<v8::Integer>();
16591 }
16592 
16593 
16594 Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16595  const AccessorInfo& info) {
16596  return v8_str("yes");
16597 }
16598 
16599 
16600 TEST(HasOwnProperty) {
16601  v8::HandleScope scope;
16602  LocalContext env;
16603  { // Check normal properties and defined getters.
16604  Handle<Value> value = CompileRun(
16605  "function Foo() {"
16606  " this.foo = 11;"
16607  " this.__defineGetter__('baz', function() { return 1; });"
16608  "};"
16609  "function Bar() { "
16610  " this.bar = 13;"
16611  " this.__defineGetter__('bla', function() { return 2; });"
16612  "};"
16613  "Bar.prototype = new Foo();"
16614  "new Bar();");
16615  CHECK(value->IsObject());
16616  Handle<Object> object = value->ToObject();
16617  CHECK(object->Has(v8_str("foo")));
16618  CHECK(!object->HasOwnProperty(v8_str("foo")));
16619  CHECK(object->HasOwnProperty(v8_str("bar")));
16620  CHECK(object->Has(v8_str("baz")));
16621  CHECK(!object->HasOwnProperty(v8_str("baz")));
16622  CHECK(object->HasOwnProperty(v8_str("bla")));
16623  }
16624  { // Check named getter interceptors.
16625  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16626  templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
16627  Handle<Object> instance = templ->NewInstance();
16628  CHECK(!instance->HasOwnProperty(v8_str("42")));
16629  CHECK(instance->HasOwnProperty(v8_str("foo")));
16630  CHECK(!instance->HasOwnProperty(v8_str("bar")));
16631  }
16632  { // Check indexed getter interceptors.
16633  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16634  templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
16635  Handle<Object> instance = templ->NewInstance();
16636  CHECK(instance->HasOwnProperty(v8_str("42")));
16637  CHECK(!instance->HasOwnProperty(v8_str("43")));
16638  CHECK(!instance->HasOwnProperty(v8_str("foo")));
16639  }
16640  { // Check named query interceptors.
16641  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16642  templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
16643  Handle<Object> instance = templ->NewInstance();
16644  CHECK(instance->HasOwnProperty(v8_str("foo")));
16645  CHECK(!instance->HasOwnProperty(v8_str("bar")));
16646  }
16647  { // Check indexed query interceptors.
16648  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16649  templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
16650  Handle<Object> instance = templ->NewInstance();
16651  CHECK(instance->HasOwnProperty(v8_str("42")));
16652  CHECK(!instance->HasOwnProperty(v8_str("41")));
16653  }
16654  { // Check callbacks.
16655  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16656  templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
16657  Handle<Object> instance = templ->NewInstance();
16658  CHECK(instance->HasOwnProperty(v8_str("foo")));
16659  CHECK(!instance->HasOwnProperty(v8_str("bar")));
16660  }
16661  { // Check that query wins on disagreement.
16662  Handle<ObjectTemplate> templ = ObjectTemplate::New();
16663  templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16664  0,
16666  Handle<Object> instance = templ->NewInstance();
16667  CHECK(!instance->HasOwnProperty(v8_str("foo")));
16668  CHECK(instance->HasOwnProperty(v8_str("bar")));
16669  }
16670 }
16671 
16672 
16674  Handle<Value> result = CompileRun("eval('42')");
16675  CHECK_EQ(42, result->Int32Value());
16676  result = CompileRun("(function(e) { return e('42'); })(eval)");
16677  CHECK_EQ(42, result->Int32Value());
16678  result = CompileRun("var f = new Function('return 42'); f()");
16679  CHECK_EQ(42, result->Int32Value());
16680 }
16681 
16682 
16684  TryCatch try_catch;
16685 
16686  Handle<Value> result = CompileRun("eval('42')");
16687  CHECK(result.IsEmpty());
16688  CHECK(try_catch.HasCaught());
16689  try_catch.Reset();
16690 
16691  result = CompileRun("(function(e) { return e('42'); })(eval)");
16692  CHECK(result.IsEmpty());
16693  CHECK(try_catch.HasCaught());
16694  try_catch.Reset();
16695 
16696  result = CompileRun("var f = new Function('return 42'); f()");
16697  CHECK(result.IsEmpty());
16698  CHECK(try_catch.HasCaught());
16699 }
16700 
16701 
16702 bool CodeGenerationAllowed(Local<Context> context) {
16704  return true;
16705 }
16706 
16707 
16708 bool CodeGenerationDisallowed(Local<Context> context) {
16710  return false;
16711 }
16712 
16713 
16714 THREADED_TEST(AllowCodeGenFromStrings) {
16715  v8::HandleScope scope;
16716  LocalContext context;
16717 
16718  // eval and the Function constructor allowed by default.
16721 
16722  // Disallow eval and the Function constructor.
16723  context->AllowCodeGenerationFromStrings(false);
16726 
16727  // Allow again.
16728  context->AllowCodeGenerationFromStrings(true);
16730 
16731  // Disallow but setting a global callback that will allow the calls.
16732  context->AllowCodeGenerationFromStrings(false);
16733  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
16736 
16737  // Set a callback that disallows the code generation.
16738  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16741 }
16742 
16743 
16744 TEST(SetErrorMessageForCodeGenFromStrings) {
16745  v8::HandleScope scope;
16746  LocalContext context;
16747  TryCatch try_catch;
16748 
16749  Handle<String> message = v8_str("Message") ;
16750  Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
16751  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16752  context->AllowCodeGenerationFromStrings(false);
16754  Handle<Value> result = CompileRun("eval('42')");
16755  CHECK(result.IsEmpty());
16756  CHECK(try_catch.HasCaught());
16757  Handle<String> actual_message = try_catch.Message()->Get();
16758  CHECK(expected_message->Equals(actual_message));
16759 }
16760 
16761 
16762 static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16763  return v8::Undefined();
16764 }
16765 
16766 
16767 THREADED_TEST(CallAPIFunctionOnNonObject) {
16768  v8::HandleScope scope;
16769  LocalContext context;
16770  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
16771  Handle<Function> function = templ->GetFunction();
16772  context->Global()->Set(v8_str("f"), function);
16773  TryCatch try_catch;
16774  CompileRun("f.call(2)");
16775 }
16776 
16777 
16778 // Regression test for issue 1470.
16779 THREADED_TEST(ReadOnlyIndexedProperties) {
16780  v8::HandleScope scope;
16781  Local<ObjectTemplate> templ = ObjectTemplate::New();
16782 
16783  LocalContext context;
16784  Local<v8::Object> obj = templ->NewInstance();
16785  context->Global()->Set(v8_str("obj"), obj);
16786  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16787  obj->Set(v8_str("1"), v8_str("foobar"));
16788  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
16789  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
16790  obj->Set(v8_num(2), v8_str("foobar"));
16791  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
16792 
16793  // Test non-smi case.
16794  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16795  obj->Set(v8_str("2000000000"), v8_str("foobar"));
16796  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16797 }
16798 
16799 
16800 THREADED_TEST(Regress1516) {
16801  v8::HandleScope scope;
16802 
16803  LocalContext context;
16804  { v8::HandleScope temp_scope;
16805  CompileRun("({'a': 0})");
16806  }
16807 
16808  int elements;
16809  { i::MapCache* map_cache =
16810  i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16811  elements = map_cache->NumberOfElements();
16812  CHECK_LE(1, elements);
16813  }
16814 
16815  i::Isolate::Current()->heap()->CollectAllGarbage(
16817  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16818  if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16819  i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16820  CHECK_GT(elements, map_cache->NumberOfElements());
16821  }
16822  }
16823 }
16824 
16825 
16826 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16827  Local<Value> name,
16828  v8::AccessType type,
16829  Local<Value> data) {
16830  // Only block read access to __proto__.
16831  if (type == v8::ACCESS_GET &&
16832  name->IsString() &&
16833  name->ToString()->Length() == 9 &&
16834  name->ToString()->Utf8Length() == 9) {
16835  char buffer[10];
16836  CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16837  return strncmp(buffer, "__proto__", 9) != 0;
16838  }
16839 
16840  return true;
16841 }
16842 
16843 
16844 THREADED_TEST(Regress93759) {
16845  HandleScope scope;
16846 
16847  // Template for object with security check.
16848  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16849  // We don't do indexing, so any callback can be used for that.
16850  no_proto_template->SetAccessCheckCallbacks(
16851  BlockProtoNamedSecurityTestCallback,
16852  IndexedSecurityTestCallback);
16853 
16854  // Templates for objects with hidden prototypes and possibly security check.
16855  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16856  hidden_proto_template->SetHiddenPrototype(true);
16857 
16858  Local<FunctionTemplate> protected_hidden_proto_template =
16860  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16861  BlockProtoNamedSecurityTestCallback,
16862  IndexedSecurityTestCallback);
16863  protected_hidden_proto_template->SetHiddenPrototype(true);
16864 
16865  // Context for "foreign" objects used in test.
16866  Persistent<Context> context = v8::Context::New();
16867  context->Enter();
16868 
16869  // Plain object, no security check.
16870  Local<Object> simple_object = Object::New();
16871 
16872  // Object with explicit security check.
16873  Local<Object> protected_object =
16874  no_proto_template->NewInstance();
16875 
16876  // JSGlobalProxy object, always have security check.
16877  Local<Object> proxy_object =
16878  context->Global();
16879 
16880  // Global object, the prototype of proxy_object. No security checks.
16881  Local<Object> global_object =
16882  proxy_object->GetPrototype()->ToObject();
16883 
16884  // Hidden prototype without security check.
16885  Local<Object> hidden_prototype =
16886  hidden_proto_template->GetFunction()->NewInstance();
16887  Local<Object> object_with_hidden =
16888  Object::New();
16889  object_with_hidden->SetPrototype(hidden_prototype);
16890 
16891  // Hidden prototype with security check on the hidden prototype.
16892  Local<Object> protected_hidden_prototype =
16893  protected_hidden_proto_template->GetFunction()->NewInstance();
16894  Local<Object> object_with_protected_hidden =
16895  Object::New();
16896  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16897 
16898  context->Exit();
16899 
16900  // Template for object for second context. Values to test are put on it as
16901  // properties.
16902  Local<ObjectTemplate> global_template = ObjectTemplate::New();
16903  global_template->Set(v8_str("simple"), simple_object);
16904  global_template->Set(v8_str("protected"), protected_object);
16905  global_template->Set(v8_str("global"), global_object);
16906  global_template->Set(v8_str("proxy"), proxy_object);
16907  global_template->Set(v8_str("hidden"), object_with_hidden);
16908  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
16909 
16910  LocalContext context2(NULL, global_template);
16911 
16912  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16913  CHECK(result1->Equals(simple_object->GetPrototype()));
16914 
16915  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16916  CHECK(result2->Equals(Undefined()));
16917 
16918  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16919  CHECK(result3->Equals(global_object->GetPrototype()));
16920 
16921  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16922  CHECK(result4->Equals(Undefined()));
16923 
16924  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16925  CHECK(result5->Equals(
16926  object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16927 
16928  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16929  CHECK(result6->Equals(Undefined()));
16930 
16931  context.Dispose();
16932 }
16933 
16934 
16935 THREADED_TEST(Regress125988) {
16936  v8::HandleScope scope;
16937  Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16939  LocalContext env;
16940  env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
16941  CompileRun("var a = new Object();"
16942  "var b = new Intercept();"
16943  "var c = new Object();"
16944  "c.__proto__ = b;"
16945  "b.__proto__ = a;"
16946  "a.x = 23;"
16947  "for (var i = 0; i < 3; i++) c.x;");
16948  ExpectBoolean("c.hasOwnProperty('x')", false);
16949  ExpectInt32("c.x", 23);
16950  CompileRun("a.y = 42;"
16951  "for (var i = 0; i < 3; i++) c.x;");
16952  ExpectBoolean("c.hasOwnProperty('x')", false);
16953  ExpectInt32("c.x", 23);
16954  ExpectBoolean("c.hasOwnProperty('y')", false);
16955  ExpectInt32("c.y", 42);
16956 }
16957 
16958 
16959 static void TestReceiver(Local<Value> expected_result,
16960  Local<Value> expected_receiver,
16961  const char* code) {
16962  Local<Value> result = CompileRun(code);
16963  CHECK(result->IsObject());
16964  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
16965  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
16966 }
16967 
16968 
16969 THREADED_TEST(ForeignFunctionReceiver) {
16970  HandleScope scope;
16971 
16972  // Create two contexts with different "id" properties ('i' and 'o').
16973  // Call a function both from its own context and from a the foreign
16974  // context, and see what "this" is bound to (returning both "this"
16975  // and "this.id" for comparison).
16976 
16977  Persistent<Context> foreign_context = v8::Context::New();
16978  foreign_context->Enter();
16979  Local<Value> foreign_function =
16980  CompileRun("function func() { return { 0: this.id, "
16981  " 1: this, "
16982  " toString: function() { "
16983  " return this[0];"
16984  " }"
16985  " };"
16986  "}"
16987  "var id = 'i';"
16988  "func;");
16989  CHECK(foreign_function->IsFunction());
16990  foreign_context->Exit();
16991 
16992  LocalContext context;
16993 
16994  Local<String> password = v8_str("Password");
16995  // Don't get hit by security checks when accessing foreign_context's
16996  // global receiver (aka. global proxy).
16997  context->SetSecurityToken(password);
16998  foreign_context->SetSecurityToken(password);
16999 
17000  Local<String> i = v8_str("i");
17001  Local<String> o = v8_str("o");
17002  Local<String> id = v8_str("id");
17003 
17004  CompileRun("function ownfunc() { return { 0: this.id, "
17005  " 1: this, "
17006  " toString: function() { "
17007  " return this[0];"
17008  " }"
17009  " };"
17010  "}"
17011  "var id = 'o';"
17012  "ownfunc");
17013  context->Global()->Set(v8_str("func"), foreign_function);
17014 
17015  // Sanity check the contexts.
17016  CHECK(i->Equals(foreign_context->Global()->Get(id)));
17017  CHECK(o->Equals(context->Global()->Get(id)));
17018 
17019  // Checking local function's receiver.
17020  // Calling function using its call/apply methods.
17021  TestReceiver(o, context->Global(), "ownfunc.call()");
17022  TestReceiver(o, context->Global(), "ownfunc.apply()");
17023  // Making calls through built-in functions.
17024  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17025  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17026  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17027  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17028  // Calling with environment record as base.
17029  TestReceiver(o, context->Global(), "ownfunc()");
17030  // Calling with no base.
17031  TestReceiver(o, context->Global(), "(1,ownfunc)()");
17032 
17033  // Checking foreign function return value.
17034  // Calling function using its call/apply methods.
17035  TestReceiver(i, foreign_context->Global(), "func.call()");
17036  TestReceiver(i, foreign_context->Global(), "func.apply()");
17037  // Calling function using another context's call/apply methods.
17038  TestReceiver(i, foreign_context->Global(),
17039  "Function.prototype.call.call(func)");
17040  TestReceiver(i, foreign_context->Global(),
17041  "Function.prototype.call.apply(func)");
17042  TestReceiver(i, foreign_context->Global(),
17043  "Function.prototype.apply.call(func)");
17044  TestReceiver(i, foreign_context->Global(),
17045  "Function.prototype.apply.apply(func)");
17046  // Making calls through built-in functions.
17047  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17048  // ToString(func()) is func()[0], i.e., the returned this.id.
17049  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17050  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17051  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17052 
17053  // TODO(1547): Make the following also return "i".
17054  // Calling with environment record as base.
17055  TestReceiver(o, context->Global(), "func()");
17056  // Calling with no base.
17057  TestReceiver(o, context->Global(), "(1,func)()");
17058 
17059  foreign_context.Dispose();
17060 }
17061 
17062 
17063 uint8_t callback_fired = 0;
17064 
17065 
17067  i::OS::Print("Firing callback 1.\n");
17068  callback_fired ^= 1; // Toggle first bit.
17069 }
17070 
17071 
17073  i::OS::Print("Firing callback 2.\n");
17074  callback_fired ^= 2; // Toggle second bit.
17075 }
17076 
17077 
17078 Handle<Value> RecursiveCall(const Arguments& args) {
17079  int32_t level = args[0]->Int32Value();
17080  if (level < 3) {
17081  level++;
17082  i::OS::Print("Entering recursion level %d.\n", level);
17083  char script[64];
17084  i::Vector<char> script_vector(script, sizeof(script));
17085  i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17086  CompileRun(script_vector.start());
17087  i::OS::Print("Leaving recursion level %d.\n", level);
17088  CHECK_EQ(0, callback_fired);
17089  } else {
17090  i::OS::Print("Recursion ends.\n");
17091  CHECK_EQ(0, callback_fired);
17092  }
17093  return Undefined();
17094 }
17095 
17096 
17098  v8::HandleScope scope;
17099  LocalContext env;
17100  v8::Handle<v8::FunctionTemplate> recursive_runtime =
17102  env->Global()->Set(v8_str("recursion"),
17103  recursive_runtime->GetFunction());
17104  // Adding the same callback a second time has no effect.
17108  i::OS::Print("--- Script (1) ---\n");
17109  Local<Script> script =
17110  v8::Script::Compile(v8::String::New("recursion(0)"));
17111  script->Run();
17112  CHECK_EQ(3, callback_fired);
17113 
17114  i::OS::Print("\n--- Script (2) ---\n");
17115  callback_fired = 0;
17117  script->Run();
17118  CHECK_EQ(2, callback_fired);
17119 
17120  i::OS::Print("\n--- Function ---\n");
17121  callback_fired = 0;
17122  Local<Function> recursive_function =
17123  Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17124  v8::Handle<Value> args[] = { v8_num(0) };
17125  recursive_function->Call(env->Global(), 1, args);
17126  CHECK_EQ(2, callback_fired);
17127 }
17128 
17129 
17131  v8::HandleScope scope;
17132  CompileRun("1+1;");
17133 }
17134 
17135 
17137  v8::HandleScope scope;
17138  CompileRun("throw 'second exception';");
17139 }
17140 
17141 
17142 TEST(CallCompletedCallbackOneException) {
17143  v8::HandleScope scope;
17144  LocalContext env;
17146  CompileRun("throw 'exception';");
17147 }
17148 
17149 
17150 TEST(CallCompletedCallbackTwoExceptions) {
17151  v8::HandleScope scope;
17152  LocalContext env;
17154  CompileRun("throw 'first exception';");
17155 }
17156 
17157 
17158 static int probes_counter = 0;
17159 static int misses_counter = 0;
17160 static int updates_counter = 0;
17161 
17162 
17163 static int* LookupCounter(const char* name) {
17164  if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17165  return &probes_counter;
17166  } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17167  return &misses_counter;
17168  } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17169  return &updates_counter;
17170  }
17171  return NULL;
17172 }
17173 
17174 
17175 static const char* kMegamorphicTestProgram =
17176  "function ClassA() { };"
17177  "function ClassB() { };"
17178  "ClassA.prototype.foo = function() { };"
17179  "ClassB.prototype.foo = function() { };"
17180  "function fooify(obj) { obj.foo(); };"
17181  "var a = new ClassA();"
17182  "var b = new ClassB();"
17183  "for (var i = 0; i < 10000; i++) {"
17184  " fooify(a);"
17185  " fooify(b);"
17186  "}";
17187 
17188 
17189 static void StubCacheHelper(bool primary) {
17190  V8::SetCounterFunction(LookupCounter);
17191  USE(kMegamorphicTestProgram);
17192 #ifdef DEBUG
17193  i::FLAG_native_code_counters = true;
17194  if (primary) {
17195  i::FLAG_test_primary_stub_cache = true;
17196  } else {
17197  i::FLAG_test_secondary_stub_cache = true;
17198  }
17199  i::FLAG_crankshaft = false;
17200  v8::HandleScope scope;
17201  LocalContext env;
17202  int initial_probes = probes_counter;
17203  int initial_misses = misses_counter;
17204  int initial_updates = updates_counter;
17205  CompileRun(kMegamorphicTestProgram);
17206  int probes = probes_counter - initial_probes;
17207  int misses = misses_counter - initial_misses;
17208  int updates = updates_counter - initial_updates;
17209  CHECK_LT(updates, 10);
17210  CHECK_LT(misses, 10);
17211  CHECK_GE(probes, 10000);
17212 #endif
17213 }
17214 
17215 
17216 TEST(SecondaryStubCache) {
17217  StubCacheHelper(true);
17218 }
17219 
17220 
17221 TEST(PrimaryStubCache) {
17222  StubCacheHelper(false);
17223 }
17224 
17225 
17226 static int fatal_error_callback_counter = 0;
17227 static void CountingErrorCallback(const char* location, const char* message) {
17228  printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17229  fatal_error_callback_counter++;
17230 }
17231 
17232 
17233 TEST(StaticGetters) {
17234  v8::HandleScope scope;
17235  LocalContext context;
17236  v8::Isolate* isolate = v8::Isolate::GetCurrent();
17237  i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17238  CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17239  CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17240  i::Handle<i::Object> null_value = FACTORY->null_value();
17241  CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17242  CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17243  i::Handle<i::Object> true_value = FACTORY->true_value();
17244  CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17245  CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17246  i::Handle<i::Object> false_value = FACTORY->false_value();
17247  CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17248  CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17249 
17250  // Test after-death behavior.
17252  CHECK_EQ(0, fatal_error_callback_counter);
17253  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17254  v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17255  i::Isolate::Current()->TearDown();
17257  CHECK_EQ(1, fatal_error_callback_counter);
17258  CHECK(v8::Undefined().IsEmpty());
17259  CHECK_EQ(2, fatal_error_callback_counter);
17260  CHECK(v8::Undefined(isolate).IsEmpty());
17261  CHECK_EQ(3, fatal_error_callback_counter);
17262  CHECK(v8::Null().IsEmpty());
17263  CHECK_EQ(4, fatal_error_callback_counter);
17264  CHECK(v8::Null(isolate).IsEmpty());
17265  CHECK_EQ(5, fatal_error_callback_counter);
17266  CHECK(v8::True().IsEmpty());
17267  CHECK_EQ(6, fatal_error_callback_counter);
17268  CHECK(v8::True(isolate).IsEmpty());
17269  CHECK_EQ(7, fatal_error_callback_counter);
17270  CHECK(v8::False().IsEmpty());
17271  CHECK_EQ(8, fatal_error_callback_counter);
17272  CHECK(v8::False(isolate).IsEmpty());
17273  CHECK_EQ(9, fatal_error_callback_counter);
17274 }
17275 
17276 
17277 TEST(IsolateEmbedderData) {
17278  v8::Isolate* isolate = v8::Isolate::GetCurrent();
17279  CHECK_EQ(NULL, isolate->GetData());
17280  CHECK_EQ(NULL, ISOLATE->GetData());
17281  static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17282  isolate->SetData(data1);
17283  CHECK_EQ(data1, isolate->GetData());
17284  CHECK_EQ(data1, ISOLATE->GetData());
17285  static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17286  ISOLATE->SetData(data2);
17287  CHECK_EQ(data2, isolate->GetData());
17288  CHECK_EQ(data2, ISOLATE->GetData());
17289  ISOLATE->TearDown();
17290  CHECK_EQ(data2, isolate->GetData());
17291  CHECK_EQ(data2, ISOLATE->GetData());
17292 }
17293 
17294 
17295 TEST(StringEmpty) {
17296  v8::HandleScope scope;
17297  LocalContext context;
17298  v8::Isolate* isolate = v8::Isolate::GetCurrent();
17299  i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17300  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17301  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17302 
17303  // Test after-death behavior.
17305  CHECK_EQ(0, fatal_error_callback_counter);
17306  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17307  v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17308  i::Isolate::Current()->TearDown();
17310  CHECK_EQ(1, fatal_error_callback_counter);
17311  CHECK(v8::String::Empty().IsEmpty());
17312  CHECK_EQ(2, fatal_error_callback_counter);
17313  CHECK(v8::String::Empty(isolate).IsEmpty());
17314  CHECK_EQ(3, fatal_error_callback_counter);
17315 }
17316 
17317 
17318 static int instance_checked_getter_count = 0;
17319 static Handle<Value> InstanceCheckedGetter(Local<String> name,
17320  const AccessorInfo& info) {
17321  CHECK_EQ(name, v8_str("foo"));
17322  instance_checked_getter_count++;
17323  return v8_num(11);
17324 }
17325 
17326 
17327 static int instance_checked_setter_count = 0;
17328 static void InstanceCheckedSetter(Local<String> name,
17329  Local<Value> value,
17330  const AccessorInfo& info) {
17331  CHECK_EQ(name, v8_str("foo"));
17332  CHECK_EQ(value, v8_num(23));
17333  instance_checked_setter_count++;
17334 }
17335 
17336 
17337 static void CheckInstanceCheckedResult(int getters,
17338  int setters,
17339  bool expects_callbacks,
17340  TryCatch* try_catch) {
17341  if (expects_callbacks) {
17342  CHECK(!try_catch->HasCaught());
17343  CHECK_EQ(getters, instance_checked_getter_count);
17344  CHECK_EQ(setters, instance_checked_setter_count);
17345  } else {
17346  CHECK(try_catch->HasCaught());
17347  CHECK_EQ(0, instance_checked_getter_count);
17348  CHECK_EQ(0, instance_checked_setter_count);
17349  }
17350  try_catch->Reset();
17351 }
17352 
17353 
17354 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17355  instance_checked_getter_count = 0;
17356  instance_checked_setter_count = 0;
17357  TryCatch try_catch;
17358 
17359  // Test path through generic runtime code.
17360  CompileRun("obj.foo");
17361  CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17362  CompileRun("obj.foo = 23");
17363  CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17364 
17365  // Test path through generated LoadIC and StoredIC.
17366  CompileRun("function test_get(o) { o.foo; }"
17367  "test_get(obj);");
17368  CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17369  CompileRun("test_get(obj);");
17370  CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17371  CompileRun("test_get(obj);");
17372  CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17373  CompileRun("function test_set(o) { o.foo = 23; }"
17374  "test_set(obj);");
17375  CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17376  CompileRun("test_set(obj);");
17377  CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17378  CompileRun("test_set(obj);");
17379  CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17380 
17381  // Test path through optimized code.
17382  CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17383  "test_get(obj);");
17384  CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17385  CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17386  "test_set(obj);");
17387  CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17388 
17389  // Cleanup so that closures start out fresh in next check.
17390  CompileRun("%DeoptimizeFunction(test_get);"
17391  "%ClearFunctionTypeFeedback(test_get);"
17392  "%DeoptimizeFunction(test_set);"
17393  "%ClearFunctionTypeFeedback(test_set);");
17394 }
17395 
17396 
17397 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17398  v8::internal::FLAG_allow_natives_syntax = true;
17399  v8::HandleScope scope;
17400  LocalContext context;
17401 
17402  Local<FunctionTemplate> templ = FunctionTemplate::New();
17403  Local<ObjectTemplate> inst = templ->InstanceTemplate();
17404  inst->SetAccessor(v8_str("foo"),
17405  InstanceCheckedGetter, InstanceCheckedSetter,
17406  Handle<Value>(),
17407  v8::DEFAULT,
17408  v8::None,
17410  context->Global()->Set(v8_str("f"), templ->GetFunction());
17411 
17412  printf("Testing positive ...\n");
17413  CompileRun("var obj = new f();");
17414  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17415  CheckInstanceCheckedAccessors(true);
17416 
17417  printf("Testing negative ...\n");
17418  CompileRun("var obj = {};"
17419  "obj.__proto__ = new f();");
17420  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17421  CheckInstanceCheckedAccessors(false);
17422 }
17423 
17424 
17425 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17426  v8::internal::FLAG_allow_natives_syntax = true;
17427  v8::HandleScope scope;
17428  LocalContext context;
17429 
17430  Local<FunctionTemplate> templ = FunctionTemplate::New();
17431  Local<ObjectTemplate> inst = templ->InstanceTemplate();
17433  inst->SetAccessor(v8_str("foo"),
17434  InstanceCheckedGetter, InstanceCheckedSetter,
17435  Handle<Value>(),
17436  v8::DEFAULT,
17437  v8::None,
17439  context->Global()->Set(v8_str("f"), templ->GetFunction());
17440 
17441  printf("Testing positive ...\n");
17442  CompileRun("var obj = new f();");
17443  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17444  CheckInstanceCheckedAccessors(true);
17445 
17446  printf("Testing negative ...\n");
17447  CompileRun("var obj = {};"
17448  "obj.__proto__ = new f();");
17449  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17450  CheckInstanceCheckedAccessors(false);
17451 }
17452 
17453 
17454 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17455  v8::internal::FLAG_allow_natives_syntax = true;
17456  v8::HandleScope scope;
17457  LocalContext context;
17458 
17459  Local<FunctionTemplate> templ = FunctionTemplate::New();
17460  Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17461  proto->SetAccessor(v8_str("foo"),
17462  InstanceCheckedGetter, InstanceCheckedSetter,
17463  Handle<Value>(),
17464  v8::DEFAULT,
17465  v8::None,
17467  context->Global()->Set(v8_str("f"), templ->GetFunction());
17468 
17469  printf("Testing positive ...\n");
17470  CompileRun("var obj = new f();");
17471  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17472  CheckInstanceCheckedAccessors(true);
17473 
17474  printf("Testing negative ...\n");
17475  CompileRun("var obj = {};"
17476  "obj.__proto__ = new f();");
17477  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17478  CheckInstanceCheckedAccessors(false);
17479 
17480  printf("Testing positive with modified prototype chain ...\n");
17481  CompileRun("var obj = new f();"
17482  "var pro = {};"
17483  "pro.__proto__ = obj.__proto__;"
17484  "obj.__proto__ = pro;");
17485  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17486  CheckInstanceCheckedAccessors(true);
17487 }
17488 
17489 
17490 TEST(TryFinallyMessage) {
17491  v8::HandleScope scope;
17492  LocalContext context;
17493  {
17494  // Test that the original error message is not lost if there is a
17495  // recursive call into Javascript is done in the finally block, e.g. to
17496  // initialize an IC. (crbug.com/129171)
17497  TryCatch try_catch;
17498  const char* trigger_ic =
17499  "try { \n"
17500  " throw new Error('test'); \n"
17501  "} finally { \n"
17502  " var x = 0; \n"
17503  " x++; \n" // Trigger an IC initialization here.
17504  "} \n";
17505  CompileRun(trigger_ic);
17506  CHECK(try_catch.HasCaught());
17507  Local<Message> message = try_catch.Message();
17508  CHECK(!message.IsEmpty());
17509  CHECK_EQ(2, message->GetLineNumber());
17510  }
17511 
17512  {
17513  // Test that the original exception message is indeed overwritten if
17514  // a new error is thrown in the finally block.
17515  TryCatch try_catch;
17516  const char* throw_again =
17517  "try { \n"
17518  " throw new Error('test'); \n"
17519  "} finally { \n"
17520  " var x = 0; \n"
17521  " x++; \n"
17522  " throw new Error('again'); \n" // This is the new uncaught error.
17523  "} \n";
17524  CompileRun(throw_again);
17525  CHECK(try_catch.HasCaught());
17526  Local<Message> message = try_catch.Message();
17527  CHECK(!message.IsEmpty());
17528  CHECK_EQ(6, message->GetLineNumber());
17529  }
17530 }
17531 
17532 
17533 static void Helper137002(bool do_store,
17534  bool polymorphic,
17535  bool remove_accessor,
17536  bool interceptor) {
17537  LocalContext context;
17538  Local<ObjectTemplate> templ = ObjectTemplate::New();
17539  if (interceptor) {
17540  templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17541  } else {
17542  templ->SetAccessor(v8_str("foo"),
17543  GetterWhichReturns42,
17544  SetterWhichSetsYOnThisTo23);
17545  }
17546  context->Global()->Set(v8_str("obj"), templ->NewInstance());
17547 
17548  // Turn monomorphic on slow object with native accessor, then turn
17549  // polymorphic, finally optimize to create negative lookup and fail.
17550  CompileRun(do_store ?
17551  "function f(x) { x.foo = void 0; }" :
17552  "function f(x) { return x.foo; }");
17553  CompileRun("obj.y = void 0;");
17554  if (!interceptor) {
17555  CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17556  }
17557  CompileRun("obj.__proto__ = null;"
17558  "f(obj); f(obj); f(obj);");
17559  if (polymorphic) {
17560  CompileRun("f({});");
17561  }
17562  CompileRun("obj.y = void 0;"
17563  "%OptimizeFunctionOnNextCall(f);");
17564  if (remove_accessor) {
17565  CompileRun("delete obj.foo;");
17566  }
17567  CompileRun("var result = f(obj);");
17568  if (do_store) {
17569  CompileRun("result = obj.y;");
17570  }
17571  if (remove_accessor && !interceptor) {
17572  CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17573  } else {
17574  CHECK_EQ(do_store ? 23 : 42,
17575  context->Global()->Get(v8_str("result"))->Int32Value());
17576  }
17577 }
17578 
17579 
17580 THREADED_TEST(Regress137002a) {
17581  i::FLAG_allow_natives_syntax = true;
17582  i::FLAG_compilation_cache = false;
17583  v8::HandleScope scope;
17584  for (int i = 0; i < 16; i++) {
17585  Helper137002(i & 8, i & 4, i & 2, i & 1);
17586  }
17587 }
17588 
17589 
17590 THREADED_TEST(Regress137002b) {
17591  i::FLAG_allow_natives_syntax = true;
17592  v8::HandleScope scope;
17593  LocalContext context;
17594  Local<ObjectTemplate> templ = ObjectTemplate::New();
17595  templ->SetAccessor(v8_str("foo"),
17596  GetterWhichReturns42,
17597  SetterWhichSetsYOnThisTo23);
17598  context->Global()->Set(v8_str("obj"), templ->NewInstance());
17599 
17600  // Turn monomorphic on slow object with native accessor, then just
17601  // delete the property and fail.
17602  CompileRun("function load(x) { return x.foo; }"
17603  "function store(x) { x.foo = void 0; }"
17604  "function keyed_load(x, key) { return x[key]; }"
17605  // Second version of function has a different source (add void 0)
17606  // so that it does not share code with the first version. This
17607  // ensures that the ICs are monomorphic.
17608  "function load2(x) { void 0; return x.foo; }"
17609  "function store2(x) { void 0; x.foo = void 0; }"
17610  "function keyed_load2(x, key) { void 0; return x[key]; }"
17611 
17612  "obj.y = void 0;"
17613  "obj.__proto__ = null;"
17614  "var subobj = {};"
17615  "subobj.y = void 0;"
17616  "subobj.__proto__ = obj;"
17617  "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17618 
17619  // Make the ICs monomorphic.
17620  "load(obj); load(obj);"
17621  "load2(subobj); load2(subobj);"
17622  "store(obj); store(obj);"
17623  "store2(subobj); store2(subobj);"
17624  "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
17625  "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
17626 
17627  // Actually test the shiny new ICs and better not crash. This
17628  // serves as a regression test for issue 142088 as well.
17629  "load(obj);"
17630  "load2(subobj);"
17631  "store(obj);"
17632  "store2(subobj);"
17633  "keyed_load(obj, 'foo');"
17634  "keyed_load2(subobj, 'foo');"
17635 
17636  // Delete the accessor. It better not be called any more now.
17637  "delete obj.foo;"
17638  "obj.y = void 0;"
17639  "subobj.y = void 0;"
17640 
17641  "var load_result = load(obj);"
17642  "var load_result2 = load2(subobj);"
17643  "var keyed_load_result = keyed_load(obj, 'foo');"
17644  "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
17645  "store(obj);"
17646  "store2(subobj);"
17647  "var y_from_obj = obj.y;"
17648  "var y_from_subobj = subobj.y;");
17649  CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
17650  CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
17651  CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
17652  CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
17653  CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
17654  CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
17655 }
17656 
17657 
17658 THREADED_TEST(Regress142088) {
17659  i::FLAG_allow_natives_syntax = true;
17660  v8::HandleScope scope;
17661  LocalContext context;
17662  Local<ObjectTemplate> templ = ObjectTemplate::New();
17663  templ->SetAccessor(v8_str("foo"),
17664  GetterWhichReturns42,
17665  SetterWhichSetsYOnThisTo23);
17666  context->Global()->Set(v8_str("obj"), templ->NewInstance());
17667 
17668  CompileRun("function load(x) { return x.foo; }"
17669  "var o = Object.create(obj);"
17670  "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17671  "load(o); load(o); load(o); load(o);");
17672 }
17673 
17674 
17675 THREADED_TEST(Regress137496) {
17676  i::FLAG_expose_gc = true;
17677  v8::HandleScope scope;
17678  LocalContext context;
17679 
17680  // Compile a try-finally clause where the finally block causes a GC
17681  // while there still is a message pending for external reporting.
17682  TryCatch try_catch;
17683  try_catch.SetVerbose(true);
17684  CompileRun("try { throw new Error(); } finally { gc(); }");
17685  CHECK(try_catch.HasCaught());
17686 }
17687 
17688 
17689 THREADED_TEST(Regress149912) {
17690  v8::HandleScope scope;
17691  LocalContext context;
17692  Handle<FunctionTemplate> templ = FunctionTemplate::New();
17694  context->Global()->Set(v8_str("Bug"), templ->GetFunction());
17695  CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
17696 }
17697 
17698 
17699 THREADED_TEST(Regress157124) {
17700  v8::HandleScope scope;
17701  LocalContext context;
17702  Local<ObjectTemplate> templ = ObjectTemplate::New();
17703  Local<Object> obj = templ->NewInstance();
17704  obj->GetIdentityHash();
17705  obj->DeleteHiddenValue(v8_str("Bug"));
17706 }
17707 
17708 
17709 #ifndef WIN32
17711  public:
17712  ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17713  ~ThreadInterruptTest() { delete sem_; }
17714 
17715  void RunTest() {
17716  sem_ = i::OS::CreateSemaphore(0);
17717 
17718  InterruptThread i_thread(this);
17719  i_thread.Start();
17720 
17721  sem_->Wait();
17722  CHECK_EQ(kExpectedValue, sem_value_);
17723  }
17724 
17725  private:
17726  static const int kExpectedValue = 1;
17727 
17728  class InterruptThread : public i::Thread {
17729  public:
17730  explicit InterruptThread(ThreadInterruptTest* test)
17731  : Thread("InterruptThread"), test_(test) {}
17732 
17733  virtual void Run() {
17734  struct sigaction action;
17735 
17736  // Ensure that we'll enter waiting condition
17737  i::OS::Sleep(100);
17738 
17739  // Setup signal handler
17740  memset(&action, 0, sizeof(action));
17741  action.sa_handler = SignalHandler;
17742  sigaction(SIGCHLD, &action, NULL);
17743 
17744  // Send signal
17745  kill(getpid(), SIGCHLD);
17746 
17747  // Ensure that if wait has returned because of error
17748  i::OS::Sleep(100);
17749 
17750  // Set value and signal semaphore
17751  test_->sem_value_ = 1;
17752  test_->sem_->Signal();
17753  }
17754 
17755  static void SignalHandler(int signal) {
17756  }
17757 
17758  private:
17759  ThreadInterruptTest* test_;
17760  struct sigaction sa_;
17761  };
17762 
17763  i::Semaphore* sem_;
17764  volatile int sem_value_;
17765 };
17766 
17767 
17768 THREADED_TEST(SemaphoreInterruption) {
17770 }
17771 #endif // WIN32
static void RunAllTests()
Definition: test-api.cc:10693
Handle< S > As()
Definition: v8.h:253
Handle< v8::Array > NonStrictArgsIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:4119
v8::Handle< Value > keyed_call_ic_function
Definition: test-api.cc:10007
static Isolate * GetCurrent()
Definition: api.cc:5520
void MakeWeak(void *parameters, WeakReferenceCallback callback)
Definition: v8.h:4245
void OOMCallback(const char *location, const char *message)
Definition: test-api.cc:5179
const SwVfpRegister s2
Local< S > As()
Definition: v8.h:291
Handle< Array >(* NamedPropertyEnumerator)(const AccessorInfo &info)
Definition: v8.h:2086
Handle< Value > GetScriptData() const
Definition: api.cc:1810
v8::Persistent< Script > script_
Definition: test-api.cc:5242
v8::Persistent< v8::Object > some_object
Definition: test-api.cc:10962
V8EXPORT double NumberValue() const
Definition: api.cc:2555
static Object * Cast(Value *obj)
Definition: v8.h:4581
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1568
int GetLineNumber() const
Definition: api.cc:2021
void FlattenString(Handle< String > string)
Definition: handles.cc:211
bool IsEval() const
Definition: api.cc:2101
static void AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll)
Definition: api.cc:5413
v8::Persistent< Context > calling_context2
Definition: test-api.cc:12937
V8EXPORT bool HasRealIndexedProperty(uint32_t index)
Definition: api.cc:3144
TestAsciiResourceWithDisposeControl(const char *data, bool dispose)
Definition: test-api.cc:670
void set_max_young_space_size(int value)
Definition: v8.h:2638
virtual ~VisitorImpl()
Definition: test-api.cc:14824
v8::Handle< v8::Array > CheckThisIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:1759
#define CHECK_EQ(expected, value)
Definition: checks.h:219
V8EXPORT bool IsTrue() const
Definition: api.cc:2143
Local< Array > AsArray()
Definition: api.cc:1998
V8EXPORT uint8_t * GetIndexedPropertiesPixelData()
Definition: api.cc:3435
v8::Handle< Value > call_ic_function
Definition: test-api.cc:9247
void StoringErrorCallback(const char *location, const char *message)
Definition: test-api.cc:5146
v8::Handle< v8::Value > Fail(const v8::Arguments &args)
static Local< FunctionTemplate > New(InvocationCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >())
Definition: api.cc:951
v8::Handle< Value > AnalyzeStackOfEvalWithSourceURL(const v8::Arguments &args)
Definition: test-api.cc:14510
V8EXPORT bool DeleteHiddenValue(Handle< String > key)
Definition: api.cc:3336
void Dispose()
Definition: api.cc:5532
Handle< Boolean > V8EXPORT True()
Definition: api.cc:569
V8EXPORT Local< String > GetSource() const
Definition: api.cc:5125
void(* CallCompletedCallback)()
Definition: v8.h:2724
Handle< Value >(* NamedPropertySetter)(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:2061
static void TearDown()
Definition: test-api.cc:10725
void Dispose()
Definition: v8.h:4235
Handle< Value > HasOwnPropertyAccessorGetter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:16594
void Exit()
Definition: api.cc:5549
Thread(const Options &options)
v8::Handle< Value > ThrowFromC(const v8::Arguments &args)
Definition: test-api.cc:3048
void SetSecurityToken(Handle< Value > token)
Definition: api.cc:4485
Local< Value > Exception() const
Definition: api.cc:1720
static MapCache * cast(Object *obj)
void * GetData()
Definition: v8.h:4675
static bool IsInitialized(v8::Isolate *isolate)
Definition: v8.h:4148
void CallCompletedCallbackNoException()
Definition: test-api.cc:17130
void HandleCreatingCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:11019
v8::Persistent< Context > calling_context1
Definition: test-api.cc:12936
V8EXPORT bool StrictEquals(Handle< Value > that) const
Definition: api.cc:2711
Handle< Value > InterceptorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1403
Local< Object > Holder() const
Definition: v8.h:4297
bool IsIndependent() const
Definition: v8.h:4214
static void SetAddHistogramSampleFunction(AddHistogramSampleCallback)
Definition: api.cc:5328
bool HasOutOfMemoryException()
Definition: api.cc:4521
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2853
static Smi * FromInt(int value)
Definition: objects-inl.h:981
V8EXPORT bool IsNativeError() const
Definition: api.cc:2279
void V8EXPORT RegisterExtension(Extension *extension)
Definition: api.cc:526
Local< Object > NewInstance()
Definition: api.cc:4660
void PrologueCallback(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:15374
#define CHECK_GT(a, b)
Definition: checks.h:227
bool HasCaught() const
Definition: api.cc:1703
V8EXPORT Local< Array > GetOwnPropertyNames()
Definition: api.cc:2967
v8::Persistent< v8::Object > to_be_disposed
Definition: test-api.cc:10992
int echo_named_call_count
Definition: test-api.cc:1353
void SimpleAccessorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1372
v8::Handle< v8::Integer > CheckThisIndexedPropertyQuery(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:1724
V8EXPORT bool IsBooleanObject() const
Definition: api.cc:2298
~Whammy()
Definition: test-api.cc:5229
static Handle< T > cast(Handle< S > that)
Definition: handles.h:81
Local< String > Get() const
Definition: api.cc:1781
bool pass_on_get
Definition: test-api.cc:12691
static void SetCaptureStackTraceForUncaughtExceptions(bool capture, int frame_limit=10, StackTrace::StackTraceOptions options=StackTrace::kOverview)
Definition: api.cc:5303
static Array * Cast(Value *obj)
Definition: v8.h:4589
void AllowCodeGenerationFromStrings(bool allow)
Definition: api.cc:4606
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4779
Local< Function > Callee() const
Definition: v8.h:4286
const int kSmiValueSize
Definition: v8.h:4061
int epilogue_call_count
Definition: test-api.cc:15370
void SetData(Handle< String > data)
Definition: api.cc:1660
v8::Handle< Value > AnalyzeStackInNativeCode(const v8::Arguments &args)
Definition: test-api.cc:14223
bool IsAsciiRepresentation()
Definition: objects-inl.h:290
void * new_code_start
Definition: v8.h:2998
UC16VectorResource(i::Vector< const i::uc16 > vector)
Definition: test-api.cc:12400
static ExternalTwoByteString * cast(Object *obj)
void 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)
Definition: test-api.cc:14202
v8::Handle< Value > ProvokeOutOfMemory(const v8::Arguments &args)
Definition: test-api.cc:2762
static V8EXPORT Local< String > NewSymbol(const char *data, int length=-1)
Definition: api.cc:5203
Local< ObjectTemplate > InstanceTemplate()
Definition: api.cc:1122
Handle< Value > FooSetInterceptor(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:15229
size_t used_heap_size()
Definition: v8.h:2776
Handle< Primitive > V8EXPORT Null()
Definition: api.cc:559
v8::Handle< Script > getScript()
Definition: test-api.cc:5232
v8::Persistent< Context > calling_context0
Definition: test-api.cc:12935
int int32_t
Definition: unicode.cc:47
void(* MessageCallback)(Handle< Message > message, Handle< Value > error)
Definition: v8.h:2663
V8EXPORT bool HasRealNamedCallbackProperty(Handle< String > key)
Definition: api.cc:3152
V8EXPORT Local< Value > GetHiddenValue(Handle< String > key)
Definition: api.cc:3322
static Handle< T > Cast(Handle< S > that)
Definition: v8.h:244
static Local< Value > Error(Handle< String > message)
Definition: api.cc:5683
TickSample * sample
void SetIndexedPropertyHandler(IndexedPropertyGetter getter, IndexedPropertySetter setter=0, IndexedPropertyQuery query=0, IndexedPropertyDeleter deleter=0, IndexedPropertyEnumerator enumerator=0, Handle< Value > data=Handle< Value >())
Definition: api.cc:1386
Handle< Object > SetAccessor(Handle< JSObject > obj, Handle< AccessorInfo > info)
Definition: handles.cc:342
V8EXPORT Local< Array > GetPropertyNames()
Definition: api.cc:2946
V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType()
Definition: api.cc:3505
#define CHECK_LT(a, b)
Definition: checks.h:229
V8EXPORT Local< Value > Call(Handle< Object > recv, int argc, Handle< Value > argv[])
Definition: api.cc:3652
THREADED_TEST(Handles)
Definition: test-api.cc:146
V8EXPORT bool IsRegExp() const
Definition: api.cc:2306
virtual void VisitExternalString(v8::Handle< v8::String > string)
Definition: test-api.cc:14825
#define ASSERT(condition)
Definition: checks.h:270
void Clear()
Definition: v8.h:214
static bool AddMessageListener(MessageCallback that)
Definition: api.cc:5273
v8::Handle< Value > WhammyPropertyGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:5251
ApiTestFuzzer * fuzzer_
Definition: cctest.h:155
ExternalArrayType
Definition: v8.h:1431
void CheckProperties(v8::Handle< v8::Value > val, int elmc, const char *elmv[])
Definition: test-api.cc:11553
unsigned short uint16_t
Definition: unicode.cc:46
void DisposingCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:11015
v8::Handle< v8::Value > DirectGetterCallback(Local< String > name, const v8::AccessorInfo &info)
Definition: test-api.cc:9633
V8EXPORT void * GetIndexedPropertiesExternalArrayData()
Definition: api.cc:3492
v8::Handle< Script > call_recursively_script
Definition: test-api.cc:1871
Local< Value > Data() const
Definition: v8.h:4303
static V8EXPORT Local< Value > Wrap(void *data)
Definition: api.cc:4707
Whammy()
Definition: test-api.cc:5226
kPropertyAccessorsOffset kNamedPropertyHandlerOffset instance_template
Definition: objects-inl.h:3860
Local< Value > GetInternalField(int index)
Definition: v8.h:4355
static bool IsEnabled()
Definition: snapshot.h:49
V8EXPORT Local< String > ToString() const
Definition: api.cc:2313
v8::Handle< Value > JSCheck(const v8::Arguments &args)
Definition: test-api.cc:3306
#define CHECK(condition)
Definition: checks.h:56
Handle< Value >(* IndexedPropertySetter)(uint32_t index, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:2101
const Register r2
static intptr_t AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes)
Definition: api.cc:5374
void SetVerbose(bool value)
Definition: api.cc:1768
int isnan(double x)
virtual size_t length() const
Definition: test-api.cc:12403
virtual const char * data() const
Definition: test-api.cc:12392
void Set(Handle< String > name, Handle< Data > value, PropertyAttribute attributes=None)
Definition: api.cc:902
v8::Handle< Value > CThrowCountDown(const v8::Arguments &args)
Definition: test-api.cc:3273
static ExternalAsciiString * cast(Object *obj)
int prologue_call_count
Definition: test-api.cc:15369
#define CHECK_GE(a, b)
Definition: checks.h:228
PropertyAttributes
void NewPersistentHandleCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10965
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback)
Definition: api.cc:5342
static void * Unwrap(Handle< Value > obj)
Definition: v8.h:4382
V8EXPORT void SetIndexedPropertiesToExternalArrayData(void *data, ExternalArrayType array_type, int number_of_elements)
Definition: api.cc:3460
Handle< Value > EmptyInterceptorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1383
V8EXPORT bool Equals(Handle< Value > that) const
Definition: api.cc:2684
V8EXPORT Handle< Value > GetScriptId() const
Definition: api.cc:3733
static void VisitExternalResources(ExternalResourceVisitor *visitor)
Definition: api.cc:4340
static Number * Cast(v8::Value *obj)
Definition: v8.h:4525
v8::Handle< Value > call_ic_function3
Definition: test-api.cc:9249
v8::Handle< Value > AnalyzeStackOfInlineScriptWithSourceURL(const v8::Arguments &args)
Definition: test-api.cc:14549
void CallCompletedCallbackException()
Definition: test-api.cc:17136
void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size)
Definition: test-api.cc:14136
v8::Handle< v8::Value > ThrowingDirectApiCallback(const v8::Arguments &args)
Definition: test-api.cc:9607
Handle< Value > GetScriptResourceName() const
Definition: api.cc:1793
static void AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll)
Definition: api.cc:5399
static Smi * cast(Object *object)
Handle< String > FlattenGetString(Handle< String > string)
Definition: handles.cc:216
V8EXPORT bool IsExternal() const
Definition: api.cc:4064
V8EXPORT bool HasIndexedPropertiesInExternalArrayData()
Definition: api.cc:3483
bool Equals(String *other)
Definition: objects-inl.h:2419
v8::Persistent< Value > xValue
Definition: test-api.cc:3823
V8EXPORT void SetInternalField(int index, Handle< Value > value)
Definition: api.cc:4214
v8::Handle< Value > CheckThisNamedPropertySetter(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1716
void SetClassName(Handle< String > name)
Definition: api.cc:1139
static V8EXPORT Local< Integer > NewFromUnsigned(uint32_t value)
Definition: api.cc:5235
int foo
Handle< Value >(* IndexedPropertyGetter)(uint32_t index, const AccessorInfo &info)
Definition: v8.h:2093
void CheckCodeGenerationAllowed()
Definition: test-api.cc:16673
static v8::Handle< v8::Value > Echo(const v8::Arguments &args)
Definition: test-api.cc:4979
Local< StackFrame > GetFrame(uint32_t index) const
Definition: api.cc:1976
static const char * GetVersion()
Definition: api.cc:4394
V8EXPORT Local< Value > GetRealNamedProperty(Handle< String > key)
Definition: api.cc:3217
Local< Value > Id()
Definition: api.cc:1643
V8EXPORT bool IsExternalAscii() const
Definition: api.cc:4074
V8EXPORT bool IsStringObject() const
Definition: api.cc:2247
uint32_t ComputePointerHash(void *ptr)
Definition: utils.h:311
V8EXPORT ScriptOrigin GetScriptOrigin() const
Definition: api.cc:3697
static Local< Script > New(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1506
TestResource(uint16_t *data, int *counter=NULL)
Definition: test-api.cc:343
v8::Handle< Value > CCatcher(const v8::Arguments &args)
Definition: test-api.cc:3054
const SwVfpRegister s3
size_t length() const
Definition: test-api.cc:357
const int MB
Definition: d8.cc:124
V8EXPORT int InternalFieldCount()
Definition: api.cc:4185
#define UNREACHABLE()
Definition: checks.h:50
Handle< Value >(* InvocationCallback)(const Arguments &args)
Definition: v8.h:2047
static ScriptData * PreCompile(const char *input, int length)
Definition: api.cc:1462
Handle< Value >(* NamedPropertyGetter)(Local< String > property, const AccessorInfo &info)
Definition: v8.h:2053
const char * name()
Definition: cctest.h:156
virtual const char * Data()=0
V8EXPORT void * Value() const
Definition: api.cc:4762
void CheckCodeGenerationDisallowed()
Definition: test-api.cc:16683
T * start() const
Definition: utils.h:390
static void RemoveCallCompletedCallback(CallCompletedCallback callback)
Definition: api.cc:5454
v8::Handle< Value > CheckThisIndexedPropertySetter(uint32_t index, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1707
void set_max_old_space_size(int value)
Definition: v8.h:2640
Handle< Value > RecursiveCall(const Arguments &args)
Definition: test-api.cc:17078
static Local< ObjectTemplate > New()
Definition: api.cc:1253
virtual bool HasError()=0
V8EXPORT bool HasIndexedPropertiesInPixelData()
Definition: api.cc:3427
void DetachGlobal()
Definition: api.cc:4582
Handle< Value > HasOwnPropertyIndexedPropertyGetter(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:16559
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:15382
Handle< Value > ReThrow()
Definition: api.cc:1713
static void Fuzz()
Definition: test-api.cc:10620
V8EXPORT Local< Value > GetPrototype()
Definition: api.cc:2900
static void GetHeapStatistics(HeapStatistics *heap_statistics)
Definition: api.cc:4321
static bool IsValid(intptr_t value)
Definition: objects-inl.h:1059
void set_resource(const Resource *buffer)
Definition: objects-inl.h:2618
EventType type
Definition: v8.h:2982
TEST(MakingExternalStringConditions)
Definition: test-api.cc:506
V8EXPORT bool ForceDelete(Handle< Value > key)
Definition: api.cc:2829
bool ToArrayIndex(uint32_t *index)
Definition: objects-inl.h:1682
v8::Handle< v8::Object > bottom
Definition: test-api.cc:1688
void CallCompletedCallback1()
Definition: test-api.cc:17066
TestAsciiResource(const char *data, int *counter=NULL)
Definition: test-api.cc:369
static const int kNoGCFlags
Definition: heap.h:1081
int p_getter_count
Definition: test-api.cc:5593
virtual ~AsciiVectorResource()
Definition: test-api.cc:12390
void SetAccessor(Handle< String > name, AccessorGetter getter, AccessorSetter setter=0, Handle< Value > data=Handle< Value >(), AccessControl settings=DEFAULT, PropertyAttribute attribute=None, Handle< AccessorSignature > signature=Handle< AccessorSignature >())
Definition: api.cc:1291
uint32_t occupancy() const
Definition: hashmap.h:83
v8::Handle< v8::Value > DirectApiCallback(const v8::Arguments &args)
Definition: test-api.cc:9577
void SetInternalFieldCount(int value)
Definition: api.cc:1438
int NumberOfWeakCalls()
Definition: test-api.cc:2260
Handle< v8::Integer > HasOwnPropertyNamedPropertyQuery(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:16580
int GetColumn() const
Definition: api.cc:2037
int index_
Definition: test-api.cc:5221
static Isolate * New()
Definition: api.cc:5526
void SimulateFullSpace(i::PagedSpace *space)
Definition: test-alloc.cc:38
static void SetFatalErrorHandler(FatalErrorCallback that)
Definition: api.cc:455
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random allows verbose printing trace parsing and preparsing Check icache flushes in ARM and MIPS simulator Stack alingment in bytes in print stack trace when throwing exceptions randomize hashes to avoid predictable hash Fixed seed to use to hash property activate a timer that switches between V8 threads testing_bool_flag float flag Seed used for threading test randomness A filename with extra code to be included in the Print usage message
static int ContextDisposedNotification()
Definition: api.cc:4387
bool CodeGenerationDisallowed(Local< Context > context)
Definition: test-api.cc:16708
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook)
Definition: api.cc:4289
int Length() const
Definition: v8.h:4318
V8EXPORT int32_t Int32Value() const
Definition: api.cc:2662
v8::Handle< Value >(* NamedPropertyGetter)(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:8798
void(* AccessorSetter)(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:1452
V8EXPORT Local< Object > NewInstance() const
Definition: api.cc:3628
IsolateThread(v8::Isolate *isolate, int fib_limit)
Definition: test-api.cc:15946
bool IsConstructor() const
Definition: api.cc:2112
Entry * Lookup(void *key, uint32_t hash, bool insert, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:131
Local< Object > Global()
Definition: api.cc:4570
static FunctionTemplateInfo * cast(Object *obj)
V8EXPORT void SetIndexedPropertiesToPixelData(uint8_t *data, int length)
Definition: api.cc:3407
V8EXPORT void TurnOnAccessCheck()
Definition: api.cc:3233
int prologue_call_count_second
Definition: test-api.cc:15371
int length() const
Definition: utils.h:384
v8::Persistent< v8::Object > object_
Definition: test-api.cc:16288
V8EXPORT int GetScriptColumnNumber() const
Definition: api.cc:3724
void Enter()
Definition: api.cc:5543
static void RemoveMessageListeners(MessageCallback that)
Definition: api.cc:5285
GCType
Definition: v8.h:2748
static MUST_USE_RESULT Handle< Object > SetElement(Handle< JSObject > object, uint32_t index, Handle< Object > value, PropertyAttributes attr, StrictModeFlag strict_mode, SetPropertyMode set_mode=SET_PROPERTY)
Definition: objects.cc:9886
V8EXPORT bool Has(Handle< String > key)
Definition: api.cc:3075
const uint16_t * data() const
Definition: test-api.cc:353
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:3559
void increment()
Definition: test-api.cc:2259
V8EXPORT bool SetHiddenValue(Handle< String > key, Handle< Value > value)
Definition: api.cc:3305
void set_stack_limit(uint32_t *value)
Definition: v8.h:2645
static Persistent< T > New(Handle< T > that)
Definition: v8.h:4206
const SwVfpRegister s0
static const int kMakeHeapIterableMask
Definition: heap.h:1088
uint8_t callback_fired
Definition: test-api.cc:17063
AccessType
Definition: v8.h:2131
virtual void Run()
Definition: test-api.cc:10648
void FailedAccessCheckCallbackGC(Local< v8::Object > target, v8::AccessType type, Local< v8::Value > data)
Definition: test-api.cc:15630
activate correct semantics for inheriting readonliness false
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
V8EXPORT bool BooleanValue() const
Definition: api.cc:2540
void set_resource(const Resource *buffer)
Definition: objects-inl.h:2650
const FPURegister f2
size_t length() const
Definition: test-api.cc:381
v8::Handle< v8::Array > CheckThisNamedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:1767
Handle< Value > FooGetInterceptor(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:15220
Handle< Value > HasOwnPropertyNamedPropertyGetter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:16566
virtual void VisitPersistentHandle(Persistent< Value > value, uint16_t class_id)
Definition: test-api.cc:16275
bool IsUndefined() const
Definition: v8.h:4472
void(* WeakReferenceCallback)(Persistent< Value > object, void *parameter)
Definition: v8.h:138
int GetLineNumber() const
Definition: api.cc:1873
Handle< v8::Integer > HasOwnPropertyIndexedPropertyQuery(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:16573
static Local< Value > RangeError(Handle< String > message)
Definition: api.cc:5618
#define CHECK_NE(unexpected, value)
Definition: checks.h:223
Handle< Boolean > V8EXPORT False()
Definition: api.cc:579
static void Sleep(const int milliseconds)
static const int kAbortIncrementalMarkingMask
Definition: heap.h:1084
Vector< const char > CStrVector(const char *data)
Definition: utils.h:526
int StrLength(const char *string)
Definition: utils.h:234
static Local< Context > ToLocal(v8::internal::Handle< v8::internal::Context > obj)
#define CHECK_LE(a, b)
Definition: checks.h:230
void SetNamedPropertyHandler(NamedPropertyGetter getter, NamedPropertySetter setter=0, NamedPropertyQuery query=0, NamedPropertyDeleter deleter=0, NamedPropertyEnumerator enumerator=0, Handle< Value > data=Handle< Value >())
Definition: api.cc:1316
v8::Handle< Value > HandleF(const v8::Arguments &args)
Definition: test-api.cc:2632
static void Print(const char *format,...)
Local< Object > This() const
Definition: v8.h:4292
#define T(name, string, precedence)
Definition: token.cc:48
static void AddCallCompletedCallback(CallCompletedCallback callback)
Definition: api.cc:5445
Definition: v8.h:1744
Local< String > GetScriptName() const
Definition: api.cc:2053
v8::Handle< v8::Value > ThrowingDirectGetterCallback(Local< String > name, const v8::AccessorInfo &info)
Definition: test-api.cc:9659
bool IsString() const
Definition: v8.h:4508
const SwVfpRegister s1
static Local< Object > Cast(Local< S > that)
Definition: v8.h:282
V8EXPORT bool IsObject() const
Definition: api.cc:2177
v8::Handle< v8::Boolean > CheckThisIndexedPropertyDeleter(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:1741
Definition: v8.h:1425
V8EXPORT double Value() const
Definition: api.cc:4138
bool IsCodeGenerationFromStringsAllowed()
Definition: api.cc:4620
static Local< Value > ReferenceError(Handle< String > message)
Definition: api.cc:5634
virtual ~UC16VectorResource()
Definition: test-api.cc:12402
static int SNPrintF(Vector< char > str, const char *format,...)
Local< Value > StackTrace() const
Definition: api.cc:1732
static V8EXPORT v8::Local< v8::String > Empty()
Definition: api.cc:4769
static Semaphore * CreateSemaphore(int count)
#define ISOLATE
Definition: isolate.h:1435
int ToNumber(Register reg)
V8EXPORT bool IsDate() const
Definition: api.cc:2239
void AddInterceptor(Handle< FunctionTemplate > templ, v8::NamedPropertyGetter getter, v8::NamedPropertySetter setter)
Definition: test-api.cc:1422
v8::Handle< v8::Value > Version(const v8::Arguments &args)
Definition: shell.cc:191
v8::Handle< Value > ThrowValue(const v8::Arguments &args)
Definition: test-api.cc:3413
static int NumberOfHandles()
Definition: api.cc:723
static void WriteToFlat(String *source, sinkchar *sink, int from, int to)
Definition: objects.cc:6891
V8EXPORT int GetIndexedPropertiesExternalArrayDataLength()
Definition: api.cc:3535
const Register r1
V8EXPORT uint32_t Uint32Value() const
Definition: api.cc:2743
static double nan_value()
static Local< AccessorSignature > New(Handle< FunctionTemplate > receiver=Handle< FunctionTemplate >())
Definition: api.cc:1001
void AddAccessor(Handle< FunctionTemplate > templ, Handle< String > name, v8::AccessorGetter getter, v8::AccessorSetter setter)
Definition: test-api.cc:1415
VisitorImpl(TestResource *r1, TestResource *r2)
Definition: test-api.cc:14819
bool is_null() const
Definition: handles.h:87
struct v8::JitCodeEvent::@0::@2 name
V8EXPORT bool IsNumber() const
Definition: api.cc:2183
int cursor_
Definition: test-api.cc:5240
void CallCompletedCallback2()
Definition: test-api.cc:17072
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:15378
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< String > name)
Definition: test-api.cc:5097
v8::Handle< Value > AnalyzeStackOfDynamicScriptWithSourceURL(const v8::Arguments &args)
Definition: test-api.cc:14591
V8EXPORT Local< String > StringValue() const
Definition: api.cc:5022
Local< Function > GetFunction()
Definition: api.cc:4675
void CheckVisitedResources()
Definition: test-api.cc:14842
static RegisterThreadedTest * nth(int i)
Definition: cctest.h:145
uint16_t uc16
Definition: globals.h:259
V8EXPORT bool ForceSet(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2807
void DisposeAndForceGcCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10994
V8EXPORT bool Delete(Handle< String > key)
Definition: api.cc:3064
int GetUtf8Length(Handle< String > str)
Definition: test-api.cc:5713
static Local< Value > SyntaxError(Handle< String > message)
Definition: api.cc:5651
V8EXPORT Local< Object > Clone()
Definition: api.cc:3256
virtual int Length()=0
virtual void Signal()=0
kPropertyAccessorsOffset kNamedPropertyHandlerOffset kInstanceTemplateOffset kAccessCheckInfoOffset kEvalFrominstructionsOffsetOffset kInstanceClassNameOffset hidden_prototype
Definition: objects-inl.h:3923
v8::Persistent< v8::Object > bad_handle
Definition: test-api.cc:10963
void CheckOwnProperties(v8::Handle< v8::Value > val, int elmc, const char *elmv[])
Definition: test-api.cc:11564
virtual const i::uc16 * data() const
Definition: test-api.cc:12404
V8EXPORT bool SetAccessor(Handle< String > name, AccessorGetter getter, AccessorSetter setter=0, Handle< Value > data=Handle< Value >(), AccessControl settings=DEFAULT, PropertyAttribute attribute=None)
Definition: api.cc:3104
ApiTestFuzzer(int num)
Definition: cctest.h:90
Handle< Value > InterceptorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1389
void * Remove(void *key, uint32_t hash)
Definition: hashmap.h:162
AsciiVectorResource(i::Vector< const char > vector)
Definition: test-api.cc:12388
const char * data() const
Definition: test-api.cc:377
V8EXPORT int GetIndexedPropertiesPixelDataLength()
Definition: api.cc:3448
WeakCallCounter(int id)
Definition: test-api.cc:2257
Local< ObjectTemplate > PrototypeTemplate()
Definition: api.cc:928
#define HEAP
Definition: isolate.h:1433
int global_index
Definition: test-api.cc:5216
V8EXPORT bool IsFalse() const
Definition: api.cc:2149
v8::Handle< v8::Boolean > CheckThisNamedPropertyDeleter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:1750
static void VisitHandlesWithClassIds(PersistentHandleVisitor *visitor)
Definition: api.cc:4347
V8EXPORT Flags GetFlags() const
Definition: api.cc:5145
static Persistent< T > Cast(Persistent< S > that)
Definition: v8.h:358
const FPURegister f1
int counter_
Definition: test-api.cc:16287
static Local< Value > TypeError(Handle< String > message)
Definition: api.cc:5667
static Local< Signature > New(Handle< FunctionTemplate > receiver=Handle< FunctionTemplate >(), int argc=0, Handle< FunctionTemplate > argv[]=0)
Definition: api.cc:978
Definition: v8.h:1812
void USE(T)
Definition: globals.h:289
const SwVfpRegister s4
static V8EXPORT Local< Integer > New(int32_t value)
Definition: api.cc:5228
V8EXPORT int GetScriptLineNumber() const
Definition: api.cc:3714
virtual size_t length() const
Definition: test-api.cc:12391
static void RemoveGCEpilogueCallback(GCEpilogueCallback callback)
Definition: api.cc:5420
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Handle< StackTrace > GetStackTrace() const
Definition: api.cc:1827
InitDefaultIsolateThread(TestCase testCase)
Definition: test-api.cc:16026
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< v8::String > name)
Definition: test-api.cc:4974
static void StartPreemption(int every_n_ms)
Definition: v8threads.cc:142
static void SetCreateHistogramFunction(CreateHistogramCallback)
Definition: api.cc:5320
Local< T > Close(Handle< T > value)
Definition: v8.h:4324
V8EXPORT bool IsNumberObject() const
Definition: api.cc:2255
static void RemoveGCPrologueCallback(GCPrologueCallback callback)
Definition: api.cc:5406
static bool ReportApiFailure(const char *location, const char *message)
Definition: api.cc:220
Handle< Primitive > V8EXPORT Undefined()
Definition: api.cc:549
static V8EXPORT Local< Number > New(double value)
Definition: api.cc:5215
v8::Handle< v8::Value > WithTryCatch(const v8::Arguments &args)
Definition: test-api.cc:3483
virtual void Wait()=0
bool IsEmpty() const
Definition: v8.h:209
Local< Value > Run()
Definition: api.cc:1598
#define FACTORY
Definition: isolate.h:1434
int echo_indexed_call_count
Definition: test-api.cc:1662
V8EXPORT double NumberValue() const
Definition: api.cc:4979
bool CodeGenerationAllowed(Local< Context > context)
Definition: test-api.cc:16702
GCCallbackFlags
Definition: v8.h:2754
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
CcTest::TestFunction * callback()
Definition: cctest.h:154
static Local< StackTrace > CurrentStackTrace(int frame_limit, StackTraceOptions options=kOverview)
Definition: api.cc:2006
static Local< TypeSwitch > New(Handle< FunctionTemplate > type)
Definition: api.cc:1007
void CallTest()
Definition: test-api.cc:10759
int epilogue_call_count_second
Definition: test-api.cc:15372
char * StrDup(const char *str)
Definition: allocation.cc:85
V8EXPORT uint32_t Length() const
Definition: api.cc:5168
bool message_received
Definition: test-api.cc:2455
static ScriptData * New(const char *data, int length)
Definition: api.cc:1482
static V8EXPORT Local< External > New(void *value)
Definition: api.cc:4752
Isolate * GetIsolate() const
Definition: v8.h:4308
V8EXPORT bool IsInt32() const
Definition: api.cc:2205
v8::Local< v8::Context > local()
Definition: cctest.h:187
int bar
Handle< Object > SetPrototype(Handle< JSFunction > function, Handle< Object > prototype)
Definition: handles.cc:221
V8EXPORT bool HasRealNamedProperty(Handle< String > key)
Definition: api.cc:3135
static Handle< Boolean > New(bool value)
Definition: v8.h:4345
size_t total_heap_size()
Definition: v8.h:2774
Handle< v8::Array > UnboxedDoubleIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:4080
static void SetUp(PartOfTest part)
Definition: test-api.cc:10672
static V8EXPORT Local< String > NewExternal(ExternalStringResource *resource)
Definition: api.cc:4871
int p_getter_count2
Definition: test-api.cc:5594
void DeleteArray(T *array)
Definition: allocation.h:91
bool V8EXPORT SetResourceConstraints(ResourceConstraints *constraints)
Definition: api.cc:596
V8EXPORT Handle< Value > GetInferredName() const
Definition: api.cc:3691
void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type)
Definition: test-api.cc:14105
static ConsString * cast(Object *obj)
void ClearWeak()
Definition: v8.h:4252
void MarkIndependent()
Definition: v8.h:4257
static void StopPreemption()
Definition: v8threads.cc:147
Handle< Value > V8EXPORT ThrowException(Handle< Value > exception)
Definition: api.cc:486
void SetData(void *data)
Definition: v8.h:4669
static const int kMaxValue
Definition: objects.h:1050
void * code_start
Definition: v8.h:2984
bool IsConstructCall() const
Definition: v8.h:4313
void Reset()
Definition: api.cc:1761
Handle< Value >(* AccessorGetter)(Local< String > property, const AccessorInfo &info)
Definition: v8.h:1448
v8::Handle< Function > args_fun
Definition: test-api.cc:5415
Definition: v8.h:106
void SetErrorMessageForCodeGenerationFromStrings(Handle< String > message)
Definition: api.cc:4634
int match(Handle< Value > value)
Definition: api.cc:1030
Local< v8::Message > Message() const
Definition: api.cc:1750
Handle< Value > EmptyInterceptorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1378
AccessControl
Definition: v8.h:1470
static bool IsLocked(Isolate *isolate=NULL)
Definition: v8threads.cc:88
void Inherit(Handle< FunctionTemplate > parent)
Definition: api.cc:943
Visitor42(v8::Persistent< v8::Object > object)
Definition: test-api.cc:16272
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:15386
v8::Handle< v8::Integer > CheckThisNamedPropertyQuery(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:1733
static bool Initialize()
Definition: api.cc:4269
NativeFunctionExtension(const char *name, const char *source, v8::InvocationCallback fun=&Echo)
Definition: test-api.cc:4968
Local< String > GetFunctionName() const
Definition: api.cc:2085
Local< String > GetSourceLine() const
Definition: api.cc:1948
size_t code_len
Definition: v8.h:2986
static V8EXPORT Local< Object > New()
Definition: api.cc:4957
Handle< v8::Integer > HasOwnPropertyNamedPropertyQuery2(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:16587
Handle< Value > SimpleAccessorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1366
static void SetCounterFunction(CounterLookupCallback)
Definition: api.cc:5314
V8EXPORT Local< Uint32 > ToArrayIndex() const
Definition: api.cc:2633
V8EXPORT int GetIdentityHash()
Definition: api.cc:3295
static int count()
Definition: cctest.h:144
void SetAccessCheckCallbacks(NamedSecurityCallback named_handler, IndexedSecurityCallback indexed_handler, Handle< Value > data=Handle< Value >(), bool turned_on_by_default=true)
Definition: api.cc:1354
V8EXPORT bool Value() const
Definition: api.cc:4145
V8EXPORT bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2765
static const int kObjectCount
Definition: test-api.cc:5239
const char * name() const
Definition: platform.h:484
int GetFrameCount() const
Definition: api.cc:1990
v8::Persistent< v8::Object > objects_[kObjectCount]
Definition: test-api.cc:5241
static bool IdleNotification(int hint=1000)
Definition: api.cc:4371
V8EXPORT double NumberValue() const
Definition: api.cc:5052
v8::Handle< Value > call_ic_function2
Definition: test-api.cc:9248
static void IgnoreOutOfMemoryException()
Definition: api.cc:5268