v8  3.11.10(node0.8.26)
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 #include "v8.h"
31 
32 #include "api.h"
33 #include "isolate.h"
34 #include "compilation-cache.h"
35 #include "execution.h"
36 #include "snapshot.h"
37 #include "platform.h"
38 #include "utils.h"
39 #include "cctest.h"
40 #include "parser.h"
41 #include "unicode-inl.h"
42 
43 static const bool kLogThreading = false;
44 
45 static bool IsNaN(double x) {
46 #ifdef WIN32
47  return _isnan(x);
48 #else
49  return isnan(x);
50 #endif
51 }
52 
53 using ::v8::AccessorInfo;
54 using ::v8::Arguments;
55 using ::v8::Context;
56 using ::v8::Extension;
57 using ::v8::Function;
58 using ::v8::FunctionTemplate;
59 using ::v8::Handle;
60 using ::v8::HandleScope;
61 using ::v8::Local;
62 using ::v8::Message;
65 using ::v8::ObjectTemplate;
66 using ::v8::Persistent;
67 using ::v8::Script;
68 using ::v8::StackTrace;
69 using ::v8::String;
70 using ::v8::TryCatch;
72 using ::v8::V8;
73 using ::v8::Value;
74 
75 
76 static void ExpectString(const char* code, const char* expected) {
77  Local<Value> result = CompileRun(code);
78  CHECK(result->IsString());
79  String::AsciiValue ascii(result);
80  CHECK_EQ(expected, *ascii);
81 }
82 
83 static void ExpectInt32(const char* code, int expected) {
84  Local<Value> result = CompileRun(code);
85  CHECK(result->IsInt32());
86  CHECK_EQ(expected, result->Int32Value());
87 }
88 
89 static void ExpectBoolean(const char* code, bool expected) {
90  Local<Value> result = CompileRun(code);
91  CHECK(result->IsBoolean());
92  CHECK_EQ(expected, result->BooleanValue());
93 }
94 
95 
96 static void ExpectTrue(const char* code) {
97  ExpectBoolean(code, true);
98 }
99 
100 
101 static void ExpectFalse(const char* code) {
102  ExpectBoolean(code, false);
103 }
104 
105 
106 static void ExpectObject(const char* code, Local<Value> expected) {
107  Local<Value> result = CompileRun(code);
108  CHECK(result->Equals(expected));
109 }
110 
111 
112 static void ExpectUndefined(const char* code) {
113  Local<Value> result = CompileRun(code);
114  CHECK(result->IsUndefined());
115 }
116 
117 
118 static int signature_callback_count;
119 static v8::Handle<Value> IncrementingSignatureCallback(
120  const v8::Arguments& args) {
122  signature_callback_count++;
124  for (int i = 0; i < args.Length(); i++)
125  result->Set(v8::Integer::New(i), args[i]);
126  return result;
127 }
128 
129 
130 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
133  for (int i = 0; i < args.Length(); i++) {
134  result->Set(v8::Integer::New(i), args[i]);
135  }
136  return result;
137 }
138 
139 
140 THREADED_TEST(Handles) {
141  v8::HandleScope scope;
142  Local<Context> local_env;
143  {
144  LocalContext env;
145  local_env = env.local();
146  }
147 
148  // Local context should still be live.
149  CHECK(!local_env.IsEmpty());
150  local_env->Enter();
151 
153  CHECK(!undef.IsEmpty());
154  CHECK(undef->IsUndefined());
155 
156  const char* c_source = "1 + 2 + 3";
157  Local<String> source = String::New(c_source);
158  Local<Script> script = Script::Compile(source);
159  CHECK_EQ(6, script->Run()->Int32Value());
160 
161  local_env->Exit();
162 }
163 
164 
165 THREADED_TEST(ReceiverSignature) {
166  v8::HandleScope scope;
167  LocalContext env;
170  fun->PrototypeTemplate()->Set(
171  v8_str("m"),
172  v8::FunctionTemplate::New(IncrementingSignatureCallback,
174  sig));
175  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
176  signature_callback_count = 0;
177  CompileRun(
178  "var o = new Fun();"
179  "o.m();");
180  CHECK_EQ(1, signature_callback_count);
182  sub_fun->Inherit(fun);
183  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
184  CompileRun(
185  "var o = new SubFun();"
186  "o.m();");
187  CHECK_EQ(2, signature_callback_count);
188 
189  v8::TryCatch try_catch;
190  CompileRun(
191  "var o = { };"
192  "o.m = Fun.prototype.m;"
193  "o.m();");
194  CHECK_EQ(2, signature_callback_count);
195  CHECK(try_catch.HasCaught());
196  try_catch.Reset();
198  sub_fun->Inherit(fun);
199  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
200  CompileRun(
201  "var o = new UnrelFun();"
202  "o.m = Fun.prototype.m;"
203  "o.m();");
204  CHECK_EQ(2, signature_callback_count);
205  CHECK(try_catch.HasCaught());
206 }
207 
208 
209 THREADED_TEST(ArgumentSignature) {
210  v8::HandleScope scope;
211  LocalContext env;
213  cons->SetClassName(v8_str("Cons"));
217  v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
218  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
219  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
220 
221  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
222  CHECK(value1->IsTrue());
223 
224  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
225  CHECK(value2->IsTrue());
226 
227  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
228  CHECK(value3->IsTrue());
229 
231  cons1->SetClassName(v8_str("Cons1"));
233  cons2->SetClassName(v8_str("Cons2"));
235  cons3->SetClassName(v8_str("Cons3"));
236 
237  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
241  v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
242 
243  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
244  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
245  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
246  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
247  v8::Handle<Value> value4 = CompileRun(
248  "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
249  "'[object Cons1],[object Cons2],[object Cons3]'");
250  CHECK(value4->IsTrue());
251 
252  v8::Handle<Value> value5 = CompileRun(
253  "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
254  CHECK(value5->IsTrue());
255 
256  v8::Handle<Value> value6 = CompileRun(
257  "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
258  CHECK(value6->IsTrue());
259 
260  v8::Handle<Value> value7 = CompileRun(
261  "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
262  "'[object Cons1],[object Cons2],[object Cons3],d';");
263  CHECK(value7->IsTrue());
264 
265  v8::Handle<Value> value8 = CompileRun(
266  "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
267  CHECK(value8->IsTrue());
268 }
269 
270 
271 THREADED_TEST(HulIgennem) {
272  v8::HandleScope scope;
273  LocalContext env;
275  Local<String> undef_str = undef->ToString();
276  char* value = i::NewArray<char>(undef_str->Length() + 1);
277  undef_str->WriteAscii(value);
278  CHECK_EQ(0, strcmp(value, "undefined"));
279  i::DeleteArray(value);
280 }
281 
282 
283 THREADED_TEST(Access) {
284  v8::HandleScope scope;
285  LocalContext env;
286  Local<v8::Object> obj = v8::Object::New();
287  Local<Value> foo_before = obj->Get(v8_str("foo"));
288  CHECK(foo_before->IsUndefined());
289  Local<String> bar_str = v8_str("bar");
290  obj->Set(v8_str("foo"), bar_str);
291  Local<Value> foo_after = obj->Get(v8_str("foo"));
292  CHECK(!foo_after->IsUndefined());
293  CHECK(foo_after->IsString());
294  CHECK_EQ(bar_str, foo_after);
295 }
296 
297 
298 THREADED_TEST(AccessElement) {
299  v8::HandleScope scope;
300  LocalContext env;
301  Local<v8::Object> obj = v8::Object::New();
302  Local<Value> before = obj->Get(1);
303  CHECK(before->IsUndefined());
304  Local<String> bar_str = v8_str("bar");
305  obj->Set(1, bar_str);
306  Local<Value> after = obj->Get(1);
307  CHECK(!after->IsUndefined());
308  CHECK(after->IsString());
309  CHECK_EQ(bar_str, after);
310 
311  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
312  CHECK_EQ(v8_str("a"), value->Get(0));
313  CHECK_EQ(v8_str("b"), value->Get(1));
314 }
315 
316 
317 THREADED_TEST(Script) {
318  v8::HandleScope scope;
319  LocalContext env;
320  const char* c_source = "1 + 2 + 3";
321  Local<String> source = String::New(c_source);
322  Local<Script> script = Script::Compile(source);
323  CHECK_EQ(6, script->Run()->Int32Value());
324 }
325 
326 
327 static uint16_t* AsciiToTwoByteString(const char* source) {
328  int array_length = i::StrLength(source) + 1;
329  uint16_t* converted = i::NewArray<uint16_t>(array_length);
330  for (int i = 0; i < array_length; i++) converted[i] = source[i];
331  return converted;
332 }
333 
334 
335 class TestResource: public String::ExternalStringResource {
336  public:
337  explicit TestResource(uint16_t* data, int* counter = NULL)
338  : data_(data), length_(0), counter_(counter) {
339  while (data[length_]) ++length_;
340  }
341 
343  i::DeleteArray(data_);
344  if (counter_ != NULL) ++*counter_;
345  }
346 
347  const uint16_t* data() const {
348  return data_;
349  }
350 
351  size_t length() const {
352  return length_;
353  }
354  private:
355  uint16_t* data_;
356  size_t length_;
357  int* counter_;
358 };
359 
360 
361 class TestAsciiResource: public String::ExternalAsciiStringResource {
362  public:
363  explicit TestAsciiResource(const char* data, int* counter = NULL)
364  : data_(data), length_(strlen(data)), counter_(counter) { }
365 
367  i::DeleteArray(data_);
368  if (counter_ != NULL) ++*counter_;
369  }
370 
371  const char* data() const {
372  return data_;
373  }
374 
375  size_t length() const {
376  return length_;
377  }
378  private:
379  const char* data_;
380  size_t length_;
381  int* counter_;
382 };
383 
384 
385 THREADED_TEST(ScriptUsingStringResource) {
386  int dispose_count = 0;
387  const char* c_source = "1 + 2 * 3";
388  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
389  {
390  v8::HandleScope scope;
391  LocalContext env;
392  TestResource* resource = new TestResource(two_byte_source, &dispose_count);
393  Local<String> source = String::NewExternal(resource);
394  Local<Script> script = Script::Compile(source);
395  Local<Value> value = script->Run();
396  CHECK(value->IsNumber());
397  CHECK_EQ(7, value->Int32Value());
398  CHECK(source->IsExternal());
399  CHECK_EQ(resource,
400  static_cast<TestResource*>(source->GetExternalStringResource()));
401  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
402  CHECK_EQ(0, dispose_count);
403  }
404  v8::internal::Isolate::Current()->compilation_cache()->Clear();
405  HEAP->CollectAllAvailableGarbage();
406  CHECK_EQ(1, dispose_count);
407 }
408 
409 
410 THREADED_TEST(ScriptUsingAsciiStringResource) {
411  int dispose_count = 0;
412  const char* c_source = "1 + 2 * 3";
413  {
414  v8::HandleScope scope;
415  LocalContext env;
416  Local<String> source =
417  String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
418  &dispose_count));
419  Local<Script> script = Script::Compile(source);
420  Local<Value> value = script->Run();
421  CHECK(value->IsNumber());
422  CHECK_EQ(7, value->Int32Value());
423  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
424  CHECK_EQ(0, dispose_count);
425  }
426  i::Isolate::Current()->compilation_cache()->Clear();
427  HEAP->CollectAllAvailableGarbage();
428  CHECK_EQ(1, dispose_count);
429 }
430 
431 
432 THREADED_TEST(ScriptMakingExternalString) {
433  int dispose_count = 0;
434  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
435  {
436  v8::HandleScope scope;
437  LocalContext env;
438  Local<String> source = String::New(two_byte_source);
439  // Trigger GCs so that the newly allocated string moves to old gen.
440  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
441  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
442  bool success = source->MakeExternal(new TestResource(two_byte_source,
443  &dispose_count));
444  CHECK(success);
445  Local<Script> script = Script::Compile(source);
446  Local<Value> value = script->Run();
447  CHECK(value->IsNumber());
448  CHECK_EQ(7, value->Int32Value());
449  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
450  CHECK_EQ(0, dispose_count);
451  }
452  i::Isolate::Current()->compilation_cache()->Clear();
453  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
454  CHECK_EQ(1, dispose_count);
455 }
456 
457 
458 THREADED_TEST(ScriptMakingExternalAsciiString) {
459  int dispose_count = 0;
460  const char* c_source = "1 + 2 * 3";
461  {
462  v8::HandleScope scope;
463  LocalContext env;
464  Local<String> source = v8_str(c_source);
465  // Trigger GCs so that the newly allocated string moves to old gen.
466  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
467  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
468  bool success = source->MakeExternal(
469  new TestAsciiResource(i::StrDup(c_source), &dispose_count));
470  CHECK(success);
471  Local<Script> script = Script::Compile(source);
472  Local<Value> value = script->Run();
473  CHECK(value->IsNumber());
474  CHECK_EQ(7, value->Int32Value());
475  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
476  CHECK_EQ(0, dispose_count);
477  }
478  i::Isolate::Current()->compilation_cache()->Clear();
479  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
480  CHECK_EQ(1, dispose_count);
481 }
482 
483 
484 TEST(MakingExternalStringConditions) {
485  v8::HandleScope scope;
486  LocalContext env;
487 
488  // Free some space in the new space so that we can check freshness.
489  HEAP->CollectGarbage(i::NEW_SPACE);
490  HEAP->CollectGarbage(i::NEW_SPACE);
491 
492  uint16_t* two_byte_string = AsciiToTwoByteString("s1");
493  Local<String> small_string = String::New(two_byte_string);
494  i::DeleteArray(two_byte_string);
495 
496  // We should refuse to externalize newly created small string.
497  CHECK(!small_string->CanMakeExternal());
498  // Trigger GCs so that the newly allocated string moves to old gen.
499  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
500  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
501  // Old space strings should be accepted.
502  CHECK(small_string->CanMakeExternal());
503 
504  two_byte_string = AsciiToTwoByteString("small string 2");
505  small_string = String::New(two_byte_string);
506  i::DeleteArray(two_byte_string);
507 
508  // We should refuse externalizing newly created small string.
509  CHECK(!small_string->CanMakeExternal());
510  for (int i = 0; i < 100; i++) {
511  String::Value value(small_string);
512  }
513  // Frequently used strings should be accepted.
514  CHECK(small_string->CanMakeExternal());
515 
516  const int buf_size = 10 * 1024;
517  char* buf = i::NewArray<char>(buf_size);
518  memset(buf, 'a', buf_size);
519  buf[buf_size - 1] = '\0';
520 
521  two_byte_string = AsciiToTwoByteString(buf);
522  Local<String> large_string = String::New(two_byte_string);
523  i::DeleteArray(buf);
524  i::DeleteArray(two_byte_string);
525  // Large strings should be immediately accepted.
526  CHECK(large_string->CanMakeExternal());
527 }
528 
529 
530 TEST(MakingExternalAsciiStringConditions) {
531  v8::HandleScope scope;
532  LocalContext env;
533 
534  // Free some space in the new space so that we can check freshness.
535  HEAP->CollectGarbage(i::NEW_SPACE);
536  HEAP->CollectGarbage(i::NEW_SPACE);
537 
538  Local<String> small_string = String::New("s1");
539  // We should refuse to externalize newly created small string.
540  CHECK(!small_string->CanMakeExternal());
541  // Trigger GCs so that the newly allocated string moves to old gen.
542  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
543  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
544  // Old space strings should be accepted.
545  CHECK(small_string->CanMakeExternal());
546 
547  small_string = String::New("small string 2");
548  // We should refuse externalizing newly created small string.
549  CHECK(!small_string->CanMakeExternal());
550  for (int i = 0; i < 100; i++) {
551  String::Value value(small_string);
552  }
553  // Frequently used strings should be accepted.
554  CHECK(small_string->CanMakeExternal());
555 
556  const int buf_size = 10 * 1024;
557  char* buf = i::NewArray<char>(buf_size);
558  memset(buf, 'a', buf_size);
559  buf[buf_size - 1] = '\0';
560  Local<String> large_string = String::New(buf);
561  i::DeleteArray(buf);
562  // Large strings should be immediately accepted.
563  CHECK(large_string->CanMakeExternal());
564 }
565 
566 
567 THREADED_TEST(UsingExternalString) {
568  {
569  v8::HandleScope scope;
570  uint16_t* two_byte_string = AsciiToTwoByteString("test string");
571  Local<String> string =
572  String::NewExternal(new TestResource(two_byte_string));
573  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
574  // Trigger GCs so that the newly allocated string moves to old gen.
575  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
576  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
577  i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
578  CHECK(isymbol->IsSymbol());
579  }
580  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
581  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
582 }
583 
584 
585 THREADED_TEST(UsingExternalAsciiString) {
586  {
587  v8::HandleScope scope;
588  const char* one_byte_string = "test string";
589  Local<String> string = String::NewExternal(
590  new TestAsciiResource(i::StrDup(one_byte_string)));
591  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
592  // Trigger GCs so that the newly allocated string moves to old gen.
593  HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
594  HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
595  i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
596  CHECK(isymbol->IsSymbol());
597  }
598  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
599  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
600 }
601 
602 
603 THREADED_TEST(ScavengeExternalString) {
604  int dispose_count = 0;
605  bool in_new_space = false;
606  {
607  v8::HandleScope scope;
608  uint16_t* two_byte_string = AsciiToTwoByteString("test string");
609  Local<String> string =
610  String::NewExternal(new TestResource(two_byte_string,
611  &dispose_count));
612  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
613  HEAP->CollectGarbage(i::NEW_SPACE);
614  in_new_space = HEAP->InNewSpace(*istring);
615  CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
616  CHECK_EQ(0, dispose_count);
617  }
618  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
619  CHECK_EQ(1, dispose_count);
620 }
621 
622 
623 THREADED_TEST(ScavengeExternalAsciiString) {
624  int dispose_count = 0;
625  bool in_new_space = false;
626  {
627  v8::HandleScope scope;
628  const char* one_byte_string = "test string";
629  Local<String> string = String::NewExternal(
630  new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
631  i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
632  HEAP->CollectGarbage(i::NEW_SPACE);
633  in_new_space = HEAP->InNewSpace(*istring);
634  CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
635  CHECK_EQ(0, dispose_count);
636  }
637  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
638  CHECK_EQ(1, dispose_count);
639 }
640 
641 
643  public:
644  // Only used by non-threaded tests, so it can use static fields.
645  static int dispose_calls;
646  static int dispose_count;
647 
648  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
650  dispose_(dispose) { }
651 
652  void Dispose() {
653  ++dispose_calls;
654  if (dispose_) delete this;
655  }
656  private:
657  bool dispose_;
658 };
659 
660 
663 
664 
665 TEST(ExternalStringWithDisposeHandling) {
666  const char* c_source = "1 + 2 * 3";
667 
668  // Use a stack allocated external string resource allocated object.
669  TestAsciiResourceWithDisposeControl::dispose_count = 0;
670  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
672  {
673  v8::HandleScope scope;
674  LocalContext env;
675  Local<String> source = String::NewExternal(&res_stack);
676  Local<Script> script = Script::Compile(source);
677  Local<Value> value = script->Run();
678  CHECK(value->IsNumber());
679  CHECK_EQ(7, value->Int32Value());
680  HEAP->CollectAllAvailableGarbage();
681  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
682  }
683  i::Isolate::Current()->compilation_cache()->Clear();
684  HEAP->CollectAllAvailableGarbage();
685  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
686  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
687 
688  // Use a heap allocated external string resource allocated object.
689  TestAsciiResourceWithDisposeControl::dispose_count = 0;
690  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691  TestAsciiResource* res_heap =
692  new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
693  {
694  v8::HandleScope scope;
695  LocalContext env;
696  Local<String> source = String::NewExternal(res_heap);
697  Local<Script> script = Script::Compile(source);
698  Local<Value> value = script->Run();
699  CHECK(value->IsNumber());
700  CHECK_EQ(7, value->Int32Value());
701  HEAP->CollectAllAvailableGarbage();
702  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
703  }
704  i::Isolate::Current()->compilation_cache()->Clear();
705  HEAP->CollectAllAvailableGarbage();
706  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
707  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
708 }
709 
710 
711 THREADED_TEST(StringConcat) {
712  {
713  v8::HandleScope scope;
714  LocalContext env;
715  const char* one_byte_string_1 = "function a_times_t";
716  const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717  const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718  const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719  const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720  const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721  const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722  Local<String> left = v8_str(one_byte_string_1);
723 
724  uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725  Local<String> right = String::New(two_byte_source);
726  i::DeleteArray(two_byte_source);
727 
728  Local<String> source = String::Concat(left, right);
729  right = String::NewExternal(
730  new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731  source = String::Concat(source, right);
732  right = String::NewExternal(
733  new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734  source = String::Concat(source, right);
735  right = v8_str(one_byte_string_2);
736  source = String::Concat(source, right);
737 
738  two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739  right = String::New(two_byte_source);
740  i::DeleteArray(two_byte_source);
741 
742  source = String::Concat(source, right);
743  right = String::NewExternal(
744  new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745  source = String::Concat(source, right);
746  Local<Script> script = Script::Compile(source);
747  Local<Value> value = script->Run();
748  CHECK(value->IsNumber());
749  CHECK_EQ(68, value->Int32Value());
750  }
751  i::Isolate::Current()->compilation_cache()->Clear();
752  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
753  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
754 }
755 
756 
757 THREADED_TEST(GlobalProperties) {
758  v8::HandleScope scope;
759  LocalContext env;
760  v8::Handle<v8::Object> global = env->Global();
761  global->Set(v8_str("pi"), v8_num(3.1415926));
762  Local<Value> pi = global->Get(v8_str("pi"));
763  CHECK_EQ(3.1415926, pi->NumberValue());
764 }
765 
766 
767 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
769  return v8_num(102);
770 }
771 
772 
773 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
775  args.This()->Set(v8_str("x"), v8_num(1));
776  args.This()->Set(v8_str("y"), v8_num(2));
777  return args.This();
778 }
779 
780 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
782  return v8_num(239);
783 }
784 
785 
786 THREADED_TEST(FunctionTemplate) {
787  v8::HandleScope scope;
788  LocalContext env;
789  {
790  Local<v8::FunctionTemplate> fun_templ =
791  v8::FunctionTemplate::New(handle_call);
792  Local<Function> fun = fun_templ->GetFunction();
793  env->Global()->Set(v8_str("obj"), fun);
794  Local<Script> script = v8_compile("obj()");
795  CHECK_EQ(102, script->Run()->Int32Value());
796  }
797  // Use SetCallHandler to initialize a function template, should work like the
798  // previous one.
799  {
800  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801  fun_templ->SetCallHandler(handle_call);
802  Local<Function> fun = fun_templ->GetFunction();
803  env->Global()->Set(v8_str("obj"), fun);
804  Local<Script> script = v8_compile("obj()");
805  CHECK_EQ(102, script->Run()->Int32Value());
806  }
807  // Test constructor calls.
808  {
809  Local<v8::FunctionTemplate> fun_templ =
810  v8::FunctionTemplate::New(construct_call);
811  fun_templ->SetClassName(v8_str("funky"));
812  fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
813  Local<Function> fun = fun_templ->GetFunction();
814  env->Global()->Set(v8_str("obj"), fun);
815  Local<Script> script = v8_compile("var s = new obj(); s.x");
816  CHECK_EQ(1, script->Run()->Int32Value());
817 
818  Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819  CHECK_EQ(v8_str("[object funky]"), result);
820 
821  result = v8_compile("(new obj()).m")->Run();
822  CHECK_EQ(239, result->Int32Value());
823  }
824 }
825 
826 
827 static void* expected_ptr;
828 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829  void* ptr = v8::External::Unwrap(args.Data());
830  CHECK_EQ(expected_ptr, ptr);
831  return v8::True();
832 }
833 
834 
835 static void TestExternalPointerWrapping() {
836  v8::HandleScope scope;
837  LocalContext env;
838 
839  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840 
842  obj->Set(v8_str("func"),
843  v8::FunctionTemplate::New(callback, data)->GetFunction());
844  env->Global()->Set(v8_str("obj"), obj);
845 
846  CHECK(CompileRun(
847  "function foo() {\n"
848  " for (var i = 0; i < 13; i++) obj.func();\n"
849  "}\n"
850  "foo(), true")->BooleanValue());
851 }
852 
853 
854 THREADED_TEST(ExternalWrap) {
855  // Check heap allocated object.
856  int* ptr = new int;
857  expected_ptr = ptr;
858  TestExternalPointerWrapping();
859  delete ptr;
860 
861  // Check stack allocated object.
862  int foo;
863  expected_ptr = &foo;
864  TestExternalPointerWrapping();
865 
866  // Check not aligned addresses.
867  const int n = 100;
868  char* s = new char[n];
869  for (int i = 0; i < n; i++) {
870  expected_ptr = s + i;
871  TestExternalPointerWrapping();
872  }
873 
874  delete[] s;
875 
876  // Check several invalid addresses.
877  expected_ptr = reinterpret_cast<void*>(1);
878  TestExternalPointerWrapping();
879 
880  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881  TestExternalPointerWrapping();
882 
883  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884  TestExternalPointerWrapping();
885 
886 #if defined(V8_HOST_ARCH_X64)
887  // Check a value with a leading 1 bit in x64 Smi encoding.
888  expected_ptr = reinterpret_cast<void*>(0x400000000);
889  TestExternalPointerWrapping();
890 
891  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892  TestExternalPointerWrapping();
893 
894  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895  TestExternalPointerWrapping();
896 #endif
897 }
898 
899 
900 THREADED_TEST(FindInstanceInPrototypeChain) {
901  v8::HandleScope scope;
902  LocalContext env;
903 
904  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907  derived->Inherit(base);
908 
909  Local<v8::Function> base_function = base->GetFunction();
910  Local<v8::Function> derived_function = derived->GetFunction();
911  Local<v8::Function> other_function = other->GetFunction();
912 
913  Local<v8::Object> base_instance = base_function->NewInstance();
914  Local<v8::Object> derived_instance = derived_function->NewInstance();
915  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916  Local<v8::Object> other_instance = other_function->NewInstance();
917  derived_instance2->Set(v8_str("__proto__"), derived_instance);
918  other_instance->Set(v8_str("__proto__"), derived_instance2);
919 
920  // base_instance is only an instance of base.
921  CHECK_EQ(base_instance,
922  base_instance->FindInstanceInPrototypeChain(base));
923  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925 
926  // derived_instance is an instance of base and derived.
927  CHECK_EQ(derived_instance,
928  derived_instance->FindInstanceInPrototypeChain(base));
929  CHECK_EQ(derived_instance,
930  derived_instance->FindInstanceInPrototypeChain(derived));
931  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932 
933  // other_instance is an instance of other and its immediate
934  // prototype derived_instance2 is an instance of base and derived.
935  // Note, derived_instance is an instance of base and derived too,
936  // but it comes after derived_instance2 in the prototype chain of
937  // other_instance.
938  CHECK_EQ(derived_instance2,
939  other_instance->FindInstanceInPrototypeChain(base));
940  CHECK_EQ(derived_instance2,
941  other_instance->FindInstanceInPrototypeChain(derived));
942  CHECK_EQ(other_instance,
943  other_instance->FindInstanceInPrototypeChain(other));
944 }
945 
946 
947 THREADED_TEST(TinyInteger) {
948  v8::HandleScope scope;
949  LocalContext env;
950  int32_t value = 239;
951  Local<v8::Integer> value_obj = v8::Integer::New(value);
952  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953 }
954 
955 
956 THREADED_TEST(BigSmiInteger) {
957  v8::HandleScope scope;
958  LocalContext env;
959  int32_t value = i::Smi::kMaxValue;
960  // We cannot add one to a Smi::kMaxValue without wrapping.
961  if (i::kSmiValueSize < 32) {
962  CHECK(i::Smi::IsValid(value));
963  CHECK(!i::Smi::IsValid(value + 1));
964  Local<v8::Integer> value_obj = v8::Integer::New(value);
965  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966  }
967 }
968 
969 
970 THREADED_TEST(BigInteger) {
971  v8::HandleScope scope;
972  LocalContext env;
973  // We cannot add one to a Smi::kMaxValue without wrapping.
974  if (i::kSmiValueSize < 32) {
975  // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976  // The code will not be run in that case, due to the "if" guard.
977  int32_t value =
978  static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979  CHECK(value > i::Smi::kMaxValue);
980  CHECK(!i::Smi::IsValid(value));
981  Local<v8::Integer> value_obj = v8::Integer::New(value);
982  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983  }
984 }
985 
986 
987 THREADED_TEST(TinyUnsignedInteger) {
988  v8::HandleScope scope;
989  LocalContext env;
990  uint32_t value = 239;
991  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993 }
994 
995 
996 THREADED_TEST(BigUnsignedSmiInteger) {
997  v8::HandleScope scope;
998  LocalContext env;
999  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000  CHECK(i::Smi::IsValid(value));
1001  CHECK(!i::Smi::IsValid(value + 1));
1002  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004 }
1005 
1006 
1007 THREADED_TEST(BigUnsignedInteger) {
1008  v8::HandleScope scope;
1009  LocalContext env;
1010  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012  CHECK(!i::Smi::IsValid(value));
1013  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015 }
1016 
1017 
1018 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019  v8::HandleScope scope;
1020  LocalContext env;
1021  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022  uint32_t value = INT32_MAX_AS_UINT + 1;
1023  CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1024  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026 }
1027 
1028 
1029 THREADED_TEST(IsNativeError) {
1030  v8::HandleScope scope;
1031  LocalContext env;
1032  v8::Handle<Value> syntax_error = CompileRun(
1033  "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034  CHECK(syntax_error->IsNativeError());
1035  v8::Handle<Value> not_error = CompileRun("{a:42}");
1036  CHECK(!not_error->IsNativeError());
1037  v8::Handle<Value> not_object = CompileRun("42");
1038  CHECK(!not_object->IsNativeError());
1039 }
1040 
1041 
1042 THREADED_TEST(StringObject) {
1043  v8::HandleScope scope;
1044  LocalContext env;
1045  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046  CHECK(boxed_string->IsStringObject());
1047  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048  CHECK(!unboxed_string->IsStringObject());
1049  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050  CHECK(!boxed_not_string->IsStringObject());
1051  v8::Handle<Value> not_object = CompileRun("0");
1052  CHECK(!not_object->IsStringObject());
1053  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054  CHECK(!as_boxed.IsEmpty());
1055  Local<v8::String> the_string = as_boxed->StringValue();
1056  CHECK(!the_string.IsEmpty());
1057  ExpectObject("\"test\"", the_string);
1058  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059  CHECK(new_boxed_string->IsStringObject());
1060  as_boxed = new_boxed_string.As<v8::StringObject>();
1061  the_string = as_boxed->StringValue();
1062  CHECK(!the_string.IsEmpty());
1063  ExpectObject("\"test\"", the_string);
1064 }
1065 
1066 
1067 THREADED_TEST(NumberObject) {
1068  v8::HandleScope scope;
1069  LocalContext env;
1070  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071  CHECK(boxed_number->IsNumberObject());
1072  v8::Handle<Value> unboxed_number = CompileRun("42");
1073  CHECK(!unboxed_number->IsNumberObject());
1074  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075  CHECK(!boxed_not_number->IsNumberObject());
1076  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077  CHECK(!as_boxed.IsEmpty());
1078  double the_number = as_boxed->NumberValue();
1079  CHECK_EQ(42.0, the_number);
1080  v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081  CHECK(new_boxed_number->IsNumberObject());
1082  as_boxed = new_boxed_number.As<v8::NumberObject>();
1083  the_number = as_boxed->NumberValue();
1084  CHECK_EQ(43.0, the_number);
1085 }
1086 
1087 
1088 THREADED_TEST(BooleanObject) {
1089  v8::HandleScope scope;
1090  LocalContext env;
1091  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092  CHECK(boxed_boolean->IsBooleanObject());
1093  v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094  CHECK(!unboxed_boolean->IsBooleanObject());
1095  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096  CHECK(!boxed_not_boolean->IsBooleanObject());
1098  boxed_boolean.As<v8::BooleanObject>();
1099  CHECK(!as_boxed.IsEmpty());
1100  bool the_boolean = as_boxed->BooleanValue();
1101  CHECK_EQ(true, the_boolean);
1102  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104  CHECK(boxed_true->IsBooleanObject());
1105  CHECK(boxed_false->IsBooleanObject());
1106  as_boxed = boxed_true.As<v8::BooleanObject>();
1107  CHECK_EQ(true, as_boxed->BooleanValue());
1108  as_boxed = boxed_false.As<v8::BooleanObject>();
1109  CHECK_EQ(false, as_boxed->BooleanValue());
1110 }
1111 
1112 
1113 THREADED_TEST(Number) {
1114  v8::HandleScope scope;
1115  LocalContext env;
1116  double PI = 3.1415926;
1117  Local<v8::Number> pi_obj = v8::Number::New(PI);
1118  CHECK_EQ(PI, pi_obj->NumberValue());
1119 }
1120 
1121 
1123  v8::HandleScope scope;
1124  LocalContext env;
1125  Local<String> str = v8_str("3.1415926");
1126  CHECK_EQ(3.1415926, str->NumberValue());
1128  CHECK_EQ(1.0, t->NumberValue());
1130  CHECK_EQ(0.0, f->NumberValue());
1131 }
1132 
1133 
1135  v8::HandleScope scope;
1136  LocalContext env;
1137  double PI = 3.1415926;
1138  Local<Value> date = v8::Date::New(PI);
1139  CHECK_EQ(3.0, date->NumberValue());
1140  date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1142 }
1143 
1144 
1145 THREADED_TEST(Boolean) {
1146  v8::HandleScope scope;
1147  LocalContext env;
1149  CHECK(t->Value());
1151  CHECK(!f->Value());
1153  CHECK(!u->BooleanValue());
1155  CHECK(!n->BooleanValue());
1156  v8::Handle<String> str1 = v8_str("");
1157  CHECK(!str1->BooleanValue());
1158  v8::Handle<String> str2 = v8_str("x");
1159  CHECK(str2->BooleanValue());
1160  CHECK(!v8::Number::New(0)->BooleanValue());
1161  CHECK(v8::Number::New(-1)->BooleanValue());
1162  CHECK(v8::Number::New(1)->BooleanValue());
1163  CHECK(v8::Number::New(42)->BooleanValue());
1164  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165 }
1166 
1167 
1168 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1170  return v8_num(13.4);
1171 }
1172 
1173 
1174 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1176  return v8_num(876);
1177 }
1178 
1179 
1180 THREADED_TEST(GlobalPrototype) {
1181  v8::HandleScope scope;
1183  func_templ->PrototypeTemplate()->Set(
1184  "dummy",
1185  v8::FunctionTemplate::New(DummyCallHandler));
1186  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187  templ->Set("x", v8_num(200));
1188  templ->SetAccessor(v8_str("m"), GetM);
1189  LocalContext env(0, templ);
1190  v8::Handle<Script> script(v8_compile("dummy()"));
1191  v8::Handle<Value> result(script->Run());
1192  CHECK_EQ(13.4, result->NumberValue());
1193  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1194  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1195 }
1196 
1197 
1198 THREADED_TEST(ObjectTemplate) {
1199  v8::HandleScope scope;
1200  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1201  templ1->Set("x", v8_num(10));
1202  templ1->Set("y", v8_num(13));
1203  LocalContext env;
1204  Local<v8::Object> instance1 = templ1->NewInstance();
1205  env->Global()->Set(v8_str("p"), instance1);
1206  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1207  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1208  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1209  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1210  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1211  templ2->Set("a", v8_num(12));
1212  templ2->Set("b", templ1);
1213  Local<v8::Object> instance2 = templ2->NewInstance();
1214  env->Global()->Set(v8_str("q"), instance2);
1215  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1216  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1217  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1218  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1219 }
1220 
1221 
1222 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1224  return v8_num(17.2);
1225 }
1226 
1227 
1228 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1230  return v8_num(15.2);
1231 }
1232 
1233 
1234 THREADED_TEST(DescriptorInheritance) {
1235  v8::HandleScope scope;
1237  super->PrototypeTemplate()->Set("flabby",
1238  v8::FunctionTemplate::New(GetFlabby));
1239  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1240 
1241  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1242 
1244  base1->Inherit(super);
1245  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1246 
1248  base2->Inherit(super);
1249  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1250 
1251  LocalContext env;
1252 
1253  env->Global()->Set(v8_str("s"), super->GetFunction());
1254  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1255  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1256 
1257  // Checks right __proto__ chain.
1258  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1259  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1260 
1261  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1262 
1263  // Instance accessor should not be visible on function object or its prototype
1264  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1265  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1266  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1267 
1268  env->Global()->Set(v8_str("obj"),
1269  base1->GetFunction()->NewInstance());
1270  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1271  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1272  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1273  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1274  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1275 
1276  env->Global()->Set(v8_str("obj2"),
1277  base2->GetFunction()->NewInstance());
1278  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1279  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1280  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1281  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1282  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1283 
1284  // base1 and base2 cannot cross reference to each's prototype
1285  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1286  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1287 }
1288 
1289 
1291 
1292 
1293 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1294  const AccessorInfo& info) {
1296  CHECK_EQ(v8_str("data"), info.Data());
1297  echo_named_call_count++;
1298  return name;
1299 }
1300 
1301 // Helper functions for Interceptor/Accessor interaction tests
1302 
1303 Handle<Value> SimpleAccessorGetter(Local<String> name,
1304  const AccessorInfo& info) {
1305  Handle<Object> self = info.This();
1306  return self->Get(String::Concat(v8_str("accessor_"), name));
1307 }
1308 
1309 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1310  const AccessorInfo& info) {
1311  Handle<Object> self = info.This();
1312  self->Set(String::Concat(v8_str("accessor_"), name), value);
1313 }
1314 
1315 Handle<Value> EmptyInterceptorGetter(Local<String> name,
1316  const AccessorInfo& info) {
1317  return Handle<Value>();
1318 }
1319 
1320 Handle<Value> EmptyInterceptorSetter(Local<String> name,
1321  Local<Value> value,
1322  const AccessorInfo& info) {
1323  return Handle<Value>();
1324 }
1325 
1326 Handle<Value> InterceptorGetter(Local<String> name,
1327  const AccessorInfo& info) {
1328  // Intercept names that start with 'interceptor_'.
1329  String::AsciiValue ascii(name);
1330  char* name_str = *ascii;
1331  char prefix[] = "interceptor_";
1332  int i;
1333  for (i = 0; name_str[i] && prefix[i]; ++i) {
1334  if (name_str[i] != prefix[i]) return Handle<Value>();
1335  }
1336  Handle<Object> self = info.This();
1337  return self->GetHiddenValue(v8_str(name_str + i));
1338 }
1339 
1340 Handle<Value> InterceptorSetter(Local<String> name,
1341  Local<Value> value,
1342  const AccessorInfo& info) {
1343  // Intercept accesses that set certain integer values.
1344  if (value->IsInt32() && value->Int32Value() < 10000) {
1345  Handle<Object> self = info.This();
1346  self->SetHiddenValue(name, value);
1347  return value;
1348  }
1349  return Handle<Value>();
1350 }
1351 
1352 void AddAccessor(Handle<FunctionTemplate> templ,
1353  Handle<String> name,
1354  v8::AccessorGetter getter,
1355  v8::AccessorSetter setter) {
1356  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1357 }
1358 
1359 void AddInterceptor(Handle<FunctionTemplate> templ,
1360  v8::NamedPropertyGetter getter,
1361  v8::NamedPropertySetter setter) {
1362  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1363 }
1364 
1365 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1366  v8::HandleScope scope;
1367  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1368  Handle<FunctionTemplate> child = FunctionTemplate::New();
1369  child->Inherit(parent);
1370  AddAccessor(parent, v8_str("age"),
1373  LocalContext env;
1374  env->Global()->Set(v8_str("Child"), child->GetFunction());
1375  CompileRun("var child = new Child;"
1376  "child.age = 10;");
1377  ExpectBoolean("child.hasOwnProperty('age')", false);
1378  ExpectInt32("child.age", 10);
1379  ExpectInt32("child.accessor_age", 10);
1380 }
1381 
1382 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1383  v8::HandleScope scope;
1384  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1385  Handle<FunctionTemplate> child = FunctionTemplate::New();
1386  child->Inherit(parent);
1388  LocalContext env;
1389  env->Global()->Set(v8_str("Child"), child->GetFunction());
1390  CompileRun("var child = new Child;"
1391  "var parent = child.__proto__;"
1392  "Object.defineProperty(parent, 'age', "
1393  " {get: function(){ return this.accessor_age; }, "
1394  " set: function(v){ this.accessor_age = v; }, "
1395  " enumerable: true, configurable: true});"
1396  "child.age = 10;");
1397  ExpectBoolean("child.hasOwnProperty('age')", false);
1398  ExpectInt32("child.age", 10);
1399  ExpectInt32("child.accessor_age", 10);
1400 }
1401 
1402 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1403  v8::HandleScope scope;
1404  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1405  Handle<FunctionTemplate> child = FunctionTemplate::New();
1406  child->Inherit(parent);
1408  LocalContext env;
1409  env->Global()->Set(v8_str("Child"), child->GetFunction());
1410  CompileRun("var child = new Child;"
1411  "var parent = child.__proto__;"
1412  "parent.name = 'Alice';");
1413  ExpectBoolean("child.hasOwnProperty('name')", false);
1414  ExpectString("child.name", "Alice");
1415  CompileRun("child.name = 'Bob';");
1416  ExpectString("child.name", "Bob");
1417  ExpectBoolean("child.hasOwnProperty('name')", true);
1418  ExpectString("parent.name", "Alice");
1419 }
1420 
1421 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1422  v8::HandleScope scope;
1423  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1424  AddAccessor(templ, v8_str("age"),
1427  LocalContext env;
1428  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1429  CompileRun("var obj = new Obj;"
1430  "function setAge(i){ obj.age = i; };"
1431  "for(var i = 0; i <= 10000; i++) setAge(i);");
1432  // All i < 10000 go to the interceptor.
1433  ExpectInt32("obj.interceptor_age", 9999);
1434  // The last i goes to the accessor.
1435  ExpectInt32("obj.accessor_age", 10000);
1436 }
1437 
1438 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1439  v8::HandleScope scope;
1440  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1441  AddAccessor(templ, v8_str("age"),
1444  LocalContext env;
1445  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1446  CompileRun("var obj = new Obj;"
1447  "function setAge(i){ obj.age = i; };"
1448  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1449  // All i >= 10000 go to the accessor.
1450  ExpectInt32("obj.accessor_age", 10000);
1451  // The last i goes to the interceptor.
1452  ExpectInt32("obj.interceptor_age", 9999);
1453 }
1454 
1455 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1456  v8::HandleScope scope;
1457  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1458  Handle<FunctionTemplate> child = FunctionTemplate::New();
1459  child->Inherit(parent);
1460  AddAccessor(parent, v8_str("age"),
1463  LocalContext env;
1464  env->Global()->Set(v8_str("Child"), child->GetFunction());
1465  CompileRun("var child = new Child;"
1466  "function setAge(i){ child.age = i; };"
1467  "for(var i = 0; i <= 10000; i++) setAge(i);");
1468  // All i < 10000 go to the interceptor.
1469  ExpectInt32("child.interceptor_age", 9999);
1470  // The last i goes to the accessor.
1471  ExpectInt32("child.accessor_age", 10000);
1472 }
1473 
1474 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1475  v8::HandleScope scope;
1476  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1477  Handle<FunctionTemplate> child = FunctionTemplate::New();
1478  child->Inherit(parent);
1479  AddAccessor(parent, v8_str("age"),
1482  LocalContext env;
1483  env->Global()->Set(v8_str("Child"), child->GetFunction());
1484  CompileRun("var child = new Child;"
1485  "function setAge(i){ child.age = i; };"
1486  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1487  // All i >= 10000 go to the accessor.
1488  ExpectInt32("child.accessor_age", 10000);
1489  // The last i goes to the interceptor.
1490  ExpectInt32("child.interceptor_age", 9999);
1491 }
1492 
1493 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1494  v8::HandleScope scope;
1495  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1497  LocalContext env;
1498  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1499  CompileRun("var obj = new Obj;"
1500  "function setter(i) { this.accessor_age = i; };"
1501  "function getter() { return this.accessor_age; };"
1502  "function setAge(i) { obj.age = i; };"
1503  "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1504  "for(var i = 0; i <= 10000; i++) setAge(i);");
1505  // All i < 10000 go to the interceptor.
1506  ExpectInt32("obj.interceptor_age", 9999);
1507  // The last i goes to the JavaScript accessor.
1508  ExpectInt32("obj.accessor_age", 10000);
1509  // The installed JavaScript getter is still intact.
1510  // This last part is a regression test for issue 1651 and relies on the fact
1511  // that both interceptor and accessor are being installed on the same object.
1512  ExpectInt32("obj.age", 10000);
1513  ExpectBoolean("obj.hasOwnProperty('age')", true);
1514  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1515 }
1516 
1517 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1518  v8::HandleScope scope;
1519  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1521  LocalContext env;
1522  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1523  CompileRun("var obj = new Obj;"
1524  "function setter(i) { this.accessor_age = i; };"
1525  "function getter() { return this.accessor_age; };"
1526  "function setAge(i) { obj.age = i; };"
1527  "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1528  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1529  // All i >= 10000 go to the accessor.
1530  ExpectInt32("obj.accessor_age", 10000);
1531  // The last i goes to the interceptor.
1532  ExpectInt32("obj.interceptor_age", 9999);
1533  // The installed JavaScript getter is still intact.
1534  // This last part is a regression test for issue 1651 and relies on the fact
1535  // that both interceptor and accessor are being installed on the same object.
1536  ExpectInt32("obj.age", 10000);
1537  ExpectBoolean("obj.hasOwnProperty('age')", true);
1538  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1539 }
1540 
1541 THREADED_TEST(SwitchFromInterceptorToProperty) {
1542  v8::HandleScope scope;
1543  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1544  Handle<FunctionTemplate> child = FunctionTemplate::New();
1545  child->Inherit(parent);
1547  LocalContext env;
1548  env->Global()->Set(v8_str("Child"), child->GetFunction());
1549  CompileRun("var child = new Child;"
1550  "function setAge(i){ child.age = i; };"
1551  "for(var i = 0; i <= 10000; i++) setAge(i);");
1552  // All i < 10000 go to the interceptor.
1553  ExpectInt32("child.interceptor_age", 9999);
1554  // The last i goes to child's own property.
1555  ExpectInt32("child.age", 10000);
1556 }
1557 
1558 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1559  v8::HandleScope scope;
1560  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1561  Handle<FunctionTemplate> child = FunctionTemplate::New();
1562  child->Inherit(parent);
1564  LocalContext env;
1565  env->Global()->Set(v8_str("Child"), child->GetFunction());
1566  CompileRun("var child = new Child;"
1567  "function setAge(i){ child.age = i; };"
1568  "for(var i = 20000; i >= 9999; i--) setAge(i);");
1569  // All i >= 10000 go to child's own property.
1570  ExpectInt32("child.age", 10000);
1571  // The last i goes to the interceptor.
1572  ExpectInt32("child.interceptor_age", 9999);
1573 }
1574 
1575 THREADED_TEST(NamedPropertyHandlerGetter) {
1576  echo_named_call_count = 0;
1577  v8::HandleScope scope;
1579  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1580  0, 0, 0, 0,
1581  v8_str("data"));
1582  LocalContext env;
1583  env->Global()->Set(v8_str("obj"),
1584  templ->GetFunction()->NewInstance());
1585  CHECK_EQ(echo_named_call_count, 0);
1586  v8_compile("obj.x")->Run();
1587  CHECK_EQ(echo_named_call_count, 1);
1588  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1589  v8::Handle<Value> str = CompileRun(code);
1590  String::AsciiValue value(str);
1591  CHECK_EQ(*value, "oddlepoddle");
1592  // Check default behavior
1593  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1594  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1595  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1596 }
1597 
1598 
1600 
1601 
1602 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1603  const AccessorInfo& info) {
1605  CHECK_EQ(v8_num(637), info.Data());
1606  echo_indexed_call_count++;
1607  return v8_num(index);
1608 }
1609 
1610 
1611 THREADED_TEST(IndexedPropertyHandlerGetter) {
1612  v8::HandleScope scope;
1614  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1615  0, 0, 0, 0,
1616  v8_num(637));
1617  LocalContext env;
1618  env->Global()->Set(v8_str("obj"),
1619  templ->GetFunction()->NewInstance());
1620  Local<Script> script = v8_compile("obj[900]");
1621  CHECK_EQ(script->Run()->Int32Value(), 900);
1622 }
1623 
1624 
1626 
1627 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1628  uint32_t index,
1629  const AccessorInfo& info) {
1631  CHECK(info.This()->Equals(bottom));
1632  return v8::Handle<Value>();
1633 }
1634 
1635 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1636  Local<String> name,
1637  const AccessorInfo& info) {
1639  CHECK(info.This()->Equals(bottom));
1640  return v8::Handle<Value>();
1641 }
1642 
1643 
1645  Local<Value> value,
1646  const AccessorInfo& info) {
1648  CHECK(info.This()->Equals(bottom));
1649  return v8::Handle<Value>();
1650 }
1651 
1652 
1654  Local<Value> value,
1655  const AccessorInfo& info) {
1657  CHECK(info.This()->Equals(bottom));
1658  return v8::Handle<Value>();
1659 }
1660 
1662  uint32_t index,
1663  const AccessorInfo& info) {
1665  CHECK(info.This()->Equals(bottom));
1666  return v8::Handle<v8::Integer>();
1667 }
1668 
1669 
1671  const AccessorInfo& info) {
1673  CHECK(info.This()->Equals(bottom));
1674  return v8::Handle<v8::Integer>();
1675 }
1676 
1677 
1679  uint32_t index,
1680  const AccessorInfo& info) {
1682  CHECK(info.This()->Equals(bottom));
1683  return v8::Handle<v8::Boolean>();
1684 }
1685 
1686 
1688  Local<String> property,
1689  const AccessorInfo& info) {
1691  CHECK(info.This()->Equals(bottom));
1692  return v8::Handle<v8::Boolean>();
1693 }
1694 
1695 
1697  const AccessorInfo& info) {
1699  CHECK(info.This()->Equals(bottom));
1700  return v8::Handle<v8::Array>();
1701 }
1702 
1703 
1705  const AccessorInfo& info) {
1707  CHECK(info.This()->Equals(bottom));
1708  return v8::Handle<v8::Array>();
1709 }
1710 
1711 
1712 THREADED_TEST(PropertyHandlerInPrototype) {
1713  v8::HandleScope scope;
1714  LocalContext env;
1715 
1716  // Set up a prototype chain with three interceptors.
1718  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1719  CheckThisIndexedPropertyHandler,
1724 
1725  templ->InstanceTemplate()->SetNamedPropertyHandler(
1726  CheckThisNamedPropertyHandler,
1731 
1732  bottom = templ->GetFunction()->NewInstance();
1733  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1734  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1735 
1736  bottom->Set(v8_str("__proto__"), middle);
1737  middle->Set(v8_str("__proto__"), top);
1738  env->Global()->Set(v8_str("obj"), bottom);
1739 
1740  // Indexed and named get.
1741  Script::Compile(v8_str("obj[0]"))->Run();
1742  Script::Compile(v8_str("obj.x"))->Run();
1743 
1744  // Indexed and named set.
1745  Script::Compile(v8_str("obj[1] = 42"))->Run();
1746  Script::Compile(v8_str("obj.y = 42"))->Run();
1747 
1748  // Indexed and named query.
1749  Script::Compile(v8_str("0 in obj"))->Run();
1750  Script::Compile(v8_str("'x' in obj"))->Run();
1751 
1752  // Indexed and named deleter.
1753  Script::Compile(v8_str("delete obj[0]"))->Run();
1754  Script::Compile(v8_str("delete obj.x"))->Run();
1755 
1756  // Enumerators.
1757  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1758 }
1759 
1760 
1761 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1762  const AccessorInfo& info) {
1764  if (v8_str("pre")->Equals(key)) {
1765  return v8_str("PrePropertyHandler: pre");
1766  }
1767  return v8::Handle<String>();
1768 }
1769 
1770 
1771 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1772  const AccessorInfo&) {
1773  if (v8_str("pre")->Equals(key)) {
1774  return v8::Integer::New(v8::None);
1775  }
1776 
1777  return v8::Handle<v8::Integer>(); // do not intercept the call
1778 }
1779 
1780 
1781 THREADED_TEST(PrePropertyHandler) {
1782  v8::HandleScope scope;
1784  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1785  0,
1786  PrePropertyHandlerQuery);
1787  LocalContext env(NULL, desc->InstanceTemplate());
1788  Script::Compile(v8_str(
1789  "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1790  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1791  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1792  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1793  CHECK_EQ(v8_str("Object: on"), result_on);
1794  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1795  CHECK(result_post.IsEmpty());
1796 }
1797 
1798 
1799 THREADED_TEST(UndefinedIsNotEnumerable) {
1800  v8::HandleScope scope;
1801  LocalContext env;
1802  v8::Handle<Value> result = Script::Compile(v8_str(
1803  "this.propertyIsEnumerable(undefined)"))->Run();
1804  CHECK(result->IsFalse());
1805 }
1806 
1807 
1809 static const int kTargetRecursionDepth = 200; // near maximum
1810 
1811 
1812 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1814  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1815  if (depth == kTargetRecursionDepth) return v8::Undefined();
1816  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1817  return call_recursively_script->Run();
1818 }
1819 
1820 
1821 static v8::Handle<Value> CallFunctionRecursivelyCall(
1822  const v8::Arguments& args) {
1824  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1825  if (depth == kTargetRecursionDepth) {
1826  printf("[depth = %d]\n", depth);
1827  return v8::Undefined();
1828  }
1829  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1830  v8::Handle<Value> function =
1831  args.This()->Get(v8_str("callFunctionRecursively"));
1832  return function.As<Function>()->Call(args.This(), 0, NULL);
1833 }
1834 
1835 
1836 THREADED_TEST(DeepCrossLanguageRecursion) {
1837  v8::HandleScope scope;
1838  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1839  global->Set(v8_str("callScriptRecursively"),
1840  v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1841  global->Set(v8_str("callFunctionRecursively"),
1842  v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1843  LocalContext env(NULL, global);
1844 
1845  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1846  call_recursively_script = v8_compile("callScriptRecursively()");
1847  call_recursively_script->Run();
1848  call_recursively_script = v8::Handle<Script>();
1849 
1850  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1851  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1852 }
1853 
1854 
1855 static v8::Handle<Value>
1856  ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1858  return v8::ThrowException(key);
1859 }
1860 
1861 
1862 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1863  Local<Value>,
1864  const AccessorInfo&) {
1865  v8::ThrowException(key);
1866  return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1867 }
1868 
1869 
1870 THREADED_TEST(CallbackExceptionRegression) {
1871  v8::HandleScope scope;
1872  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1873  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1874  ThrowingPropertyHandlerSet);
1875  LocalContext env;
1876  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1877  v8::Handle<Value> otto = Script::Compile(v8_str(
1878  "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1879  CHECK_EQ(v8_str("otto"), otto);
1880  v8::Handle<Value> netto = Script::Compile(v8_str(
1881  "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1882  CHECK_EQ(v8_str("netto"), netto);
1883 }
1884 
1885 
1886 THREADED_TEST(FunctionPrototype) {
1887  v8::HandleScope scope;
1888  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1889  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1890  LocalContext env;
1891  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1892  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1893  CHECK_EQ(script->Run()->Int32Value(), 321);
1894 }
1895 
1896 
1897 THREADED_TEST(InternalFields) {
1898  v8::HandleScope scope;
1899  LocalContext env;
1900 
1901  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1902  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1903  instance_templ->SetInternalFieldCount(1);
1904  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1905  CHECK_EQ(1, obj->InternalFieldCount());
1906  CHECK(obj->GetInternalField(0)->IsUndefined());
1907  obj->SetInternalField(0, v8_num(17));
1908  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1909 }
1910 
1911 
1912 THREADED_TEST(GlobalObjectInternalFields) {
1913  v8::HandleScope scope;
1914  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1915  global_template->SetInternalFieldCount(1);
1916  LocalContext env(NULL, global_template);
1917  v8::Handle<v8::Object> global_proxy = env->Global();
1918  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1919  CHECK_EQ(1, global->InternalFieldCount());
1920  CHECK(global->GetInternalField(0)->IsUndefined());
1921  global->SetInternalField(0, v8_num(17));
1922  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1923 }
1924 
1925 
1926 THREADED_TEST(InternalFieldsNativePointers) {
1927  v8::HandleScope scope;
1928  LocalContext env;
1929 
1930  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1931  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1932  instance_templ->SetInternalFieldCount(1);
1933  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1934  CHECK_EQ(1, obj->InternalFieldCount());
1935  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1936 
1937  char* data = new char[100];
1938 
1939  void* aligned = data;
1940  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1941  void* unaligned = data + 1;
1942  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1943 
1944  // Check reading and writing aligned pointers.
1945  obj->SetPointerInInternalField(0, aligned);
1946  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1947  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1948 
1949  // Check reading and writing unaligned pointers.
1950  obj->SetPointerInInternalField(0, unaligned);
1951  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1952  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1953 
1954  delete[] data;
1955 }
1956 
1957 
1958 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1959  v8::HandleScope scope;
1960  LocalContext env;
1961 
1962  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1963  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1964  instance_templ->SetInternalFieldCount(1);
1965  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1966  CHECK_EQ(1, obj->InternalFieldCount());
1967  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1968 
1969  char* data = new char[100];
1970 
1971  void* aligned = data;
1972  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1973  void* unaligned = data + 1;
1974  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1975 
1976  obj->SetPointerInInternalField(0, aligned);
1977  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1978  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1979 
1980  obj->SetPointerInInternalField(0, unaligned);
1981  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1982  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1983 
1984  obj->SetInternalField(0, v8::External::Wrap(aligned));
1985  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1986  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1987 
1988  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1989  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1990  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1991 
1992  delete[] data;
1993 }
1994 
1995 
1996 THREADED_TEST(IdentityHash) {
1997  v8::HandleScope scope;
1998  LocalContext env;
1999 
2000  // Ensure that the test starts with an fresh heap to test whether the hash
2001  // code is based on the address.
2002  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2003  Local<v8::Object> obj = v8::Object::New();
2004  int hash = obj->GetIdentityHash();
2005  int hash1 = obj->GetIdentityHash();
2006  CHECK_EQ(hash, hash1);
2007  int hash2 = v8::Object::New()->GetIdentityHash();
2008  // Since the identity hash is essentially a random number two consecutive
2009  // objects should not be assigned the same hash code. If the test below fails
2010  // the random number generator should be evaluated.
2011  CHECK_NE(hash, hash2);
2012  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2013  int hash3 = v8::Object::New()->GetIdentityHash();
2014  // Make sure that the identity hash is not based on the initial address of
2015  // the object alone. If the test below fails the random number generator
2016  // should be evaluated.
2017  CHECK_NE(hash, hash3);
2018  int hash4 = obj->GetIdentityHash();
2019  CHECK_EQ(hash, hash4);
2020 
2021  // Check identity hashes behaviour in the presence of JS accessors.
2022  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2023  {
2024  CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2025  Local<v8::Object> o1 = v8::Object::New();
2026  Local<v8::Object> o2 = v8::Object::New();
2027  CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2028  }
2029  {
2030  CompileRun(
2031  "function cnst() { return 42; };\n"
2032  "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2033  Local<v8::Object> o1 = v8::Object::New();
2034  Local<v8::Object> o2 = v8::Object::New();
2035  CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2036  }
2037 }
2038 
2039 
2040 THREADED_TEST(HiddenProperties) {
2041  v8::HandleScope scope;
2042  LocalContext env;
2043 
2045  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2046  v8::Local<v8::String> empty = v8_str("");
2047  v8::Local<v8::String> prop_name = v8_str("prop_name");
2048 
2049  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2050 
2051  // Make sure delete of a non-existent hidden value works
2052  CHECK(obj->DeleteHiddenValue(key));
2053 
2054  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2055  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2056  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2057  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2058 
2059  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2060 
2061  // Make sure we do not find the hidden property.
2062  CHECK(!obj->Has(empty));
2063  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2064  CHECK(obj->Get(empty)->IsUndefined());
2065  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2066  CHECK(obj->Set(empty, v8::Integer::New(2003)));
2067  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2068  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2069 
2070  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2071 
2072  // Add another property and delete it afterwards to force the object in
2073  // slow case.
2074  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2075  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2076  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2077  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2078  CHECK(obj->Delete(prop_name));
2079  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2080 
2081  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2082 
2083  CHECK(obj->DeleteHiddenValue(key));
2084  CHECK(obj->GetHiddenValue(key).IsEmpty());
2085 }
2086 
2087 
2088 THREADED_TEST(Regress97784) {
2089  // Regression test for crbug.com/97784
2090  // Messing with the Object.prototype should not have effect on
2091  // hidden properties.
2092  v8::HandleScope scope;
2093  LocalContext env;
2094 
2096  v8::Local<v8::String> key = v8_str("hidden");
2097 
2098  CompileRun(
2099  "set_called = false;"
2100  "Object.defineProperty("
2101  " Object.prototype,"
2102  " 'hidden',"
2103  " {get: function() { return 45; },"
2104  " set: function() { set_called = true; }})");
2105 
2106  CHECK(obj->GetHiddenValue(key).IsEmpty());
2107  // Make sure that the getter and setter from Object.prototype is not invoked.
2108  // If it did we would have full access to the hidden properties in
2109  // the accessor.
2110  CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2111  ExpectFalse("set_called");
2112  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2113 }
2114 
2115 
2116 static bool interceptor_for_hidden_properties_called;
2117 static v8::Handle<Value> InterceptorForHiddenProperties(
2118  Local<String> name, const AccessorInfo& info) {
2119  interceptor_for_hidden_properties_called = true;
2120  return v8::Handle<Value>();
2121 }
2122 
2123 
2124 THREADED_TEST(HiddenPropertiesWithInterceptors) {
2125  v8::HandleScope scope;
2126  LocalContext context;
2127 
2128  interceptor_for_hidden_properties_called = false;
2129 
2130  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2131 
2132  // Associate an interceptor with an object and start setting hidden values.
2133  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2134  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2135  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2136  Local<v8::Function> function = fun_templ->GetFunction();
2137  Local<v8::Object> obj = function->NewInstance();
2138  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2139  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2140  CHECK(!interceptor_for_hidden_properties_called);
2141 }
2142 
2143 
2144 THREADED_TEST(External) {
2145  v8::HandleScope scope;
2146  int x = 3;
2147  Local<v8::External> ext = v8::External::New(&x);
2148  LocalContext env;
2149  env->Global()->Set(v8_str("ext"), ext);
2150  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2151  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2152  int* ptr = static_cast<int*>(reext->Value());
2153  CHECK_EQ(x, 3);
2154  *ptr = 10;
2155  CHECK_EQ(x, 10);
2156 
2157  // Make sure unaligned pointers are wrapped properly.
2158  char* data = i::StrDup("0123456789");
2159  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2160  Local<v8::Value> one = v8::External::Wrap(&data[1]);
2161  Local<v8::Value> two = v8::External::Wrap(&data[2]);
2162  Local<v8::Value> three = v8::External::Wrap(&data[3]);
2163 
2164  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2165  CHECK_EQ('0', *char_ptr);
2166  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2167  CHECK_EQ('1', *char_ptr);
2168  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2169  CHECK_EQ('2', *char_ptr);
2170  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2171  CHECK_EQ('3', *char_ptr);
2172  i::DeleteArray(data);
2173 }
2174 
2175 
2176 THREADED_TEST(GlobalHandle) {
2177  v8::Persistent<String> global;
2178  {
2179  v8::HandleScope scope;
2180  Local<String> str = v8_str("str");
2181  global = v8::Persistent<String>::New(str);
2182  }
2183  CHECK_EQ(global->Length(), 3);
2184  global.Dispose();
2185 }
2186 
2187 
2189  public:
2190  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2191  int id() { return id_; }
2192  void increment() { number_of_weak_calls_++; }
2193  int NumberOfWeakCalls() { return number_of_weak_calls_; }
2194  private:
2195  int id_;
2196  int number_of_weak_calls_;
2197 };
2198 
2199 
2200 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2201  WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2202  CHECK_EQ(1234, counter->id());
2203  counter->increment();
2204  handle.Dispose();
2205 }
2206 
2207 
2208 THREADED_TEST(ApiObjectGroups) {
2209  HandleScope scope;
2210  LocalContext env;
2211 
2212  Persistent<Object> g1s1;
2213  Persistent<Object> g1s2;
2214  Persistent<Object> g1c1;
2215  Persistent<Object> g2s1;
2216  Persistent<Object> g2s2;
2217  Persistent<Object> g2c1;
2218 
2219  WeakCallCounter counter(1234);
2220 
2221  {
2222  HandleScope scope;
2223  g1s1 = Persistent<Object>::New(Object::New());
2224  g1s2 = Persistent<Object>::New(Object::New());
2225  g1c1 = Persistent<Object>::New(Object::New());
2226  g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2227  g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2228  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2229 
2230  g2s1 = Persistent<Object>::New(Object::New());
2231  g2s2 = Persistent<Object>::New(Object::New());
2232  g2c1 = Persistent<Object>::New(Object::New());
2233  g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2234  g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2235  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2236  }
2237 
2238  Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2239 
2240  // Connect group 1 and 2, make a cycle.
2241  CHECK(g1s2->Set(0, g2s2));
2242  CHECK(g2s1->Set(0, g1s1));
2243 
2244  {
2245  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2246  Persistent<Value> g1_children[] = { g1c1 };
2247  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2248  Persistent<Value> g2_children[] = { g2c1 };
2249  V8::AddObjectGroup(g1_objects, 2);
2250  V8::AddImplicitReferences(g1s1, g1_children, 1);
2251  V8::AddObjectGroup(g2_objects, 2);
2252  V8::AddImplicitReferences(g2s2, g2_children, 1);
2253  }
2254  // Do a single full GC, ensure incremental marking is stopped.
2255  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2256 
2257  // All object should be alive.
2258  CHECK_EQ(0, counter.NumberOfWeakCalls());
2259 
2260  // Weaken the root.
2261  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2262  // But make children strong roots---all the objects (except for children)
2263  // should be collectable now.
2264  g1c1.ClearWeak();
2265  g2c1.ClearWeak();
2266 
2267  // Groups are deleted, rebuild groups.
2268  {
2269  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2270  Persistent<Value> g1_children[] = { g1c1 };
2271  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2272  Persistent<Value> g2_children[] = { g2c1 };
2273  V8::AddObjectGroup(g1_objects, 2);
2274  V8::AddImplicitReferences(g1s1, g1_children, 1);
2275  V8::AddObjectGroup(g2_objects, 2);
2276  V8::AddImplicitReferences(g2s2, g2_children, 1);
2277  }
2278 
2279  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2280 
2281  // All objects should be gone. 5 global handles in total.
2282  CHECK_EQ(5, counter.NumberOfWeakCalls());
2283 
2284  // And now make children weak again and collect them.
2285  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2286  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2287 
2288  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2289  CHECK_EQ(7, counter.NumberOfWeakCalls());
2290 }
2291 
2292 
2293 THREADED_TEST(ApiObjectGroupsCycle) {
2294  HandleScope scope;
2295  LocalContext env;
2296 
2297  WeakCallCounter counter(1234);
2298 
2299  Persistent<Object> g1s1;
2300  Persistent<Object> g1s2;
2301  Persistent<Object> g2s1;
2302  Persistent<Object> g2s2;
2303  Persistent<Object> g3s1;
2304  Persistent<Object> g3s2;
2305 
2306  {
2307  HandleScope scope;
2308  g1s1 = Persistent<Object>::New(Object::New());
2309  g1s2 = Persistent<Object>::New(Object::New());
2310  g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2311  g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2312 
2313  g2s1 = Persistent<Object>::New(Object::New());
2314  g2s2 = Persistent<Object>::New(Object::New());
2315  g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2316  g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2317 
2318  g3s1 = Persistent<Object>::New(Object::New());
2319  g3s2 = Persistent<Object>::New(Object::New());
2320  g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2321  g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2322  }
2323 
2324  Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2325 
2326  // Connect groups. We're building the following cycle:
2327  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2328  // groups.
2329  {
2330  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2331  Persistent<Value> g1_children[] = { g2s1 };
2332  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2333  Persistent<Value> g2_children[] = { g3s1 };
2334  Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2335  Persistent<Value> g3_children[] = { g1s1 };
2336  V8::AddObjectGroup(g1_objects, 2);
2337  V8::AddImplicitReferences(g1s1, g1_children, 1);
2338  V8::AddObjectGroup(g2_objects, 2);
2339  V8::AddImplicitReferences(g2s1, g2_children, 1);
2340  V8::AddObjectGroup(g3_objects, 2);
2341  V8::AddImplicitReferences(g3s1, g3_children, 1);
2342  }
2343  // Do a single full GC
2344  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2345 
2346  // All object should be alive.
2347  CHECK_EQ(0, counter.NumberOfWeakCalls());
2348 
2349  // Weaken the root.
2350  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2351 
2352  // Groups are deleted, rebuild groups.
2353  {
2354  Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2355  Persistent<Value> g1_children[] = { g2s1 };
2356  Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2357  Persistent<Value> g2_children[] = { g3s1 };
2358  Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2359  Persistent<Value> g3_children[] = { g1s1 };
2360  V8::AddObjectGroup(g1_objects, 2);
2361  V8::AddImplicitReferences(g1s1, g1_children, 1);
2362  V8::AddObjectGroup(g2_objects, 2);
2363  V8::AddImplicitReferences(g2s1, g2_children, 1);
2364  V8::AddObjectGroup(g3_objects, 2);
2365  V8::AddImplicitReferences(g3s1, g3_children, 1);
2366  }
2367 
2368  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2369 
2370  // All objects should be gone. 7 global handles in total.
2371  CHECK_EQ(7, counter.NumberOfWeakCalls());
2372 }
2373 
2374 
2375 THREADED_TEST(ScriptException) {
2376  v8::HandleScope scope;
2377  LocalContext env;
2378  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2379  v8::TryCatch try_catch;
2380  Local<Value> result = script->Run();
2381  CHECK(result.IsEmpty());
2382  CHECK(try_catch.HasCaught());
2383  String::AsciiValue exception_value(try_catch.Exception());
2384  CHECK_EQ(*exception_value, "panama!");
2385 }
2386 
2387 
2389 
2390 
2391 static void check_message(v8::Handle<v8::Message> message,
2392  v8::Handle<Value> data) {
2393  CHECK_EQ(5.76, data->NumberValue());
2394  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2395  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2396  message_received = true;
2397 }
2398 
2399 
2400 THREADED_TEST(MessageHandlerData) {
2401  message_received = false;
2402  v8::HandleScope scope;
2403  CHECK(!message_received);
2404  v8::V8::AddMessageListener(check_message, v8_num(5.76));
2405  LocalContext context;
2406  v8::ScriptOrigin origin =
2407  v8::ScriptOrigin(v8_str("6.75"));
2408  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2409  &origin);
2410  script->SetData(v8_str("7.56"));
2411  script->Run();
2412  CHECK(message_received);
2413  // clear out the message listener
2414  v8::V8::RemoveMessageListeners(check_message);
2415 }
2416 
2417 
2418 THREADED_TEST(GetSetProperty) {
2419  v8::HandleScope scope;
2420  LocalContext context;
2421  context->Global()->Set(v8_str("foo"), v8_num(14));
2422  context->Global()->Set(v8_str("12"), v8_num(92));
2423  context->Global()->Set(v8::Integer::New(16), v8_num(32));
2424  context->Global()->Set(v8_num(13), v8_num(56));
2425  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2426  CHECK_EQ(14, foo->Int32Value());
2427  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2428  CHECK_EQ(92, twelve->Int32Value());
2429  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2430  CHECK_EQ(32, sixteen->Int32Value());
2431  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2432  CHECK_EQ(56, thirteen->Int32Value());
2433  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2434  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2435  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2436  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2437  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2438  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2439  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2440  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2441  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2442 }
2443 
2444 
2446  v8::HandleScope scope;
2447  LocalContext context;
2448  // none
2449  Local<String> prop = v8_str("none");
2450  context->Global()->Set(prop, v8_num(7));
2451  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2452  // read-only
2453  prop = v8_str("read_only");
2454  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2455  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2456  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2457  Script::Compile(v8_str("read_only = 9"))->Run();
2458  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2459  context->Global()->Set(prop, v8_num(10));
2460  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2461  // dont-delete
2462  prop = v8_str("dont_delete");
2463  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2464  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2465  Script::Compile(v8_str("delete dont_delete"))->Run();
2466  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2467  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2468  // dont-enum
2469  prop = v8_str("dont_enum");
2470  context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2471  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2472  // absent
2473  prop = v8_str("absent");
2474  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2475  Local<Value> fake_prop = v8_num(1);
2476  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2477  // exception
2478  TryCatch try_catch;
2479  Local<Value> exception =
2480  CompileRun("({ toString: function() { throw 'exception';} })");
2481  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2482  CHECK(try_catch.HasCaught());
2483  String::AsciiValue exception_value(try_catch.Exception());
2484  CHECK_EQ("exception", *exception_value);
2485  try_catch.Reset();
2486 }
2487 
2488 
2490  v8::HandleScope scope;
2491  LocalContext context;
2492  Local<v8::Array> array = v8::Array::New();
2493  CHECK_EQ(0, array->Length());
2494  CHECK(array->Get(0)->IsUndefined());
2495  CHECK(!array->Has(0));
2496  CHECK(array->Get(100)->IsUndefined());
2497  CHECK(!array->Has(100));
2498  array->Set(2, v8_num(7));
2499  CHECK_EQ(3, array->Length());
2500  CHECK(!array->Has(0));
2501  CHECK(!array->Has(1));
2502  CHECK(array->Has(2));
2503  CHECK_EQ(7, array->Get(2)->Int32Value());
2504  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2505  Local<v8::Array> arr = obj.As<v8::Array>();
2506  CHECK_EQ(3, arr->Length());
2507  CHECK_EQ(1, arr->Get(0)->Int32Value());
2508  CHECK_EQ(2, arr->Get(1)->Int32Value());
2509  CHECK_EQ(3, arr->Get(2)->Int32Value());
2510  array = v8::Array::New(27);
2511  CHECK_EQ(27, array->Length());
2512  array = v8::Array::New(-27);
2513  CHECK_EQ(0, array->Length());
2514 }
2515 
2516 
2518  v8::HandleScope scope;
2520  Local<v8::Array> result = v8::Array::New(args.Length());
2521  for (int i = 0; i < args.Length(); i++)
2522  result->Set(i, args[i]);
2523  return scope.Close(result);
2524 }
2525 
2526 
2527 THREADED_TEST(Vector) {
2528  v8::HandleScope scope;
2529  Local<ObjectTemplate> global = ObjectTemplate::New();
2530  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2531  LocalContext context(0, global);
2532 
2533  const char* fun = "f()";
2534  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2535  CHECK_EQ(0, a0->Length());
2536 
2537  const char* fun2 = "f(11)";
2538  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2539  CHECK_EQ(1, a1->Length());
2540  CHECK_EQ(11, a1->Get(0)->Int32Value());
2541 
2542  const char* fun3 = "f(12, 13)";
2543  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2544  CHECK_EQ(2, a2->Length());
2545  CHECK_EQ(12, a2->Get(0)->Int32Value());
2546  CHECK_EQ(13, a2->Get(1)->Int32Value());
2547 
2548  const char* fun4 = "f(14, 15, 16)";
2549  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2550  CHECK_EQ(3, a3->Length());
2551  CHECK_EQ(14, a3->Get(0)->Int32Value());
2552  CHECK_EQ(15, a3->Get(1)->Int32Value());
2553  CHECK_EQ(16, a3->Get(2)->Int32Value());
2554 
2555  const char* fun5 = "f(17, 18, 19, 20)";
2556  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2557  CHECK_EQ(4, a4->Length());
2558  CHECK_EQ(17, a4->Get(0)->Int32Value());
2559  CHECK_EQ(18, a4->Get(1)->Int32Value());
2560  CHECK_EQ(19, a4->Get(2)->Int32Value());
2561  CHECK_EQ(20, a4->Get(3)->Int32Value());
2562 }
2563 
2564 
2565 THREADED_TEST(FunctionCall) {
2566  v8::HandleScope scope;
2567  LocalContext context;
2568  CompileRun(
2569  "function Foo() {"
2570  " var result = [];"
2571  " for (var i = 0; i < arguments.length; i++) {"
2572  " result.push(arguments[i]);"
2573  " }"
2574  " return result;"
2575  "}");
2576  Local<Function> Foo =
2577  Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2578 
2579  v8::Handle<Value>* args0 = NULL;
2580  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2581  CHECK_EQ(0, a0->Length());
2582 
2583  v8::Handle<Value> args1[] = { v8_num(1.1) };
2584  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2585  CHECK_EQ(1, a1->Length());
2586  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2587 
2588  v8::Handle<Value> args2[] = { v8_num(2.2),
2589  v8_num(3.3) };
2590  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2591  CHECK_EQ(2, a2->Length());
2592  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2593  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2594 
2595  v8::Handle<Value> args3[] = { v8_num(4.4),
2596  v8_num(5.5),
2597  v8_num(6.6) };
2598  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2599  CHECK_EQ(3, a3->Length());
2600  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2601  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2602  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2603 
2604  v8::Handle<Value> args4[] = { v8_num(7.7),
2605  v8_num(8.8),
2606  v8_num(9.9),
2607  v8_num(10.11) };
2608  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2609  CHECK_EQ(4, a4->Length());
2610  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2611  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2612  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2613  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2614 }
2615 
2616 
2617 static const char* js_code_causing_out_of_memory =
2618  "var a = new Array(); while(true) a.push(a);";
2619 
2620 
2621 // These tests run for a long time and prevent us from running tests
2622 // that come after them so they cannot run in parallel.
2623 TEST(OutOfMemory) {
2624  // It's not possible to read a snapshot into a heap with different dimensions.
2625  if (i::Snapshot::IsEnabled()) return;
2626  // Set heap limits.
2627  static const int K = 1024;
2628  v8::ResourceConstraints constraints;
2629  constraints.set_max_young_space_size(256 * K);
2630  constraints.set_max_old_space_size(4 * K * K);
2631  v8::SetResourceConstraints(&constraints);
2632 
2633  // Execute a script that causes out of memory.
2634  v8::HandleScope scope;
2635  LocalContext context;
2637  Local<Script> script =
2638  Script::Compile(String::New(js_code_causing_out_of_memory));
2639  Local<Value> result = script->Run();
2640 
2641  // Check for out of memory state.
2642  CHECK(result.IsEmpty());
2643  CHECK(context->HasOutOfMemoryException());
2644 }
2645 
2646 
2649 
2650  v8::HandleScope scope;
2651  LocalContext context;
2652  Local<Script> script =
2653  Script::Compile(String::New(js_code_causing_out_of_memory));
2654  Local<Value> result = script->Run();
2655 
2656  // Check for out of memory state.
2657  CHECK(result.IsEmpty());
2658  CHECK(context->HasOutOfMemoryException());
2659 
2660  return result;
2661 }
2662 
2663 
2664 TEST(OutOfMemoryNested) {
2665  // It's not possible to read a snapshot into a heap with different dimensions.
2666  if (i::Snapshot::IsEnabled()) return;
2667  // Set heap limits.
2668  static const int K = 1024;
2669  v8::ResourceConstraints constraints;
2670  constraints.set_max_young_space_size(256 * K);
2671  constraints.set_max_old_space_size(4 * K * K);
2672  v8::SetResourceConstraints(&constraints);
2673 
2674  v8::HandleScope scope;
2675  Local<ObjectTemplate> templ = ObjectTemplate::New();
2676  templ->Set(v8_str("ProvokeOutOfMemory"),
2678  LocalContext context(0, templ);
2680  Local<Value> result = CompileRun(
2681  "var thrown = false;"
2682  "try {"
2683  " ProvokeOutOfMemory();"
2684  "} catch (e) {"
2685  " thrown = true;"
2686  "}");
2687  // Check for out of memory state.
2688  CHECK(result.IsEmpty());
2689  CHECK(context->HasOutOfMemoryException());
2690 }
2691 
2692 
2693 TEST(HugeConsStringOutOfMemory) {
2694  // It's not possible to read a snapshot into a heap with different dimensions.
2695  if (i::Snapshot::IsEnabled()) return;
2696  // Set heap limits.
2697  static const int K = 1024;
2698  v8::ResourceConstraints constraints;
2699  constraints.set_max_young_space_size(256 * K);
2700  constraints.set_max_old_space_size(2 * K * K);
2701  v8::SetResourceConstraints(&constraints);
2702 
2703  // Execute a script that causes out of memory.
2705 
2706  v8::HandleScope scope;
2707  LocalContext context;
2708 
2709  // Build huge string. This should fail with out of memory exception.
2710  Local<Value> result = CompileRun(
2711  "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2712  "for (var i = 0; i < 22; i++) { str = str + str; }");
2713 
2714  // Check for out of memory state.
2715  CHECK(result.IsEmpty());
2716  CHECK(context->HasOutOfMemoryException());
2717 }
2718 
2719 
2720 THREADED_TEST(ConstructCall) {
2721  v8::HandleScope scope;
2722  LocalContext context;
2723  CompileRun(
2724  "function Foo() {"
2725  " var result = [];"
2726  " for (var i = 0; i < arguments.length; i++) {"
2727  " result.push(arguments[i]);"
2728  " }"
2729  " return result;"
2730  "}");
2731  Local<Function> Foo =
2732  Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2733 
2734  v8::Handle<Value>* args0 = NULL;
2735  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2736  CHECK_EQ(0, a0->Length());
2737 
2738  v8::Handle<Value> args1[] = { v8_num(1.1) };
2739  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2740  CHECK_EQ(1, a1->Length());
2741  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2742 
2743  v8::Handle<Value> args2[] = { v8_num(2.2),
2744  v8_num(3.3) };
2745  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2746  CHECK_EQ(2, a2->Length());
2747  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2748  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2749 
2750  v8::Handle<Value> args3[] = { v8_num(4.4),
2751  v8_num(5.5),
2752  v8_num(6.6) };
2753  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2754  CHECK_EQ(3, a3->Length());
2755  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2756  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2757  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2758 
2759  v8::Handle<Value> args4[] = { v8_num(7.7),
2760  v8_num(8.8),
2761  v8_num(9.9),
2762  v8_num(10.11) };
2763  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2764  CHECK_EQ(4, a4->Length());
2765  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2766  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2767  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2768  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2769 }
2770 
2771 
2772 static void CheckUncle(v8::TryCatch* try_catch) {
2773  CHECK(try_catch->HasCaught());
2774  String::AsciiValue str_value(try_catch->Exception());
2775  CHECK_EQ(*str_value, "uncle?");
2776  try_catch->Reset();
2777 }
2778 
2779 
2780 THREADED_TEST(ConversionNumber) {
2781  v8::HandleScope scope;
2782  LocalContext env;
2783  // Very large number.
2784  CompileRun("var obj = Math.pow(2,32) * 1237;");
2785  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2786  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2787  CHECK_EQ(0, obj->ToInt32()->Value());
2788  CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2789  // Large number.
2790  CompileRun("var obj = -1234567890123;");
2791  obj = env->Global()->Get(v8_str("obj"));
2792  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2793  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2794  CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2795  // Small positive integer.
2796  CompileRun("var obj = 42;");
2797  obj = env->Global()->Get(v8_str("obj"));
2798  CHECK_EQ(42.0, obj->ToNumber()->Value());
2799  CHECK_EQ(42, obj->ToInt32()->Value());
2800  CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2801  // Negative integer.
2802  CompileRun("var obj = -37;");
2803  obj = env->Global()->Get(v8_str("obj"));
2804  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2805  CHECK_EQ(-37, obj->ToInt32()->Value());
2806  CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2807  // Positive non-int32 integer.
2808  CompileRun("var obj = 0x81234567;");
2809  obj = env->Global()->Get(v8_str("obj"));
2810  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2811  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2812  CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2813  // Fraction.
2814  CompileRun("var obj = 42.3;");
2815  obj = env->Global()->Get(v8_str("obj"));
2816  CHECK_EQ(42.3, obj->ToNumber()->Value());
2817  CHECK_EQ(42, obj->ToInt32()->Value());
2818  CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2819  // Large negative fraction.
2820  CompileRun("var obj = -5726623061.75;");
2821  obj = env->Global()->Get(v8_str("obj"));
2822  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2823  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2824  CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2825 }
2826 
2827 
2828 THREADED_TEST(isNumberType) {
2829  v8::HandleScope scope;
2830  LocalContext env;
2831  // Very large number.
2832  CompileRun("var obj = Math.pow(2,32) * 1237;");
2833  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2834  CHECK(!obj->IsInt32());
2835  CHECK(!obj->IsUint32());
2836  // Large negative number.
2837  CompileRun("var obj = -1234567890123;");
2838  obj = env->Global()->Get(v8_str("obj"));
2839  CHECK(!obj->IsInt32());
2840  CHECK(!obj->IsUint32());
2841  // Small positive integer.
2842  CompileRun("var obj = 42;");
2843  obj = env->Global()->Get(v8_str("obj"));
2844  CHECK(obj->IsInt32());
2845  CHECK(obj->IsUint32());
2846  // Negative integer.
2847  CompileRun("var obj = -37;");
2848  obj = env->Global()->Get(v8_str("obj"));
2849  CHECK(obj->IsInt32());
2850  CHECK(!obj->IsUint32());
2851  // Positive non-int32 integer.
2852  CompileRun("var obj = 0x81234567;");
2853  obj = env->Global()->Get(v8_str("obj"));
2854  CHECK(!obj->IsInt32());
2855  CHECK(obj->IsUint32());
2856  // Fraction.
2857  CompileRun("var obj = 42.3;");
2858  obj = env->Global()->Get(v8_str("obj"));
2859  CHECK(!obj->IsInt32());
2860  CHECK(!obj->IsUint32());
2861  // Large negative fraction.
2862  CompileRun("var obj = -5726623061.75;");
2863  obj = env->Global()->Get(v8_str("obj"));
2864  CHECK(!obj->IsInt32());
2865  CHECK(!obj->IsUint32());
2866  // Positive zero
2867  CompileRun("var obj = 0.0;");
2868  obj = env->Global()->Get(v8_str("obj"));
2869  CHECK(obj->IsInt32());
2870  CHECK(obj->IsUint32());
2871  // Positive zero
2872  CompileRun("var obj = -0.0;");
2873  obj = env->Global()->Get(v8_str("obj"));
2874  CHECK(!obj->IsInt32());
2875  CHECK(!obj->IsUint32());
2876 }
2877 
2878 
2879 THREADED_TEST(ConversionException) {
2880  v8::HandleScope scope;
2881  LocalContext env;
2882  CompileRun(
2883  "function TestClass() { };"
2884  "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2885  "var obj = new TestClass();");
2886  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2887 
2888  v8::TryCatch try_catch;
2889 
2890  Local<Value> to_string_result = obj->ToString();
2891  CHECK(to_string_result.IsEmpty());
2892  CheckUncle(&try_catch);
2893 
2894  Local<Value> to_number_result = obj->ToNumber();
2895  CHECK(to_number_result.IsEmpty());
2896  CheckUncle(&try_catch);
2897 
2898  Local<Value> to_integer_result = obj->ToInteger();
2899  CHECK(to_integer_result.IsEmpty());
2900  CheckUncle(&try_catch);
2901 
2902  Local<Value> to_uint32_result = obj->ToUint32();
2903  CHECK(to_uint32_result.IsEmpty());
2904  CheckUncle(&try_catch);
2905 
2906  Local<Value> to_int32_result = obj->ToInt32();
2907  CHECK(to_int32_result.IsEmpty());
2908  CheckUncle(&try_catch);
2909 
2910  Local<Value> to_object_result = v8::Undefined()->ToObject();
2911  CHECK(to_object_result.IsEmpty());
2912  CHECK(try_catch.HasCaught());
2913  try_catch.Reset();
2914 
2915  int32_t int32_value = obj->Int32Value();
2916  CHECK_EQ(0, int32_value);
2917  CheckUncle(&try_catch);
2918 
2919  uint32_t uint32_value = obj->Uint32Value();
2920  CHECK_EQ(0, uint32_value);
2921  CheckUncle(&try_catch);
2922 
2923  double number_value = obj->NumberValue();
2924  CHECK_NE(0, IsNaN(number_value));
2925  CheckUncle(&try_catch);
2926 
2927  int64_t integer_value = obj->IntegerValue();
2928  CHECK_EQ(0.0, static_cast<double>(integer_value));
2929  CheckUncle(&try_catch);
2930 }
2931 
2932 
2935  return v8::ThrowException(v8_str("konto"));
2936 }
2937 
2938 
2940  if (args.Length() < 1) return v8::False();
2941  v8::HandleScope scope;
2942  v8::TryCatch try_catch;
2943  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2944  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2945  return v8::Boolean::New(try_catch.HasCaught());
2946 }
2947 
2948 
2949 THREADED_TEST(APICatch) {
2950  v8::HandleScope scope;
2951  Local<ObjectTemplate> templ = ObjectTemplate::New();
2952  templ->Set(v8_str("ThrowFromC"),
2954  LocalContext context(0, templ);
2955  CompileRun(
2956  "var thrown = false;"
2957  "try {"
2958  " ThrowFromC();"
2959  "} catch (e) {"
2960  " thrown = true;"
2961  "}");
2962  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2963  CHECK(thrown->BooleanValue());
2964 }
2965 
2966 
2967 THREADED_TEST(APIThrowTryCatch) {
2968  v8::HandleScope scope;
2969  Local<ObjectTemplate> templ = ObjectTemplate::New();
2970  templ->Set(v8_str("ThrowFromC"),
2972  LocalContext context(0, templ);
2973  v8::TryCatch try_catch;
2974  CompileRun("ThrowFromC();");
2975  CHECK(try_catch.HasCaught());
2976 }
2977 
2978 
2979 // Test that a try-finally block doesn't shadow a try-catch block
2980 // when setting up an external handler.
2981 //
2982 // BUG(271): Some of the exception propagation does not work on the
2983 // ARM simulator because the simulator separates the C++ stack and the
2984 // JS stack. This test therefore fails on the simulator. The test is
2985 // not threaded to allow the threading tests to run on the simulator.
2986 TEST(TryCatchInTryFinally) {
2987  v8::HandleScope scope;
2988  Local<ObjectTemplate> templ = ObjectTemplate::New();
2989  templ->Set(v8_str("CCatcher"),
2991  LocalContext context(0, templ);
2992  Local<Value> result = CompileRun("try {"
2993  " try {"
2994  " CCatcher('throw 7;');"
2995  " } finally {"
2996  " }"
2997  "} catch (e) {"
2998  "}");
2999  CHECK(result->IsTrue());
3000 }
3001 
3002 
3003 static void check_reference_error_message(
3004  v8::Handle<v8::Message> message,
3005  v8::Handle<v8::Value> data) {
3006  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3007  CHECK(message->Get()->Equals(v8_str(reference_error)));
3008 }
3009 
3010 
3011 static v8::Handle<Value> Fail(const v8::Arguments& args) {
3013  CHECK(false);
3014  return v8::Undefined();
3015 }
3016 
3017 
3018 // Test that overwritten methods are not invoked on uncaught exception
3019 // formatting. However, they are invoked when performing normal error
3020 // string conversions.
3021 TEST(APIThrowMessageOverwrittenToString) {
3022  v8::HandleScope scope;
3023  v8::V8::AddMessageListener(check_reference_error_message);
3024  Local<ObjectTemplate> templ = ObjectTemplate::New();
3025  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3026  LocalContext context(NULL, templ);
3027  CompileRun("asdf;");
3028  CompileRun("var limit = {};"
3029  "limit.valueOf = fail;"
3030  "Error.stackTraceLimit = limit;");
3031  CompileRun("asdf");
3032  CompileRun("Array.prototype.pop = fail;");
3033  CompileRun("Object.prototype.hasOwnProperty = fail;");
3034  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
3035  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3036  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
3037  CompileRun("ReferenceError.prototype.toString ="
3038  " function() { return 'Whoops' }");
3039  CompileRun("asdf;");
3040  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3041  CompileRun("asdf;");
3042  CompileRun("ReferenceError.prototype.constructor = void 0;");
3043  CompileRun("asdf;");
3044  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3045  CompileRun("asdf;");
3046  CompileRun("ReferenceError.prototype = new Object();");
3047  CompileRun("asdf;");
3048  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3049  CHECK(string->Equals(v8_str("Whoops")));
3050  CompileRun("ReferenceError.prototype.constructor = new Object();"
3051  "ReferenceError.prototype.constructor.name = 1;"
3052  "Number.prototype.toString = function() { return 'Whoops'; };"
3053  "ReferenceError.prototype.toString = Object.prototype.toString;");
3054  CompileRun("asdf;");
3055  v8::V8::RemoveMessageListeners(check_message);
3056 }
3057 
3058 
3059 static void receive_message(v8::Handle<v8::Message> message,
3060  v8::Handle<v8::Value> data) {
3061  message->Get();
3062  message_received = true;
3063 }
3064 
3065 
3066 TEST(APIThrowMessage) {
3067  message_received = false;
3068  v8::HandleScope scope;
3069  v8::V8::AddMessageListener(receive_message);
3070  Local<ObjectTemplate> templ = ObjectTemplate::New();
3071  templ->Set(v8_str("ThrowFromC"),
3073  LocalContext context(0, templ);
3074  CompileRun("ThrowFromC();");
3075  CHECK(message_received);
3076  v8::V8::RemoveMessageListeners(check_message);
3077 }
3078 
3079 
3080 TEST(APIThrowMessageAndVerboseTryCatch) {
3081  message_received = false;
3082  v8::HandleScope scope;
3083  v8::V8::AddMessageListener(receive_message);
3084  Local<ObjectTemplate> templ = ObjectTemplate::New();
3085  templ->Set(v8_str("ThrowFromC"),
3087  LocalContext context(0, templ);
3088  v8::TryCatch try_catch;
3089  try_catch.SetVerbose(true);
3090  Local<Value> result = CompileRun("ThrowFromC();");
3091  CHECK(try_catch.HasCaught());
3092  CHECK(result.IsEmpty());
3093  CHECK(message_received);
3094  v8::V8::RemoveMessageListeners(check_message);
3095 }
3096 
3097 
3098 TEST(APIStackOverflowAndVerboseTryCatch) {
3099  message_received = false;
3100  v8::HandleScope scope;
3101  v8::V8::AddMessageListener(receive_message);
3102  LocalContext context;
3103  v8::TryCatch try_catch;
3104  try_catch.SetVerbose(true);
3105  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3106  CHECK(try_catch.HasCaught());
3107  CHECK(result.IsEmpty());
3108  CHECK(message_received);
3109  v8::V8::RemoveMessageListeners(receive_message);
3110 }
3111 
3112 
3113 THREADED_TEST(ExternalScriptException) {
3114  v8::HandleScope scope;
3115  Local<ObjectTemplate> templ = ObjectTemplate::New();
3116  templ->Set(v8_str("ThrowFromC"),
3118  LocalContext context(0, templ);
3119 
3120  v8::TryCatch try_catch;
3121  Local<Script> script
3122  = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3123  Local<Value> result = script->Run();
3124  CHECK(result.IsEmpty());
3125  CHECK(try_catch.HasCaught());
3126  String::AsciiValue exception_value(try_catch.Exception());
3127  CHECK_EQ("konto", *exception_value);
3128 }
3129 
3130 
3131 
3134  CHECK_EQ(4, args.Length());
3135  int count = args[0]->Int32Value();
3136  int cInterval = args[2]->Int32Value();
3137  if (count == 0) {
3138  return v8::ThrowException(v8_str("FromC"));
3139  } else {
3140  Local<v8::Object> global = Context::GetCurrent()->Global();
3141  Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3142  v8::Handle<Value> argv[] = { v8_num(count - 1),
3143  args[1],
3144  args[2],
3145  args[3] };
3146  if (count % cInterval == 0) {
3147  v8::TryCatch try_catch;
3148  Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3149  int expected = args[3]->Int32Value();
3150  if (try_catch.HasCaught()) {
3151  CHECK_EQ(expected, count);
3152  CHECK(result.IsEmpty());
3153  CHECK(!i::Isolate::Current()->has_scheduled_exception());
3154  } else {
3155  CHECK_NE(expected, count);
3156  }
3157  return result;
3158  } else {
3159  return fun.As<Function>()->Call(global, 4, argv);
3160  }
3161  }
3162 }
3163 
3164 
3167  CHECK_EQ(3, args.Length());
3168  bool equality = args[0]->BooleanValue();
3169  int count = args[1]->Int32Value();
3170  int expected = args[2]->Int32Value();
3171  if (equality) {
3172  CHECK_EQ(count, expected);
3173  } else {
3174  CHECK_NE(count, expected);
3175  }
3176  return v8::Undefined();
3177 }
3178 
3179 
3180 THREADED_TEST(EvalInTryFinally) {
3181  v8::HandleScope scope;
3182  LocalContext context;
3183  v8::TryCatch try_catch;
3184  CompileRun("(function() {"
3185  " try {"
3186  " eval('asldkf (*&^&*^');"
3187  " } finally {"
3188  " return;"
3189  " }"
3190  "})()");
3191  CHECK(!try_catch.HasCaught());
3192 }
3193 
3194 
3195 // This test works by making a stack of alternating JavaScript and C
3196 // activations. These activations set up exception handlers with regular
3197 // intervals, one interval for C activations and another for JavaScript
3198 // activations. When enough activations have been created an exception is
3199 // thrown and we check that the right activation catches the exception and that
3200 // no other activations do. The right activation is always the topmost one with
3201 // a handler, regardless of whether it is in JavaScript or C.
3202 //
3203 // The notation used to describe a test case looks like this:
3204 //
3205 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3206 //
3207 // Each entry is an activation, either JS or C. The index is the count at that
3208 // level. Stars identify activations with exception handlers, the @ identifies
3209 // the exception handler that should catch the exception.
3210 //
3211 // BUG(271): Some of the exception propagation does not work on the
3212 // ARM simulator because the simulator separates the C++ stack and the
3213 // JS stack. This test therefore fails on the simulator. The test is
3214 // not threaded to allow the threading tests to run on the simulator.
3215 TEST(ExceptionOrder) {
3216  v8::HandleScope scope;
3217  Local<ObjectTemplate> templ = ObjectTemplate::New();
3218  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3219  templ->Set(v8_str("CThrowCountDown"),
3221  LocalContext context(0, templ);
3222  CompileRun(
3223  "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3224  " if (count == 0) throw 'FromJS';"
3225  " if (count % jsInterval == 0) {"
3226  " try {"
3227  " var value = CThrowCountDown(count - 1,"
3228  " jsInterval,"
3229  " cInterval,"
3230  " expected);"
3231  " check(false, count, expected);"
3232  " return value;"
3233  " } catch (e) {"
3234  " check(true, count, expected);"
3235  " }"
3236  " } else {"
3237  " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3238  " }"
3239  "}");
3240  Local<Function> fun =
3241  Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3242 
3243  const int argc = 4;
3244  // count jsInterval cInterval expected
3245 
3246  // *JS[4] *C[3] @JS[2] C[1] JS[0]
3247  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3248  fun->Call(fun, argc, a0);
3249 
3250  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3251  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3252  fun->Call(fun, argc, a1);
3253 
3254  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3255  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3256  fun->Call(fun, argc, a2);
3257 
3258  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3259  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3260  fun->Call(fun, argc, a3);
3261 
3262  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3263  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3264  fun->Call(fun, argc, a4);
3265 
3266  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3267  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3268  fun->Call(fun, argc, a5);
3269 }
3270 
3271 
3274  CHECK_EQ(1, args.Length());
3275  return v8::ThrowException(args[0]);
3276 }
3277 
3278 
3279 THREADED_TEST(ThrowValues) {
3280  v8::HandleScope scope;
3281  Local<ObjectTemplate> templ = ObjectTemplate::New();
3282  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3283  LocalContext context(0, templ);
3285  "function Run(obj) {"
3286  " try {"
3287  " Throw(obj);"
3288  " } catch (e) {"
3289  " return e;"
3290  " }"
3291  " return 'no exception';"
3292  "}"
3293  "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3294  CHECK_EQ(5, result->Length());
3295  CHECK(result->Get(v8::Integer::New(0))->IsString());
3296  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3297  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3298  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3299  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3300  CHECK(result->Get(v8::Integer::New(3))->IsNull());
3301  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3302 }
3303 
3304 
3305 THREADED_TEST(CatchZero) {
3306  v8::HandleScope scope;
3307  LocalContext context;
3308  v8::TryCatch try_catch;
3309  CHECK(!try_catch.HasCaught());
3310  Script::Compile(v8_str("throw 10"))->Run();
3311  CHECK(try_catch.HasCaught());
3312  CHECK_EQ(10, try_catch.Exception()->Int32Value());
3313  try_catch.Reset();
3314  CHECK(!try_catch.HasCaught());
3315  Script::Compile(v8_str("throw 0"))->Run();
3316  CHECK(try_catch.HasCaught());
3317  CHECK_EQ(0, try_catch.Exception()->Int32Value());
3318 }
3319 
3320 
3321 THREADED_TEST(CatchExceptionFromWith) {
3322  v8::HandleScope scope;
3323  LocalContext context;
3324  v8::TryCatch try_catch;
3325  CHECK(!try_catch.HasCaught());
3326  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3327  CHECK(try_catch.HasCaught());
3328 }
3329 
3330 
3331 THREADED_TEST(TryCatchAndFinallyHidingException) {
3332  v8::HandleScope scope;
3333  LocalContext context;
3334  v8::TryCatch try_catch;
3335  CHECK(!try_catch.HasCaught());
3336  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3337  CompileRun("f({toString: function() { throw 42; }});");
3338  CHECK(!try_catch.HasCaught());
3339 }
3340 
3341 
3343  v8::TryCatch try_catch;
3344  return v8::Undefined();
3345 }
3346 
3347 
3348 THREADED_TEST(TryCatchAndFinally) {
3349  v8::HandleScope scope;
3350  LocalContext context;
3351  context->Global()->Set(
3352  v8_str("native_with_try_catch"),
3353  v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3354  v8::TryCatch try_catch;
3355  CHECK(!try_catch.HasCaught());
3356  CompileRun(
3357  "try {\n"
3358  " throw new Error('a');\n"
3359  "} finally {\n"
3360  " native_with_try_catch();\n"
3361  "}\n");
3362  CHECK(try_catch.HasCaught());
3363 }
3364 
3365 
3366 THREADED_TEST(Equality) {
3367  v8::HandleScope scope;
3368  LocalContext context;
3369  // Check that equality works at all before relying on CHECK_EQ
3370  CHECK(v8_str("a")->Equals(v8_str("a")));
3371  CHECK(!v8_str("a")->Equals(v8_str("b")));
3372 
3373  CHECK_EQ(v8_str("a"), v8_str("a"));
3374  CHECK_NE(v8_str("a"), v8_str("b"));
3375  CHECK_EQ(v8_num(1), v8_num(1));
3376  CHECK_EQ(v8_num(1.00), v8_num(1));
3377  CHECK_NE(v8_num(1), v8_num(2));
3378 
3379  // Assume String is not symbol.
3380  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3381  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3382  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3383  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3384  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3385  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3386  Local<Value> not_a_number = v8_num(i::OS::nan_value());
3387  CHECK(!not_a_number->StrictEquals(not_a_number));
3388  CHECK(v8::False()->StrictEquals(v8::False()));
3389  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3390 
3393  CHECK(alias->StrictEquals(obj));
3394  alias.Dispose();
3395 }
3396 
3397 
3398 THREADED_TEST(MultiRun) {
3399  v8::HandleScope scope;
3400  LocalContext context;
3401  Local<Script> script = Script::Compile(v8_str("x"));
3402  for (int i = 0; i < 10; i++)
3403  script->Run();
3404 }
3405 
3406 
3407 static v8::Handle<Value> GetXValue(Local<String> name,
3408  const AccessorInfo& info) {
3410  CHECK_EQ(info.Data(), v8_str("donut"));
3411  CHECK_EQ(name, v8_str("x"));
3412  return name;
3413 }
3414 
3415 
3416 THREADED_TEST(SimplePropertyRead) {
3417  v8::HandleScope scope;
3418  Local<ObjectTemplate> templ = ObjectTemplate::New();
3419  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3420  LocalContext context;
3421  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3422  Local<Script> script = Script::Compile(v8_str("obj.x"));
3423  for (int i = 0; i < 10; i++) {
3424  Local<Value> result = script->Run();
3425  CHECK_EQ(result, v8_str("x"));
3426  }
3427 }
3428 
3429 THREADED_TEST(DefinePropertyOnAPIAccessor) {
3430  v8::HandleScope scope;
3431  Local<ObjectTemplate> templ = ObjectTemplate::New();
3432  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3433  LocalContext context;
3434  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3435 
3436  // Uses getOwnPropertyDescriptor to check the configurable status
3437  Local<Script> script_desc
3438  = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3439  "obj, 'x');"
3440  "prop.configurable;"));
3441  Local<Value> result = script_desc->Run();
3442  CHECK_EQ(result->BooleanValue(), true);
3443 
3444  // Redefine get - but still configurable
3445  Local<Script> script_define
3446  = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3447  " configurable: true };"
3448  "Object.defineProperty(obj, 'x', desc);"
3449  "obj.x"));
3450  result = script_define->Run();
3451  CHECK_EQ(result, v8_num(42));
3452 
3453  // Check that the accessor is still configurable
3454  result = script_desc->Run();
3455  CHECK_EQ(result->BooleanValue(), true);
3456 
3457  // Redefine to a non-configurable
3458  script_define
3459  = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3460  " configurable: false };"
3461  "Object.defineProperty(obj, 'x', desc);"
3462  "obj.x"));
3463  result = script_define->Run();
3464  CHECK_EQ(result, v8_num(43));
3465  result = script_desc->Run();
3466  CHECK_EQ(result->BooleanValue(), false);
3467 
3468  // Make sure that it is not possible to redefine again
3469  v8::TryCatch try_catch;
3470  result = script_define->Run();
3471  CHECK(try_catch.HasCaught());
3472  String::AsciiValue exception_value(try_catch.Exception());
3473  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3474 }
3475 
3476 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3477  v8::HandleScope scope;
3478  Local<ObjectTemplate> templ = ObjectTemplate::New();
3479  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3480  LocalContext context;
3481  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3482 
3483  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3484  "Object.getOwnPropertyDescriptor( "
3485  "obj, 'x');"
3486  "prop.configurable;"));
3487  Local<Value> result = script_desc->Run();
3488  CHECK_EQ(result->BooleanValue(), true);
3489 
3490  Local<Script> script_define =
3491  Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3492  " configurable: true };"
3493  "Object.defineProperty(obj, 'x', desc);"
3494  "obj.x"));
3495  result = script_define->Run();
3496  CHECK_EQ(result, v8_num(42));
3497 
3498 
3499  result = script_desc->Run();
3500  CHECK_EQ(result->BooleanValue(), true);
3501 
3502 
3503  script_define =
3504  Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3505  " configurable: false };"
3506  "Object.defineProperty(obj, 'x', desc);"
3507  "obj.x"));
3508  result = script_define->Run();
3509  CHECK_EQ(result, v8_num(43));
3510  result = script_desc->Run();
3511 
3512  CHECK_EQ(result->BooleanValue(), false);
3513 
3514  v8::TryCatch try_catch;
3515  result = script_define->Run();
3516  CHECK(try_catch.HasCaught());
3517  String::AsciiValue exception_value(try_catch.Exception());
3518  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3519 }
3520 
3521 
3522 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3523  char const* name) {
3524  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3525 }
3526 
3527 
3528 THREADED_TEST(DefineAPIAccessorOnObject) {
3529  v8::HandleScope scope;
3530  Local<ObjectTemplate> templ = ObjectTemplate::New();
3531  LocalContext context;
3532 
3533  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3534  CompileRun("var obj2 = {};");
3535 
3536  CHECK(CompileRun("obj1.x")->IsUndefined());
3537  CHECK(CompileRun("obj2.x")->IsUndefined());
3538 
3539  CHECK(GetGlobalProperty(&context, "obj1")->
3540  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541 
3542  ExpectString("obj1.x", "x");
3543  CHECK(CompileRun("obj2.x")->IsUndefined());
3544 
3545  CHECK(GetGlobalProperty(&context, "obj2")->
3546  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3547 
3548  ExpectString("obj1.x", "x");
3549  ExpectString("obj2.x", "x");
3550 
3551  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3552  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3553 
3554  CompileRun("Object.defineProperty(obj1, 'x',"
3555  "{ get: function() { return 'y'; }, configurable: true })");
3556 
3557  ExpectString("obj1.x", "y");
3558  ExpectString("obj2.x", "x");
3559 
3560  CompileRun("Object.defineProperty(obj2, 'x',"
3561  "{ get: function() { return 'y'; }, configurable: true })");
3562 
3563  ExpectString("obj1.x", "y");
3564  ExpectString("obj2.x", "y");
3565 
3566  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3567  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3568 
3569  CHECK(GetGlobalProperty(&context, "obj1")->
3570  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3571  CHECK(GetGlobalProperty(&context, "obj2")->
3572  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3573 
3574  ExpectString("obj1.x", "x");
3575  ExpectString("obj2.x", "x");
3576 
3577  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3578  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3579 
3580  // Define getters/setters, but now make them not configurable.
3581  CompileRun("Object.defineProperty(obj1, 'x',"
3582  "{ get: function() { return 'z'; }, configurable: false })");
3583  CompileRun("Object.defineProperty(obj2, 'x',"
3584  "{ get: function() { return 'z'; }, configurable: false })");
3585 
3586  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3587  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3588 
3589  ExpectString("obj1.x", "z");
3590  ExpectString("obj2.x", "z");
3591 
3592  CHECK(!GetGlobalProperty(&context, "obj1")->
3593  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3594  CHECK(!GetGlobalProperty(&context, "obj2")->
3595  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3596 
3597  ExpectString("obj1.x", "z");
3598  ExpectString("obj2.x", "z");
3599 }
3600 
3601 
3602 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3603  v8::HandleScope scope;
3604  Local<ObjectTemplate> templ = ObjectTemplate::New();
3605  LocalContext context;
3606 
3607  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3608  CompileRun("var obj2 = {};");
3609 
3610  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3611  v8_str("x"),
3612  GetXValue, NULL,
3613  v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3614  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3615  v8_str("x"),
3616  GetXValue, NULL,
3617  v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3618 
3619  ExpectString("obj1.x", "x");
3620  ExpectString("obj2.x", "x");
3621 
3622  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3623  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3624 
3625  CHECK(!GetGlobalProperty(&context, "obj1")->
3626  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3627  CHECK(!GetGlobalProperty(&context, "obj2")->
3628  SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3629 
3630  {
3631  v8::TryCatch try_catch;
3632  CompileRun("Object.defineProperty(obj1, 'x',"
3633  "{get: function() { return 'func'; }})");
3634  CHECK(try_catch.HasCaught());
3635  String::AsciiValue exception_value(try_catch.Exception());
3636  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3637  }
3638  {
3639  v8::TryCatch try_catch;
3640  CompileRun("Object.defineProperty(obj2, 'x',"
3641  "{get: function() { return 'func'; }})");
3642  CHECK(try_catch.HasCaught());
3643  String::AsciiValue exception_value(try_catch.Exception());
3644  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3645  }
3646 }
3647 
3648 
3649 static v8::Handle<Value> Get239Value(Local<String> name,
3650  const AccessorInfo& info) {
3652  CHECK_EQ(info.Data(), v8_str("donut"));
3653  CHECK_EQ(name, v8_str("239"));
3654  return name;
3655 }
3656 
3657 
3658 THREADED_TEST(ElementAPIAccessor) {
3659  v8::HandleScope scope;
3660  Local<ObjectTemplate> templ = ObjectTemplate::New();
3661  LocalContext context;
3662 
3663  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3664  CompileRun("var obj2 = {};");
3665 
3666  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3667  v8_str("239"),
3668  Get239Value, NULL,
3669  v8_str("donut")));
3670  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3671  v8_str("239"),
3672  Get239Value, NULL,
3673  v8_str("donut")));
3674 
3675  ExpectString("obj1[239]", "239");
3676  ExpectString("obj2[239]", "239");
3677  ExpectString("obj1['239']", "239");
3678  ExpectString("obj2['239']", "239");
3679 }
3680 
3681 
3683 
3684 
3685 static void SetXValue(Local<String> name,
3686  Local<Value> value,
3687  const AccessorInfo& info) {
3688  CHECK_EQ(value, v8_num(4));
3689  CHECK_EQ(info.Data(), v8_str("donut"));
3690  CHECK_EQ(name, v8_str("x"));
3691  CHECK(xValue.IsEmpty());
3692  xValue = v8::Persistent<Value>::New(value);
3693 }
3694 
3695 
3696 THREADED_TEST(SimplePropertyWrite) {
3697  v8::HandleScope scope;
3698  Local<ObjectTemplate> templ = ObjectTemplate::New();
3699  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3700  LocalContext context;
3701  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3702  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3703  for (int i = 0; i < 10; i++) {
3704  CHECK(xValue.IsEmpty());
3705  script->Run();
3706  CHECK_EQ(v8_num(4), xValue);
3707  xValue.Dispose();
3708  xValue = v8::Persistent<Value>();
3709  }
3710 }
3711 
3712 
3713 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3714  const AccessorInfo& info) {
3716  CHECK(info.Data()->IsUndefined());
3717  return property;
3718 }
3719 
3720 
3721 THREADED_TEST(NamedInterceptorPropertyRead) {
3722  v8::HandleScope scope;
3723  Local<ObjectTemplate> templ = ObjectTemplate::New();
3724  templ->SetNamedPropertyHandler(XPropertyGetter);
3725  LocalContext context;
3726  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3727  Local<Script> script = Script::Compile(v8_str("obj.x"));
3728  for (int i = 0; i < 10; i++) {
3729  Local<Value> result = script->Run();
3730  CHECK_EQ(result, v8_str("x"));
3731  }
3732 }
3733 
3734 
3735 THREADED_TEST(NamedInterceptorDictionaryIC) {
3736  v8::HandleScope scope;
3737  Local<ObjectTemplate> templ = ObjectTemplate::New();
3738  templ->SetNamedPropertyHandler(XPropertyGetter);
3739  LocalContext context;
3740  // Create an object with a named interceptor.
3741  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3742  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3743  for (int i = 0; i < 10; i++) {
3744  Local<Value> result = script->Run();
3745  CHECK_EQ(result, v8_str("x"));
3746  }
3747  // Create a slow case object and a function accessing a property in
3748  // that slow case object (with dictionary probing in generated
3749  // code). Then force object with a named interceptor into slow-case,
3750  // pass it to the function, and check that the interceptor is called
3751  // instead of accessing the local property.
3752  Local<Value> result =
3753  CompileRun("function get_x(o) { return o.x; };"
3754  "var obj = { x : 42, y : 0 };"
3755  "delete obj.y;"
3756  "for (var i = 0; i < 10; i++) get_x(obj);"
3757  "interceptor_obj.x = 42;"
3758  "interceptor_obj.y = 10;"
3759  "delete interceptor_obj.y;"
3760  "get_x(interceptor_obj)");
3761  CHECK_EQ(result, v8_str("x"));
3762 }
3763 
3764 
3765 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3766  v8::HandleScope scope;
3767 
3768  v8::Persistent<Context> context1 = Context::New();
3769 
3770  context1->Enter();
3771  Local<ObjectTemplate> templ = ObjectTemplate::New();
3772  templ->SetNamedPropertyHandler(XPropertyGetter);
3773  // Create an object with a named interceptor.
3774  v8::Local<v8::Object> object = templ->NewInstance();
3775  context1->Global()->Set(v8_str("interceptor_obj"), object);
3776 
3777  // Force the object into the slow case.
3778  CompileRun("interceptor_obj.y = 0;"
3779  "delete interceptor_obj.y;");
3780  context1->Exit();
3781 
3782  {
3783  // Introduce the object into a different context.
3784  // Repeat named loads to exercise ICs.
3785  LocalContext context2;
3786  context2->Global()->Set(v8_str("interceptor_obj"), object);
3787  Local<Value> result =
3788  CompileRun("function get_x(o) { return o.x; }"
3789  "interceptor_obj.x = 42;"
3790  "for (var i=0; i != 10; i++) {"
3791  " get_x(interceptor_obj);"
3792  "}"
3793  "get_x(interceptor_obj)");
3794  // Check that the interceptor was actually invoked.
3795  CHECK_EQ(result, v8_str("x"));
3796  }
3797 
3798  // Return to the original context and force some object to the slow case
3799  // to cause the NormalizedMapCache to verify.
3800  context1->Enter();
3801  CompileRun("var obj = { x : 0 }; delete obj.x;");
3802  context1->Exit();
3803 
3804  context1.Dispose();
3805 }
3806 
3807 
3808 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3809  const AccessorInfo& info) {
3810  // Set x on the prototype object and do not handle the get request.
3811  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3812  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3813  return v8::Handle<Value>();
3814 }
3815 
3816 
3817 // This is a regression test for http://crbug.com/20104. Map
3818 // transitions should not interfere with post interceptor lookup.
3819 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3820  v8::HandleScope scope;
3821  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3822  Local<v8::ObjectTemplate> instance_template
3823  = function_template->InstanceTemplate();
3824  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3825  LocalContext context;
3826  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3827  // Create an instance of F and introduce a map transition for x.
3828  CompileRun("var o = new F(); o.x = 23;");
3829  // Create an instance of F and invoke the getter. The result should be 23.
3830  Local<Value> result = CompileRun("o = new F(); o.x");
3831  CHECK_EQ(result->Int32Value(), 23);
3832 }
3833 
3834 
3835 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3836  const AccessorInfo& info) {
3838  if (index == 37) {
3839  return v8::Handle<Value>(v8_num(625));
3840  }
3841  return v8::Handle<Value>();
3842 }
3843 
3844 
3845 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3846  Local<Value> value,
3847  const AccessorInfo& info) {
3849  if (index == 39) {
3850  return value;
3851  }
3852  return v8::Handle<Value>();
3853 }
3854 
3855 
3856 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3857  v8::HandleScope scope;
3858  Local<ObjectTemplate> templ = ObjectTemplate::New();
3859  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3860  IndexedPropertySetter);
3861  LocalContext context;
3862  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3863  Local<Script> getter_script = Script::Compile(v8_str(
3864  "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3865  Local<Script> setter_script = Script::Compile(v8_str(
3866  "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3867  "obj[17] = 23;"
3868  "obj.foo;"));
3869  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3870  "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3871  "obj[39] = 47;"
3872  "obj.foo;")); // This setter should not run, due to the interceptor.
3873  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3874  "obj[37];"));
3875  Local<Value> result = getter_script->Run();
3876  CHECK_EQ(v8_num(5), result);
3877  result = setter_script->Run();
3878  CHECK_EQ(v8_num(23), result);
3879  result = interceptor_setter_script->Run();
3880  CHECK_EQ(v8_num(23), result);
3881  result = interceptor_getter_script->Run();
3882  CHECK_EQ(v8_num(625), result);
3883 }
3884 
3885 
3886 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3887  uint32_t index,
3888  const AccessorInfo& info) {
3890  if (index < 25) {
3891  return v8::Handle<Value>(v8_num(index));
3892  }
3893  return v8::Handle<Value>();
3894 }
3895 
3896 
3897 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3898  uint32_t index,
3899  Local<Value> value,
3900  const AccessorInfo& info) {
3902  if (index < 25) {
3903  return v8::Handle<Value>(v8_num(index));
3904  }
3905  return v8::Handle<Value>();
3906 }
3907 
3908 
3910  const AccessorInfo& info) {
3911  // Force the list of returned keys to be stored in a FastDoubleArray.
3912  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3913  "keys = new Array(); keys[125000] = 1;"
3914  "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3915  "keys.length = 25; keys;"));
3916  Local<Value> result = indexed_property_names_script->Run();
3917  return Local<v8::Array>(::v8::Array::Cast(*result));
3918 }
3919 
3920 
3921 // Make sure that the the interceptor code in the runtime properly handles
3922 // merging property name lists for double-array-backed arrays.
3923 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3924  v8::HandleScope scope;
3925  Local<ObjectTemplate> templ = ObjectTemplate::New();
3926  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3927  UnboxedDoubleIndexedPropertySetter,
3928  0,
3929  0,
3931  LocalContext context;
3932  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3933  // When obj is created, force it to be Stored in a FastDoubleArray.
3934  Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3935  "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3936  "key_count = 0; "
3937  "for (x in obj) {key_count++;};"
3938  "obj;"));
3939  Local<Value> result = create_unboxed_double_script->Run();
3940  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3941  Local<Script> key_count_check = Script::Compile(v8_str(
3942  "key_count;"));
3943  result = key_count_check->Run();
3944  CHECK_EQ(v8_num(40013), result);
3945 }
3946 
3947 
3949  const AccessorInfo& info) {
3950  // Force the list of returned keys to be stored in a Arguments object.
3951  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3952  "function f(w,x) {"
3953  " return arguments;"
3954  "}"
3955  "keys = f(0, 1, 2, 3);"
3956  "keys;"));
3957  Local<Value> result = indexed_property_names_script->Run();
3958  return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3959 }
3960 
3961 
3962 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3963  uint32_t index,
3964  const AccessorInfo& info) {
3966  if (index < 4) {
3967  return v8::Handle<Value>(v8_num(index));
3968  }
3969  return v8::Handle<Value>();
3970 }
3971 
3972 
3973 // Make sure that the the interceptor code in the runtime properly handles
3974 // merging property name lists for non-string arguments arrays.
3975 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3976  v8::HandleScope scope;
3977  Local<ObjectTemplate> templ = ObjectTemplate::New();
3978  templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3979  0,
3980  0,
3981  0,
3983  LocalContext context;
3984  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3985  Local<Script> create_args_script =
3986  Script::Compile(v8_str(
3987  "var key_count = 0;"
3988  "for (x in obj) {key_count++;} key_count;"));
3989  Local<Value> result = create_args_script->Run();
3990  CHECK_EQ(v8_num(4), result);
3991 }
3992 
3993 
3994 static v8::Handle<Value> IdentityIndexedPropertyGetter(
3995  uint32_t index,
3996  const AccessorInfo& info) {
3997  return v8::Integer::NewFromUnsigned(index);
3998 }
3999 
4000 
4001 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4002  v8::HandleScope scope;
4003  Local<ObjectTemplate> templ = ObjectTemplate::New();
4004  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4005 
4006  LocalContext context;
4007  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4008 
4009  // Check fast object case.
4010  const char* fast_case_code =
4011  "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4012  ExpectString(fast_case_code, "0");
4013 
4014  // Check slow case.
4015  const char* slow_case_code =
4016  "obj.x = 1; delete obj.x;"
4017  "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4018  ExpectString(slow_case_code, "1");
4019 }
4020 
4021 
4022 THREADED_TEST(IndexedInterceptorWithNoSetter) {
4023  v8::HandleScope scope;
4024  Local<ObjectTemplate> templ = ObjectTemplate::New();
4025  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4026 
4027  LocalContext context;
4028  context->Global()->Set(v8_str("obj"), templ->NewInstance());
4029 
4030  const char* code =
4031  "try {"
4032  " obj[0] = 239;"
4033  " for (var i = 0; i < 100; i++) {"
4034  " var v = obj[0];"
4035  " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4036  " }"
4037  " 'PASSED'"
4038  "} catch(e) {"
4039  " e"
4040  "}";
4041  ExpectString(code, "PASSED");
4042 }
4043 
4044 
4045 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4046  v8::HandleScope scope;
4047  Local<ObjectTemplate> templ = ObjectTemplate::New();
4048  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4049 
4050  LocalContext context;
4051  Local<v8::Object> obj = templ->NewInstance();
4052  obj->TurnOnAccessCheck();
4053  context->Global()->Set(v8_str("obj"), obj);
4054 
4055  const char* code =
4056  "try {"
4057  " for (var i = 0; i < 100; i++) {"
4058  " var v = obj[0];"
4059  " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4060  " }"
4061  " 'PASSED'"
4062  "} catch(e) {"
4063  " e"
4064  "}";
4065  ExpectString(code, "PASSED");
4066 }
4067 
4068 
4069 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4070  i::FLAG_allow_natives_syntax = true;
4071  v8::HandleScope scope;
4072  Local<ObjectTemplate> templ = ObjectTemplate::New();
4073  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4074 
4075  LocalContext context;
4076  Local<v8::Object> obj = templ->NewInstance();
4077  context->Global()->Set(v8_str("obj"), obj);
4078 
4079  const char* code =
4080  "try {"
4081  " for (var i = 0; i < 100; i++) {"
4082  " var expected = i;"
4083  " if (i == 5) {"
4084  " %EnableAccessChecks(obj);"
4085  " expected = undefined;"
4086  " }"
4087  " var v = obj[i];"
4088  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4089  " if (i == 5) %DisableAccessChecks(obj);"
4090  " }"
4091  " 'PASSED'"
4092  "} catch(e) {"
4093  " e"
4094  "}";
4095  ExpectString(code, "PASSED");
4096 }
4097 
4098 
4099 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4100  v8::HandleScope scope;
4101  Local<ObjectTemplate> templ = ObjectTemplate::New();
4102  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4103 
4104  LocalContext context;
4105  Local<v8::Object> obj = templ->NewInstance();
4106  context->Global()->Set(v8_str("obj"), obj);
4107 
4108  const char* code =
4109  "try {"
4110  " for (var i = 0; i < 100; i++) {"
4111  " var v = obj[i];"
4112  " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4113  " }"
4114  " 'PASSED'"
4115  "} catch(e) {"
4116  " e"
4117  "}";
4118  ExpectString(code, "PASSED");
4119 }
4120 
4121 
4122 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4123  v8::HandleScope scope;
4124  Local<ObjectTemplate> templ = ObjectTemplate::New();
4125  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4126 
4127  LocalContext context;
4128  Local<v8::Object> obj = templ->NewInstance();
4129  context->Global()->Set(v8_str("obj"), obj);
4130 
4131  const char* code =
4132  "try {"
4133  " for (var i = 0; i < 100; i++) {"
4134  " var expected = i;"
4135  " var key = i;"
4136  " if (i == 25) {"
4137  " key = -1;"
4138  " expected = undefined;"
4139  " }"
4140  " if (i == 50) {"
4141  " /* probe minimal Smi number on 32-bit platforms */"
4142  " key = -(1 << 30);"
4143  " expected = undefined;"
4144  " }"
4145  " if (i == 75) {"
4146  " /* probe minimal Smi number on 64-bit platforms */"
4147  " key = 1 << 31;"
4148  " expected = undefined;"
4149  " }"
4150  " var v = obj[key];"
4151  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152  " }"
4153  " 'PASSED'"
4154  "} catch(e) {"
4155  " e"
4156  "}";
4157  ExpectString(code, "PASSED");
4158 }
4159 
4160 
4161 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4162  v8::HandleScope scope;
4163  Local<ObjectTemplate> templ = ObjectTemplate::New();
4164  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4165 
4166  LocalContext context;
4167  Local<v8::Object> obj = templ->NewInstance();
4168  context->Global()->Set(v8_str("obj"), obj);
4169 
4170  const char* code =
4171  "try {"
4172  " for (var i = 0; i < 100; i++) {"
4173  " var expected = i;"
4174  " var key = i;"
4175  " if (i == 50) {"
4176  " key = 'foobar';"
4177  " expected = undefined;"
4178  " }"
4179  " var v = obj[key];"
4180  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4181  " }"
4182  " 'PASSED'"
4183  "} catch(e) {"
4184  " e"
4185  "}";
4186  ExpectString(code, "PASSED");
4187 }
4188 
4189 
4190 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4191  v8::HandleScope scope;
4192  Local<ObjectTemplate> templ = ObjectTemplate::New();
4193  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4194 
4195  LocalContext context;
4196  Local<v8::Object> obj = templ->NewInstance();
4197  context->Global()->Set(v8_str("obj"), obj);
4198 
4199  const char* code =
4200  "var original = obj;"
4201  "try {"
4202  " for (var i = 0; i < 100; i++) {"
4203  " var expected = i;"
4204  " if (i == 50) {"
4205  " obj = {50: 'foobar'};"
4206  " expected = 'foobar';"
4207  " }"
4208  " var v = obj[i];"
4209  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4210  " if (i == 50) obj = original;"
4211  " }"
4212  " 'PASSED'"
4213  "} catch(e) {"
4214  " e"
4215  "}";
4216  ExpectString(code, "PASSED");
4217 }
4218 
4219 
4220 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4221  v8::HandleScope scope;
4222  Local<ObjectTemplate> templ = ObjectTemplate::New();
4223  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4224 
4225  LocalContext context;
4226  Local<v8::Object> obj = templ->NewInstance();
4227  context->Global()->Set(v8_str("obj"), obj);
4228 
4229  const char* code =
4230  "var original = obj;"
4231  "try {"
4232  " for (var i = 0; i < 100; i++) {"
4233  " var expected = i;"
4234  " if (i == 5) {"
4235  " obj = 239;"
4236  " expected = undefined;"
4237  " }"
4238  " var v = obj[i];"
4239  " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4240  " if (i == 5) obj = original;"
4241  " }"
4242  " 'PASSED'"
4243  "} catch(e) {"
4244  " e"
4245  "}";
4246  ExpectString(code, "PASSED");
4247 }
4248 
4249 
4250 THREADED_TEST(IndexedInterceptorOnProto) {
4251  v8::HandleScope scope;
4252  Local<ObjectTemplate> templ = ObjectTemplate::New();
4253  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4254 
4255  LocalContext context;
4256  Local<v8::Object> obj = templ->NewInstance();
4257  context->Global()->Set(v8_str("obj"), obj);
4258 
4259  const char* code =
4260  "var o = {__proto__: obj};"
4261  "try {"
4262  " for (var i = 0; i < 100; i++) {"
4263  " var v = o[i];"
4264  " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4265  " }"
4266  " 'PASSED'"
4267  "} catch(e) {"
4268  " e"
4269  "}";
4270  ExpectString(code, "PASSED");
4271 }
4272 
4273 
4274 THREADED_TEST(MultiContexts) {
4275  v8::HandleScope scope;
4276  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4277  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4278 
4279  Local<String> password = v8_str("Password");
4280 
4281  // Create an environment
4282  LocalContext context0(0, templ);
4283  context0->SetSecurityToken(password);
4284  v8::Handle<v8::Object> global0 = context0->Global();
4285  global0->Set(v8_str("custom"), v8_num(1234));
4286  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4287 
4288  // Create an independent environment
4289  LocalContext context1(0, templ);
4290  context1->SetSecurityToken(password);
4291  v8::Handle<v8::Object> global1 = context1->Global();
4292  global1->Set(v8_str("custom"), v8_num(1234));
4293  CHECK_NE(global0, global1);
4294  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4295  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4296 
4297  // Now create a new context with the old global
4298  LocalContext context2(0, templ, global1);
4299  context2->SetSecurityToken(password);
4300  v8::Handle<v8::Object> global2 = context2->Global();
4301  CHECK_EQ(global1, global2);
4302  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4303  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4304 }
4305 
4306 
4307 THREADED_TEST(FunctionPrototypeAcrossContexts) {
4308  // Make sure that functions created by cloning boilerplates cannot
4309  // communicate through their __proto__ field.
4310 
4311  v8::HandleScope scope;
4312 
4313  LocalContext env0;
4314  v8::Handle<v8::Object> global0 =
4315  env0->Global();
4316  v8::Handle<v8::Object> object0 =
4317  global0->Get(v8_str("Object")).As<v8::Object>();
4318  v8::Handle<v8::Object> tostring0 =
4319  object0->Get(v8_str("toString")).As<v8::Object>();
4320  v8::Handle<v8::Object> proto0 =
4321  tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4322  proto0->Set(v8_str("custom"), v8_num(1234));
4323 
4324  LocalContext env1;
4325  v8::Handle<v8::Object> global1 =
4326  env1->Global();
4327  v8::Handle<v8::Object> object1 =
4328  global1->Get(v8_str("Object")).As<v8::Object>();
4329  v8::Handle<v8::Object> tostring1 =
4330  object1->Get(v8_str("toString")).As<v8::Object>();
4331  v8::Handle<v8::Object> proto1 =
4332  tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4333  CHECK(!proto1->Has(v8_str("custom")));
4334 }
4335 
4336 
4337 THREADED_TEST(Regress892105) {
4338  // Make sure that object and array literals created by cloning
4339  // boilerplates cannot communicate through their __proto__
4340  // field. This is rather difficult to check, but we try to add stuff
4341  // to Object.prototype and Array.prototype and create a new
4342  // environment. This should succeed.
4343 
4344  v8::HandleScope scope;
4345 
4346  Local<String> source = v8_str("Object.prototype.obj = 1234;"
4347  "Array.prototype.arr = 4567;"
4348  "8901");
4349 
4350  LocalContext env0;
4351  Local<Script> script0 = Script::Compile(source);
4352  CHECK_EQ(8901.0, script0->Run()->NumberValue());
4353 
4354  LocalContext env1;
4355  Local<Script> script1 = Script::Compile(source);
4356  CHECK_EQ(8901.0, script1->Run()->NumberValue());
4357 }
4358 
4359 
4360 THREADED_TEST(UndetectableObject) {
4361  v8::HandleScope scope;
4362  LocalContext env;
4363 
4364  Local<v8::FunctionTemplate> desc =
4366  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4367 
4368  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4369  env->Global()->Set(v8_str("undetectable"), obj);
4370 
4371  ExpectString("undetectable.toString()", "[object Object]");
4372  ExpectString("typeof undetectable", "undefined");
4373  ExpectString("typeof(undetectable)", "undefined");
4374  ExpectBoolean("typeof undetectable == 'undefined'", true);
4375  ExpectBoolean("typeof undetectable == 'object'", false);
4376  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4377  ExpectBoolean("!undetectable", true);
4378 
4379  ExpectObject("true&&undetectable", obj);
4380  ExpectBoolean("false&&undetectable", false);
4381  ExpectBoolean("true||undetectable", true);
4382  ExpectObject("false||undetectable", obj);
4383 
4384  ExpectObject("undetectable&&true", obj);
4385  ExpectObject("undetectable&&false", obj);
4386  ExpectBoolean("undetectable||true", true);
4387  ExpectBoolean("undetectable||false", false);
4388 
4389  ExpectBoolean("undetectable==null", true);
4390  ExpectBoolean("null==undetectable", true);
4391  ExpectBoolean("undetectable==undefined", true);
4392  ExpectBoolean("undefined==undetectable", true);
4393  ExpectBoolean("undetectable==undetectable", true);
4394 
4395 
4396  ExpectBoolean("undetectable===null", false);
4397  ExpectBoolean("null===undetectable", false);
4398  ExpectBoolean("undetectable===undefined", false);
4399  ExpectBoolean("undefined===undetectable", false);
4400  ExpectBoolean("undetectable===undetectable", true);
4401 }
4402 
4403 
4404 THREADED_TEST(VoidLiteral) {
4405  v8::HandleScope scope;
4406  LocalContext env;
4407 
4408  Local<v8::FunctionTemplate> desc =
4410  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4411 
4412  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4413  env->Global()->Set(v8_str("undetectable"), obj);
4414 
4415  ExpectBoolean("undefined == void 0", true);
4416  ExpectBoolean("undetectable == void 0", true);
4417  ExpectBoolean("null == void 0", true);
4418  ExpectBoolean("undefined === void 0", true);
4419  ExpectBoolean("undetectable === void 0", false);
4420  ExpectBoolean("null === void 0", false);
4421 
4422  ExpectBoolean("void 0 == undefined", true);
4423  ExpectBoolean("void 0 == undetectable", true);
4424  ExpectBoolean("void 0 == null", true);
4425  ExpectBoolean("void 0 === undefined", true);
4426  ExpectBoolean("void 0 === undetectable", false);
4427  ExpectBoolean("void 0 === null", false);
4428 
4429  ExpectString("(function() {"
4430  " try {"
4431  " return x === void 0;"
4432  " } catch(e) {"
4433  " return e.toString();"
4434  " }"
4435  "})()",
4436  "ReferenceError: x is not defined");
4437  ExpectString("(function() {"
4438  " try {"
4439  " return void 0 === x;"
4440  " } catch(e) {"
4441  " return e.toString();"
4442  " }"
4443  "})()",
4444  "ReferenceError: x is not defined");
4445 }
4446 
4447 
4448 THREADED_TEST(ExtensibleOnUndetectable) {
4449  v8::HandleScope scope;
4450  LocalContext env;
4451 
4452  Local<v8::FunctionTemplate> desc =
4454  desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4455 
4456  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4457  env->Global()->Set(v8_str("undetectable"), obj);
4458 
4459  Local<String> source = v8_str("undetectable.x = 42;"
4460  "undetectable.x");
4461 
4462  Local<Script> script = Script::Compile(source);
4463 
4464  CHECK_EQ(v8::Integer::New(42), script->Run());
4465 
4466  ExpectBoolean("Object.isExtensible(undetectable)", true);
4467 
4468  source = v8_str("Object.preventExtensions(undetectable);");
4469  script = Script::Compile(source);
4470  script->Run();
4471  ExpectBoolean("Object.isExtensible(undetectable)", false);
4472 
4473  source = v8_str("undetectable.y = 2000;");
4474  script = Script::Compile(source);
4475  script->Run();
4476  ExpectBoolean("undetectable.y == undefined", true);
4477 }
4478 
4479 
4480 
4481 THREADED_TEST(UndetectableString) {
4482  v8::HandleScope scope;
4483  LocalContext env;
4484 
4485  Local<String> obj = String::NewUndetectable("foo");
4486  env->Global()->Set(v8_str("undetectable"), obj);
4487 
4488  ExpectString("undetectable", "foo");
4489  ExpectString("typeof undetectable", "undefined");
4490  ExpectString("typeof(undetectable)", "undefined");
4491  ExpectBoolean("typeof undetectable == 'undefined'", true);
4492  ExpectBoolean("typeof undetectable == 'string'", false);
4493  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4494  ExpectBoolean("!undetectable", true);
4495 
4496  ExpectObject("true&&undetectable", obj);
4497  ExpectBoolean("false&&undetectable", false);
4498  ExpectBoolean("true||undetectable", true);
4499  ExpectObject("false||undetectable", obj);
4500 
4501  ExpectObject("undetectable&&true", obj);
4502  ExpectObject("undetectable&&false", obj);
4503  ExpectBoolean("undetectable||true", true);
4504  ExpectBoolean("undetectable||false", false);
4505 
4506  ExpectBoolean("undetectable==null", true);
4507  ExpectBoolean("null==undetectable", true);
4508  ExpectBoolean("undetectable==undefined", true);
4509  ExpectBoolean("undefined==undetectable", true);
4510  ExpectBoolean("undetectable==undetectable", true);
4511 
4512 
4513  ExpectBoolean("undetectable===null", false);
4514  ExpectBoolean("null===undetectable", false);
4515  ExpectBoolean("undetectable===undefined", false);
4516  ExpectBoolean("undefined===undetectable", false);
4517  ExpectBoolean("undetectable===undetectable", true);
4518 }
4519 
4520 
4521 TEST(UndetectableOptimized) {
4522  i::FLAG_allow_natives_syntax = true;
4523  v8::HandleScope scope;
4524  LocalContext env;
4525 
4526  Local<String> obj = String::NewUndetectable("foo");
4527  env->Global()->Set(v8_str("undetectable"), obj);
4528  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4529 
4530  ExpectString(
4531  "function testBranch() {"
4532  " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4533  " if (%_IsUndetectableObject(detectable)) throw 2;"
4534  "}\n"
4535  "function testBool() {"
4536  " var b1 = !%_IsUndetectableObject(undetectable);"
4537  " var b2 = %_IsUndetectableObject(detectable);"
4538  " if (b1) throw 3;"
4539  " if (b2) throw 4;"
4540  " return b1 == b2;"
4541  "}\n"
4542  "%OptimizeFunctionOnNextCall(testBranch);"
4543  "%OptimizeFunctionOnNextCall(testBool);"
4544  "for (var i = 0; i < 10; i++) {"
4545  " testBranch();"
4546  " testBool();"
4547  "}\n"
4548  "\"PASS\"",
4549  "PASS");
4550 }
4551 
4552 
4553 template <typename T> static void USE(T) { }
4554 
4555 
4556 // This test is not intended to be run, just type checked.
4557 static inline void PersistentHandles() {
4558  USE(PersistentHandles);
4559  Local<String> str = v8_str("foo");
4561  USE(p_str);
4562  Local<Script> scr = Script::Compile(v8_str(""));
4564  USE(p_scr);
4565  Local<ObjectTemplate> templ = ObjectTemplate::New();
4568  USE(p_templ);
4569 }
4570 
4571 
4572 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4574  return v8::Undefined();
4575 }
4576 
4577 
4578 THREADED_TEST(GlobalObjectTemplate) {
4579  v8::HandleScope handle_scope;
4580  Local<ObjectTemplate> global_template = ObjectTemplate::New();
4581  global_template->Set(v8_str("JSNI_Log"),
4582  v8::FunctionTemplate::New(HandleLogDelegator));
4583  v8::Persistent<Context> context = Context::New(0, global_template);
4584  Context::Scope context_scope(context);
4585  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4586  context.Dispose();
4587 }
4588 
4589 
4590 static const char* kSimpleExtensionSource =
4591  "function Foo() {"
4592  " return 4;"
4593  "}";
4594 
4595 
4596 THREADED_TEST(SimpleExtensions) {
4597  v8::HandleScope handle_scope;
4598  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4599  const char* extension_names[] = { "simpletest" };
4600  v8::ExtensionConfiguration extensions(1, extension_names);
4601  v8::Handle<Context> context = Context::New(&extensions);
4602  Context::Scope lock(context);
4603  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4604  CHECK_EQ(result, v8::Integer::New(4));
4605 }
4606 
4607 
4608 static const char* kEmbeddedExtensionSource =
4609  "function Ret54321(){return 54321;}~~@@$"
4610  "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4611 static const int kEmbeddedExtensionSourceValidLen = 34;
4612 
4613 
4614 THREADED_TEST(ExtensionMissingSourceLength) {
4615  v8::HandleScope handle_scope;
4616  v8::RegisterExtension(new Extension("srclentest_fail",
4617  kEmbeddedExtensionSource));
4618  const char* extension_names[] = { "srclentest_fail" };
4619  v8::ExtensionConfiguration extensions(1, extension_names);
4620  v8::Handle<Context> context = Context::New(&extensions);
4621  CHECK_EQ(0, *context);
4622 }
4623 
4624 
4625 THREADED_TEST(ExtensionWithSourceLength) {
4626  for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4627  source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4628  v8::HandleScope handle_scope;
4629  i::ScopedVector<char> extension_name(32);
4630  i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4631  v8::RegisterExtension(new Extension(extension_name.start(),
4632  kEmbeddedExtensionSource, 0, 0,
4633  source_len));
4634  const char* extension_names[1] = { extension_name.start() };
4635  v8::ExtensionConfiguration extensions(1, extension_names);
4636  v8::Handle<Context> context = Context::New(&extensions);
4637  if (source_len == kEmbeddedExtensionSourceValidLen) {
4638  Context::Scope lock(context);
4639  v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4640  CHECK_EQ(v8::Integer::New(54321), result);
4641  } else {
4642  // Anything but exactly the right length should fail to compile.
4643  CHECK_EQ(0, *context);
4644  }
4645  }
4646 }
4647 
4648 
4649 static const char* kEvalExtensionSource1 =
4650  "function UseEval1() {"
4651  " var x = 42;"
4652  " return eval('x');"
4653  "}";
4654 
4655 
4656 static const char* kEvalExtensionSource2 =
4657  "(function() {"
4658  " var x = 42;"
4659  " function e() {"
4660  " return eval('x');"
4661  " }"
4662  " this.UseEval2 = e;"
4663  "})()";
4664 
4665 
4666 THREADED_TEST(UseEvalFromExtension) {
4667  v8::HandleScope handle_scope;
4668  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4669  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4670  const char* extension_names[] = { "evaltest1", "evaltest2" };
4671  v8::ExtensionConfiguration extensions(2, extension_names);
4672  v8::Handle<Context> context = Context::New(&extensions);
4673  Context::Scope lock(context);
4674  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4675  CHECK_EQ(result, v8::Integer::New(42));
4676  result = Script::Compile(v8_str("UseEval2()"))->Run();
4677  CHECK_EQ(result, v8::Integer::New(42));
4678 }
4679 
4680 
4681 static const char* kWithExtensionSource1 =
4682  "function UseWith1() {"
4683  " var x = 42;"
4684  " with({x:87}) { return x; }"
4685  "}";
4686 
4687 
4688 
4689 static const char* kWithExtensionSource2 =
4690  "(function() {"
4691  " var x = 42;"
4692  " function e() {"
4693  " with ({x:87}) { return x; }"
4694  " }"
4695  " this.UseWith2 = e;"
4696  "})()";
4697 
4698 
4699 THREADED_TEST(UseWithFromExtension) {
4700  v8::HandleScope handle_scope;
4701  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4702  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4703  const char* extension_names[] = { "withtest1", "withtest2" };
4704  v8::ExtensionConfiguration extensions(2, extension_names);
4705  v8::Handle<Context> context = Context::New(&extensions);
4706  Context::Scope lock(context);
4707  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4708  CHECK_EQ(result, v8::Integer::New(87));
4709  result = Script::Compile(v8_str("UseWith2()"))->Run();
4710  CHECK_EQ(result, v8::Integer::New(87));
4711 }
4712 
4713 
4714 THREADED_TEST(AutoExtensions) {
4715  v8::HandleScope handle_scope;
4716  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4717  extension->set_auto_enable(true);
4718  v8::RegisterExtension(extension);
4719  v8::Handle<Context> context = Context::New();
4720  Context::Scope lock(context);
4721  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4722  CHECK_EQ(result, v8::Integer::New(4));
4723 }
4724 
4725 
4726 static const char* kSyntaxErrorInExtensionSource =
4727  "[";
4728 
4729 
4730 // Test that a syntax error in an extension does not cause a fatal
4731 // error but results in an empty context.
4732 THREADED_TEST(SyntaxErrorExtensions) {
4733  v8::HandleScope handle_scope;
4734  v8::RegisterExtension(new Extension("syntaxerror",
4735  kSyntaxErrorInExtensionSource));
4736  const char* extension_names[] = { "syntaxerror" };
4737  v8::ExtensionConfiguration extensions(1, extension_names);
4738  v8::Handle<Context> context = Context::New(&extensions);
4739  CHECK(context.IsEmpty());
4740 }
4741 
4742 
4743 static const char* kExceptionInExtensionSource =
4744  "throw 42";
4745 
4746 
4747 // Test that an exception when installing an extension does not cause
4748 // a fatal error but results in an empty context.
4749 THREADED_TEST(ExceptionExtensions) {
4750  v8::HandleScope handle_scope;
4751  v8::RegisterExtension(new Extension("exception",
4752  kExceptionInExtensionSource));
4753  const char* extension_names[] = { "exception" };
4754  v8::ExtensionConfiguration extensions(1, extension_names);
4755  v8::Handle<Context> context = Context::New(&extensions);
4756  CHECK(context.IsEmpty());
4757 }
4758 
4759 
4760 static const char* kNativeCallInExtensionSource =
4761  "function call_runtime_last_index_of(x) {"
4762  " return %StringLastIndexOf(x, 'bob', 10);"
4763  "}";
4764 
4765 
4766 static const char* kNativeCallTest =
4767  "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4768 
4769 // Test that a native runtime calls are supported in extensions.
4770 THREADED_TEST(NativeCallInExtensions) {
4771  v8::HandleScope handle_scope;
4772  v8::RegisterExtension(new Extension("nativecall",
4773  kNativeCallInExtensionSource));
4774  const char* extension_names[] = { "nativecall" };
4775  v8::ExtensionConfiguration extensions(1, extension_names);
4776  v8::Handle<Context> context = Context::New(&extensions);
4777  Context::Scope lock(context);
4778  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4779  CHECK_EQ(result, v8::Integer::New(3));
4780 }
4781 
4782 
4783 class NativeFunctionExtension : public Extension {
4784  public:
4785  NativeFunctionExtension(const char* name,
4786  const char* source,
4788  : Extension(name, source),
4789  function_(fun) { }
4790 
4792  v8::Handle<v8::String> name) {
4793  return v8::FunctionTemplate::New(function_);
4794  }
4795 
4797  if (args.Length() >= 1) return (args[0]);
4798  return v8::Undefined();
4799  }
4800  private:
4801  v8::InvocationCallback function_;
4802 };
4803 
4804 
4805 THREADED_TEST(NativeFunctionDeclaration) {
4806  v8::HandleScope handle_scope;
4807  const char* name = "nativedecl";
4809  "native function foo();"));
4810  const char* extension_names[] = { name };
4811  v8::ExtensionConfiguration extensions(1, extension_names);
4812  v8::Handle<Context> context = Context::New(&extensions);
4813  Context::Scope lock(context);
4814  v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4815  CHECK_EQ(result, v8::Integer::New(42));
4816 }
4817 
4818 
4819 THREADED_TEST(NativeFunctionDeclarationError) {
4820  v8::HandleScope handle_scope;
4821  const char* name = "nativedeclerr";
4822  // Syntax error in extension code.
4824  "native\nfunction foo();"));
4825  const char* extension_names[] = { name };
4826  v8::ExtensionConfiguration extensions(1, extension_names);
4827  v8::Handle<Context> context(Context::New(&extensions));
4828  CHECK(context.IsEmpty());
4829 }
4830 
4831 
4832 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4833  v8::HandleScope handle_scope;
4834  const char* name = "nativedeclerresc";
4835  // Syntax error in extension code - escape code in "native" means that
4836  // it's not treated as a keyword.
4838  name,
4839  "nativ\\u0065 function foo();"));
4840  const char* extension_names[] = { name };
4841  v8::ExtensionConfiguration extensions(1, extension_names);
4842  v8::Handle<Context> context(Context::New(&extensions));
4843  CHECK(context.IsEmpty());
4844 }
4845 
4846 
4847 static void CheckDependencies(const char* name, const char* expected) {
4848  v8::HandleScope handle_scope;
4849  v8::ExtensionConfiguration config(1, &name);
4850  LocalContext context(&config);
4851  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4852 }
4853 
4854 
4855 /*
4856  * Configuration:
4857  *
4858  * /-- B <--\
4859  * A <- -- D <-- E
4860  * \-- C <--/
4861  */
4862 THREADED_TEST(ExtensionDependency) {
4863  static const char* kEDeps[] = { "D" };
4864  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4865  static const char* kDDeps[] = { "B", "C" };
4866  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4867  static const char* kBCDeps[] = { "A" };
4868  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4869  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4870  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4871  CheckDependencies("A", "undefinedA");
4872  CheckDependencies("B", "undefinedAB");
4873  CheckDependencies("C", "undefinedAC");
4874  CheckDependencies("D", "undefinedABCD");
4875  CheckDependencies("E", "undefinedABCDE");
4876  v8::HandleScope handle_scope;
4877  static const char* exts[2] = { "C", "E" };
4878  v8::ExtensionConfiguration config(2, exts);
4879  LocalContext context(&config);
4880  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4881 }
4882 
4883 
4884 static const char* kExtensionTestScript =
4885  "native function A();"
4886  "native function B();"
4887  "native function C();"
4888  "function Foo(i) {"
4889  " if (i == 0) return A();"
4890  " if (i == 1) return B();"
4891  " if (i == 2) return C();"
4892  "}";
4893 
4894 
4895 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4897  if (args.IsConstructCall()) {
4898  args.This()->Set(v8_str("data"), args.Data());
4899  return v8::Null();
4900  }
4901  return args.Data();
4902 }
4903 
4904 
4905 class FunctionExtension : public Extension {
4906  public:
4907  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4909  v8::Handle<String> name);
4910 };
4911 
4912 
4913 static int lookup_count = 0;
4915  v8::Handle<String> name) {
4916  lookup_count++;
4917  if (name->Equals(v8_str("A"))) {
4918  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4919  } else if (name->Equals(v8_str("B"))) {
4920  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4921  } else if (name->Equals(v8_str("C"))) {
4922  return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4923  } else {
4925  }
4926 }
4927 
4928 
4929 THREADED_TEST(FunctionLookup) {
4931  v8::HandleScope handle_scope;
4932  static const char* exts[1] = { "functiontest" };
4933  v8::ExtensionConfiguration config(1, exts);
4934  LocalContext context(&config);
4935  CHECK_EQ(3, lookup_count);
4936  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4937  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4938  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4939 }
4940 
4941 
4942 THREADED_TEST(NativeFunctionConstructCall) {
4944  v8::HandleScope handle_scope;
4945  static const char* exts[1] = { "functiontest" };
4946  v8::ExtensionConfiguration config(1, exts);
4947  LocalContext context(&config);
4948  for (int i = 0; i < 10; i++) {
4949  // Run a few times to ensure that allocation of objects doesn't
4950  // change behavior of a constructor function.
4952  Script::Compile(v8_str("(new A()).data"))->Run());
4954  Script::Compile(v8_str("(new B()).data"))->Run());
4956  Script::Compile(v8_str("(new C()).data"))->Run());
4957  }
4958 }
4959 
4960 
4961 static const char* last_location;
4962 static const char* last_message;
4963 void StoringErrorCallback(const char* location, const char* message) {
4964  if (last_location == NULL) {
4965  last_location = location;
4966  last_message = message;
4967  }
4968 }
4969 
4970 
4971 // ErrorReporting creates a circular extensions configuration and
4972 // tests that the fatal error handler gets called. This renders V8
4973 // unusable and therefore this test cannot be run in parallel.
4974 TEST(ErrorReporting) {
4976  static const char* aDeps[] = { "B" };
4977  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4978  static const char* bDeps[] = { "A" };
4979  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4980  last_location = NULL;
4981  v8::ExtensionConfiguration config(1, bDeps);
4982  v8::Handle<Context> context = Context::New(&config);
4983  CHECK(context.IsEmpty());
4984  CHECK_NE(last_location, NULL);
4985 }
4986 
4987 
4988 static const char* js_code_causing_huge_string_flattening =
4989  "var str = 'X';"
4990  "for (var i = 0; i < 30; i++) {"
4991  " str = str + str;"
4992  "}"
4993  "str.match(/X/);";
4994 
4995 
4996 void OOMCallback(const char* location, const char* message) {
4997  exit(0);
4998 }
4999 
5000 
5001 TEST(RegexpOutOfMemory) {
5002  // Execute a script that causes out of memory when flattening a string.
5003  v8::HandleScope scope;
5005  LocalContext context;
5006  Local<Script> script =
5007  Script::Compile(String::New(js_code_causing_huge_string_flattening));
5008  last_location = NULL;
5009  script->Run();
5010 
5011  CHECK(false); // Should not return.
5012 }
5013 
5014 
5015 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5016  v8::Handle<Value> data) {
5017  CHECK_EQ(v8::Undefined(), data);
5018  CHECK(message->GetScriptResourceName()->IsUndefined());
5020  message->GetLineNumber();
5021  message->GetSourceLine();
5022 }
5023 
5024 
5025 THREADED_TEST(ErrorWithMissingScriptInfo) {
5026  v8::HandleScope scope;
5027  LocalContext context;
5028  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5029  Script::Compile(v8_str("throw Error()"))->Run();
5030  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5031 }
5032 
5033 
5035 
5036 class Snorkel {
5037  public:
5038  Snorkel() { index_ = global_index++; }
5039  int index_;
5040 };
5041 
5042 class Whammy {
5043  public:
5045  cursor_ = 0;
5046  }
5048  script_.Dispose();
5049  }
5051  if (script_.IsEmpty())
5052  script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5053  return Local<Script>(*script_);
5054  }
5055 
5056  public:
5057  static const int kObjectCount = 256;
5058  int cursor_;
5061 };
5062 
5063 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5064  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5065  delete snorkel;
5066  obj.ClearWeak();
5067 }
5068 
5070  const AccessorInfo& info) {
5071  Whammy* whammy =
5072  static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5073 
5074  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5075 
5078  if (!prev.IsEmpty()) {
5079  prev->Set(v8_str("next"), obj);
5080  prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5081  whammy->objects_[whammy->cursor_].Clear();
5082  }
5083  whammy->objects_[whammy->cursor_] = global;
5084  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5085  return whammy->getScript()->Run();
5086 }
5087 
5088 THREADED_TEST(WeakReference) {
5089  v8::HandleScope handle_scope;
5091  Whammy* whammy = new Whammy();
5093  0, 0, 0, 0,
5094  v8::External::New(whammy));
5095  const char* extension_list[] = { "v8/gc" };
5096  v8::ExtensionConfiguration extensions(1, extension_list);
5097  v8::Persistent<Context> context = Context::New(&extensions);
5098  Context::Scope context_scope(context);
5099 
5100  v8::Handle<v8::Object> interceptor = templ->NewInstance();
5101  context->Global()->Set(v8_str("whammy"), interceptor);
5102  const char* code =
5103  "var last;"
5104  "for (var i = 0; i < 10000; i++) {"
5105  " var obj = whammy.length;"
5106  " if (last) last.next = obj;"
5107  " last = obj;"
5108  "}"
5109  "gc();"
5110  "4";
5111  v8::Handle<Value> result = CompileRun(code);
5112  CHECK_EQ(4.0, result->NumberValue());
5113  delete whammy;
5114  context.Dispose();
5115 }
5116 
5117 
5118 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5119  obj.Dispose();
5120  obj.Clear();
5121  *(reinterpret_cast<bool*>(data)) = true;
5122 }
5123 
5124 
5125 THREADED_TEST(IndependentWeakHandle) {
5126  v8::Persistent<Context> context = Context::New();
5127  Context::Scope context_scope(context);
5128 
5129  v8::Persistent<v8::Object> object_a;
5130 
5131  {
5132  v8::HandleScope handle_scope;
5134  }
5135 
5136  bool object_a_disposed = false;
5137  object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5138  object_a.MarkIndependent();
5139  HEAP->PerformScavenge();
5140  CHECK(object_a_disposed);
5141 }
5142 
5143 
5144 static void InvokeScavenge() {
5145  HEAP->PerformScavenge();
5146 }
5147 
5148 
5149 static void InvokeMarkSweep() {
5150  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5151 }
5152 
5153 
5154 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5155  obj.Dispose();
5156  obj.Clear();
5157  *(reinterpret_cast<bool*>(data)) = true;
5158  InvokeScavenge();
5159 }
5160 
5161 
5162 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5163  obj.Dispose();
5164  obj.Clear();
5165  *(reinterpret_cast<bool*>(data)) = true;
5166  InvokeMarkSweep();
5167 }
5168 
5169 
5170 THREADED_TEST(GCFromWeakCallbacks) {
5171  v8::Persistent<Context> context = Context::New();
5172  Context::Scope context_scope(context);
5173 
5174  static const int kNumberOfGCTypes = 2;
5175  v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5176  {&ForceScavenge, &ForceMarkSweep};
5177 
5178  typedef void (*GCInvoker)();
5179  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5180 
5181  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5182  for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5184  {
5185  v8::HandleScope handle_scope;
5187  }
5188  bool disposed = false;
5189  object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5190  object.MarkIndependent();
5191  invoke_gc[outer_gc]();
5192  CHECK(disposed);
5193  }
5194  }
5195 }
5196 
5197 
5198 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5199  obj.ClearWeak();
5200  *(reinterpret_cast<bool*>(data)) = true;
5201 }
5202 
5203 
5204 THREADED_TEST(IndependentHandleRevival) {
5205  v8::Persistent<Context> context = Context::New();
5206  Context::Scope context_scope(context);
5207 
5209  {
5210  v8::HandleScope handle_scope;
5212  object->Set(v8_str("x"), v8::Integer::New(1));
5213  v8::Local<String> y_str = v8_str("y");
5214  object->Set(y_str, y_str);
5215  }
5216  bool revived = false;
5217  object.MakeWeak(&revived, &RevivingCallback);
5218  object.MarkIndependent();
5219  HEAP->PerformScavenge();
5220  CHECK(revived);
5221  HEAP->CollectAllGarbage(true);
5222  {
5223  v8::HandleScope handle_scope;
5224  v8::Local<String> y_str = v8_str("y");
5225  CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5226  CHECK(object->Get(y_str)->Equals(y_str));
5227  }
5228 }
5229 
5230 
5232 
5233 
5234 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5236  CHECK_EQ(args_fun, args.Callee());
5237  CHECK_EQ(3, args.Length());
5238  CHECK_EQ(v8::Integer::New(1), args[0]);
5239  CHECK_EQ(v8::Integer::New(2), args[1]);
5240  CHECK_EQ(v8::Integer::New(3), args[2]);
5241  CHECK_EQ(v8::Undefined(), args[3]);
5242  v8::HandleScope scope;
5243  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5244  return v8::Undefined();
5245 }
5246 
5247 
5248 THREADED_TEST(Arguments) {
5249  v8::HandleScope scope;
5250  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5251  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5252  LocalContext context(NULL, global);
5253  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5254  v8_compile("f(1, 2, 3)")->Run();
5255 }
5256 
5257 
5258 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5259  const AccessorInfo&) {
5260  return v8::Handle<Value>();
5261 }
5262 
5263 
5264 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5265  const AccessorInfo&) {
5266  return v8::Handle<Value>();
5267 }
5268 
5269 
5270 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5271  const AccessorInfo&) {
5272  if (!name->Equals(v8_str("foo"))) {
5273  return v8::Handle<v8::Boolean>(); // not intercepted
5274  }
5275 
5276  return v8::False(); // intercepted, and don't delete the property
5277 }
5278 
5279 
5280 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5281  if (index != 2) {
5282  return v8::Handle<v8::Boolean>(); // not intercepted
5283  }
5284 
5285  return v8::False(); // intercepted, and don't delete the property
5286 }
5287 
5288 
5289 THREADED_TEST(Deleter) {
5290  v8::HandleScope scope;
5291  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5292  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5293  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5294  LocalContext context;
5295  context->Global()->Set(v8_str("k"), obj->NewInstance());
5296  CompileRun(
5297  "k.foo = 'foo';"
5298  "k.bar = 'bar';"
5299  "k[2] = 2;"
5300  "k[4] = 4;");
5301  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5302  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5303 
5304  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5305  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5306 
5307  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5308  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5309 
5310  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5311  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5312 }
5313 
5314 
5315 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5317  if (name->Equals(v8_str("foo")) ||
5318  name->Equals(v8_str("bar")) ||
5319  name->Equals(v8_str("baz"))) {
5320  return v8::Undefined();
5321  }
5322  return v8::Handle<Value>();
5323 }
5324 
5325 
5326 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5328  if (index == 0 || index == 1) return v8::Undefined();
5329  return v8::Handle<Value>();
5330 }
5331 
5332 
5333 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5336  result->Set(v8::Integer::New(0), v8_str("foo"));
5337  result->Set(v8::Integer::New(1), v8_str("bar"));
5338  result->Set(v8::Integer::New(2), v8_str("baz"));
5339  return result;
5340 }
5341 
5342 
5343 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5346  result->Set(v8::Integer::New(0), v8_str("0"));
5347  result->Set(v8::Integer::New(1), v8_str("1"));
5348  return result;
5349 }
5350 
5351 
5352 THREADED_TEST(Enumerators) {
5353  v8::HandleScope scope;
5354  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5355  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5356  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5357  LocalContext context;
5358  context->Global()->Set(v8_str("k"), obj->NewInstance());
5360  "k[10] = 0;"
5361  "k.a = 0;"
5362  "k[5] = 0;"
5363  "k.b = 0;"
5364  "k[4294967295] = 0;"
5365  "k.c = 0;"
5366  "k[4294967296] = 0;"
5367  "k.d = 0;"
5368  "k[140000] = 0;"
5369  "k.e = 0;"
5370  "k[30000000000] = 0;"
5371  "k.f = 0;"
5372  "var result = [];"
5373  "for (var prop in k) {"
5374  " result.push(prop);"
5375  "}"
5376  "result"));
5377  // Check that we get all the property names returned including the
5378  // ones from the enumerators in the right order: indexed properties
5379  // in numerical order, indexed interceptor properties, named
5380  // properties in insertion order, named interceptor properties.
5381  // This order is not mandated by the spec, so this test is just
5382  // documenting our behavior.
5383  CHECK_EQ(17, result->Length());
5384  // Indexed properties in numerical order.
5385  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5386  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5387  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5388  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5389  // Indexed interceptor properties in the order they are returned
5390  // from the enumerator interceptor.
5391  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5392  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5393  // Named properties in insertion order.
5394  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5395  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5396  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5397  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5398  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5399  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5400  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5401  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5402  // Named interceptor properties.
5403  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5404  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5405  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5406 }
5407 
5408 
5411 
5412 
5413 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5415  p_getter_count++;
5416  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5417  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5418  if (name->Equals(v8_str("p1"))) {
5419  CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5420  } else if (name->Equals(v8_str("p2"))) {
5421  CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5422  } else if (name->Equals(v8_str("p3"))) {
5423  CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5424  } else if (name->Equals(v8_str("p4"))) {
5425  CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5426  }
5427  return v8::Undefined();
5428 }
5429 
5430 
5431 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5433  LocalContext context;
5434  context->Global()->Set(v8_str("o1"), obj->NewInstance());
5435  CompileRun(
5436  "o1.__proto__ = { };"
5437  "var o2 = { __proto__: o1 };"
5438  "var o3 = { __proto__: o2 };"
5439  "var o4 = { __proto__: o3 };"
5440  "for (var i = 0; i < 10; i++) o4.p4;"
5441  "for (var i = 0; i < 10; i++) o3.p3;"
5442  "for (var i = 0; i < 10; i++) o2.p2;"
5443  "for (var i = 0; i < 10; i++) o1.p1;");
5444 }
5445 
5446 
5447 static v8::Handle<Value> PGetter2(Local<String> name,
5448  const AccessorInfo& info) {
5450  p_getter_count2++;
5451  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5452  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5453  if (name->Equals(v8_str("p1"))) {
5454  CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5455  } else if (name->Equals(v8_str("p2"))) {
5456  CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5457  } else if (name->Equals(v8_str("p3"))) {
5458  CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5459  } else if (name->Equals(v8_str("p4"))) {
5460  CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5461  }
5462  return v8::Undefined();
5463 }
5464 
5465 
5466 THREADED_TEST(GetterHolders) {
5467  v8::HandleScope scope;
5468  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5469  obj->SetAccessor(v8_str("p1"), PGetter);
5470  obj->SetAccessor(v8_str("p2"), PGetter);
5471  obj->SetAccessor(v8_str("p3"), PGetter);
5472  obj->SetAccessor(v8_str("p4"), PGetter);
5473  p_getter_count = 0;
5474  RunHolderTest(obj);
5475  CHECK_EQ(40, p_getter_count);
5476 }
5477 
5478 
5479 THREADED_TEST(PreInterceptorHolders) {
5480  v8::HandleScope scope;
5481  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5482  obj->SetNamedPropertyHandler(PGetter2);
5483  p_getter_count2 = 0;
5484  RunHolderTest(obj);
5485  CHECK_EQ(40, p_getter_count2);
5486 }
5487 
5488 
5489 THREADED_TEST(ObjectInstantiation) {
5490  v8::HandleScope scope;
5491  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5492  templ->SetAccessor(v8_str("t"), PGetter2);
5493  LocalContext context;
5494  context->Global()->Set(v8_str("o"), templ->NewInstance());
5495  for (int i = 0; i < 100; i++) {
5496  v8::HandleScope inner_scope;
5497  v8::Handle<v8::Object> obj = templ->NewInstance();
5498  CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5499  context->Global()->Set(v8_str("o2"), obj);
5500  v8::Handle<Value> value =
5501  Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5502  CHECK_EQ(v8::True(), value);
5503  context->Global()->Set(v8_str("o"), obj);
5504  }
5505 }
5506 
5507 
5508 static int StrCmp16(uint16_t* a, uint16_t* b) {
5509  while (true) {
5510  if (*a == 0 && *b == 0) return 0;
5511  if (*a != *b) return 0 + *a - *b;
5512  a++;
5513  b++;
5514  }
5515 }
5516 
5517 
5518 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5519  while (true) {
5520  if (n-- == 0) return 0;
5521  if (*a == 0 && *b == 0) return 0;
5522  if (*a != *b) return 0 + *a - *b;
5523  a++;
5524  b++;
5525  }
5526 }
5527 
5528 
5529 int GetUtf8Length(Handle<String> str) {
5530  int len = str->Utf8Length();
5531  if (len < 0) {
5533  i::FlattenString(istr);
5534  len = str->Utf8Length();
5535  }
5536  return len;
5537 }
5538 
5539 
5540 THREADED_TEST(StringWrite) {
5541  LocalContext context;
5542  v8::HandleScope scope;
5543  v8::Handle<String> str = v8_str("abcde");
5544  // abc<Icelandic eth><Unicode snowman>.
5545  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5546  const int kStride = 4; // Must match stride in for loops in JS below.
5547  CompileRun(
5548  "var left = '';"
5549  "for (var i = 0; i < 0xd800; i += 4) {"
5550  " left = left + String.fromCharCode(i);"
5551  "}");
5552  CompileRun(
5553  "var right = '';"
5554  "for (var i = 0; i < 0xd800; i += 4) {"
5555  " right = String.fromCharCode(i) + right;"
5556  "}");
5557  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5558  Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5559  Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5560 
5561  CHECK_EQ(5, str2->Length());
5562  CHECK_EQ(0xd800 / kStride, left_tree->Length());
5563  CHECK_EQ(0xd800 / kStride, right_tree->Length());
5564 
5565  char buf[100];
5566  char utf8buf[0xd800 * 3];
5567  uint16_t wbuf[100];
5568  int len;
5569  int charlen;
5570 
5571  memset(utf8buf, 0x1, 1000);
5572  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5573  CHECK_EQ(9, len);
5574  CHECK_EQ(5, charlen);
5575  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5576 
5577  memset(utf8buf, 0x1, 1000);
5578  len = str2->WriteUtf8(utf8buf, 8, &charlen);
5579  CHECK_EQ(8, len);
5580  CHECK_EQ(5, charlen);
5581  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5582 
5583  memset(utf8buf, 0x1, 1000);
5584  len = str2->WriteUtf8(utf8buf, 7, &charlen);
5585  CHECK_EQ(5, len);
5586  CHECK_EQ(4, charlen);
5587  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5588 
5589  memset(utf8buf, 0x1, 1000);
5590  len = str2->WriteUtf8(utf8buf, 6, &charlen);
5591  CHECK_EQ(5, len);
5592  CHECK_EQ(4, charlen);
5593  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5594 
5595  memset(utf8buf, 0x1, 1000);
5596  len = str2->WriteUtf8(utf8buf, 5, &charlen);
5597  CHECK_EQ(5, len);
5598  CHECK_EQ(4, charlen);
5599  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5600 
5601  memset(utf8buf, 0x1, 1000);
5602  len = str2->WriteUtf8(utf8buf, 4, &charlen);
5603  CHECK_EQ(3, len);
5604  CHECK_EQ(3, charlen);
5605  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5606 
5607  memset(utf8buf, 0x1, 1000);
5608  len = str2->WriteUtf8(utf8buf, 3, &charlen);
5609  CHECK_EQ(3, len);
5610  CHECK_EQ(3, charlen);
5611  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5612 
5613  memset(utf8buf, 0x1, 1000);
5614  len = str2->WriteUtf8(utf8buf, 2, &charlen);
5615  CHECK_EQ(2, len);
5616  CHECK_EQ(2, charlen);
5617  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5618 
5619  memset(utf8buf, 0x1, sizeof(utf8buf));
5620  len = GetUtf8Length(left_tree);
5621  int utf8_expected =
5622  (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5623  CHECK_EQ(utf8_expected, len);
5624  len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5625  CHECK_EQ(utf8_expected, len);
5626  CHECK_EQ(0xd800 / kStride, charlen);
5627  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5628  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5629  CHECK_EQ(0xc0 - kStride,
5630  static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5631  CHECK_EQ(1, utf8buf[utf8_expected]);
5632 
5633  memset(utf8buf, 0x1, sizeof(utf8buf));
5634  len = GetUtf8Length(right_tree);
5635  CHECK_EQ(utf8_expected, len);
5636  len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5637  CHECK_EQ(utf8_expected, len);
5638  CHECK_EQ(0xd800 / kStride, charlen);
5639  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5640  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5641  CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5642  CHECK_EQ(1, utf8buf[utf8_expected]);
5643 
5644  memset(buf, 0x1, sizeof(buf));
5645  memset(wbuf, 0x1, sizeof(wbuf));
5646  len = str->WriteAscii(buf);
5647  CHECK_EQ(5, len);
5648  len = str->Write(wbuf);
5649  CHECK_EQ(5, len);
5650  CHECK_EQ(0, strcmp("abcde", buf));
5651  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5652  CHECK_EQ(0, StrCmp16(answer1, wbuf));
5653 
5654  memset(buf, 0x1, sizeof(buf));
5655  memset(wbuf, 0x1, sizeof(wbuf));
5656  len = str->WriteAscii(buf, 0, 4);
5657  CHECK_EQ(4, len);
5658  len = str->Write(wbuf, 0, 4);
5659  CHECK_EQ(4, len);
5660  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5661  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5662  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5663 
5664  memset(buf, 0x1, sizeof(buf));
5665  memset(wbuf, 0x1, sizeof(wbuf));
5666  len = str->WriteAscii(buf, 0, 5);
5667  CHECK_EQ(5, len);
5668  len = str->Write(wbuf, 0, 5);
5669  CHECK_EQ(5, len);
5670  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5671  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5672  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5673 
5674  memset(buf, 0x1, sizeof(buf));
5675  memset(wbuf, 0x1, sizeof(wbuf));
5676  len = str->WriteAscii(buf, 0, 6);
5677  CHECK_EQ(5, len);
5678  len = str->Write(wbuf, 0, 6);
5679  CHECK_EQ(5, len);
5680  CHECK_EQ(0, strcmp("abcde", buf));
5681  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5682  CHECK_EQ(0, StrCmp16(answer4, wbuf));
5683 
5684  memset(buf, 0x1, sizeof(buf));
5685  memset(wbuf, 0x1, sizeof(wbuf));
5686  len = str->WriteAscii(buf, 4, -1);
5687  CHECK_EQ(1, len);
5688  len = str->Write(wbuf, 4, -1);
5689  CHECK_EQ(1, len);
5690  CHECK_EQ(0, strcmp("e", buf));
5691  uint16_t answer5[] = {'e', '\0'};
5692  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5693 
5694  memset(buf, 0x1, sizeof(buf));
5695  memset(wbuf, 0x1, sizeof(wbuf));
5696  len = str->WriteAscii(buf, 4, 6);
5697  CHECK_EQ(1, len);
5698  len = str->Write(wbuf, 4, 6);
5699  CHECK_EQ(1, len);
5700  CHECK_EQ(0, strcmp("e", buf));
5701  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5702 
5703  memset(buf, 0x1, sizeof(buf));
5704  memset(wbuf, 0x1, sizeof(wbuf));
5705  len = str->WriteAscii(buf, 4, 1);
5706  CHECK_EQ(1, len);
5707  len = str->Write(wbuf, 4, 1);
5708  CHECK_EQ(1, len);
5709  CHECK_EQ(0, strncmp("e\1", buf, 2));
5710  uint16_t answer6[] = {'e', 0x101};
5711  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5712 
5713  memset(buf, 0x1, sizeof(buf));
5714  memset(wbuf, 0x1, sizeof(wbuf));
5715  len = str->WriteAscii(buf, 3, 1);
5716  CHECK_EQ(1, len);
5717  len = str->Write(wbuf, 3, 1);
5718  CHECK_EQ(1, len);
5719  CHECK_EQ(0, strncmp("d\1", buf, 2));
5720  uint16_t answer7[] = {'d', 0x101};
5721  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5722 
5723  memset(wbuf, 0x1, sizeof(wbuf));
5724  wbuf[5] = 'X';
5725  len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5726  CHECK_EQ(5, len);
5727  CHECK_EQ('X', wbuf[5]);
5728  uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5729  uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5730  CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5731  CHECK_NE(0, StrCmp16(answer8b, wbuf));
5732  wbuf[5] = '\0';
5733  CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5734 
5735  memset(buf, 0x1, sizeof(buf));
5736  buf[5] = 'X';
5737  len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5738  CHECK_EQ(5, len);
5739  CHECK_EQ('X', buf[5]);
5740  CHECK_EQ(0, strncmp("abcde", buf, 5));
5741  CHECK_NE(0, strcmp("abcde", buf));
5742  buf[5] = '\0';
5743  CHECK_EQ(0, strcmp("abcde", buf));
5744 
5745  memset(utf8buf, 0x1, sizeof(utf8buf));
5746  utf8buf[8] = 'X';
5747  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5748  String::NO_NULL_TERMINATION);
5749  CHECK_EQ(8, len);
5750  CHECK_EQ('X', utf8buf[8]);
5751  CHECK_EQ(5, charlen);
5752  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5753  CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5754  utf8buf[8] = '\0';
5755  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5756 }
5757 
5758 
5759 static void Utf16Helper(
5760  LocalContext& context,
5761  const char* name,
5762  const char* lengths_name,
5763  int len) {
5764  Local<v8::Array> a =
5765  Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5766  Local<v8::Array> alens =
5767  Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5768  for (int i = 0; i < len; i++) {
5769  Local<v8::String> string =
5770  Local<v8::String>::Cast(a->Get(i));
5771  Local<v8::Number> expected_len =
5772  Local<v8::Number>::Cast(alens->Get(i));
5773  CHECK_EQ(expected_len->Value() != string->Length(),
5774  string->MayContainNonAscii());
5775  int length = GetUtf8Length(string);
5776  CHECK_EQ(static_cast<int>(expected_len->Value()), length);
5777  }
5778 }
5779 
5780 
5781 static uint16_t StringGet(Handle<String> str, int index) {
5782  i::Handle<i::String> istring =
5783  v8::Utils::OpenHandle(String::Cast(*str));
5784  return istring->Get(index);
5785 }
5786 
5787 
5788 static void WriteUtf8Helper(
5789  LocalContext& context,
5790  const char* name,
5791  const char* lengths_name,
5792  int len) {
5793  Local<v8::Array> b =
5794  Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5795  Local<v8::Array> alens =
5796  Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5797  char buffer[1000];
5798  char buffer2[1000];
5799  for (int i = 0; i < len; i++) {
5800  Local<v8::String> string =
5801  Local<v8::String>::Cast(b->Get(i));
5802  Local<v8::Number> expected_len =
5803  Local<v8::Number>::Cast(alens->Get(i));
5804  int utf8_length = static_cast<int>(expected_len->Value());
5805  for (int j = utf8_length + 1; j >= 0; j--) {
5806  memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
5807  memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
5808  int nchars;
5809  int utf8_written =
5810  string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
5811  int utf8_written2 =
5812  string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
5813  CHECK_GE(utf8_length + 1, utf8_written);
5814  CHECK_GE(utf8_length, utf8_written2);
5815  for (int k = 0; k < utf8_written2; k++) {
5816  CHECK_EQ(buffer[k], buffer2[k]);
5817  }
5818  CHECK(nchars * 3 >= utf8_written - 1);
5819  CHECK(nchars <= utf8_written);
5820  if (j == utf8_length + 1) {
5821  CHECK_EQ(utf8_written2, utf8_length);
5822  CHECK_EQ(utf8_written2 + 1, utf8_written);
5823  }
5824  CHECK_EQ(buffer[utf8_written], 42);
5825  if (j > utf8_length) {
5826  if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
5827  if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
5828  Handle<String> roundtrip = v8_str(buffer);
5829  CHECK(roundtrip->Equals(string));
5830  } else {
5831  if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
5832  }
5833  if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
5834  if (nchars >= 2) {
5835  uint16_t trail = StringGet(string, nchars - 1);
5836  uint16_t lead = StringGet(string, nchars - 2);
5837  if (((lead & 0xfc00) == 0xd800) &&
5838  ((trail & 0xfc00) == 0xdc00)) {
5839  unsigned char u1 = buffer2[utf8_written2 - 4];
5840  unsigned char u2 = buffer2[utf8_written2 - 3];
5841  unsigned char u3 = buffer2[utf8_written2 - 2];
5842  unsigned char u4 = buffer2[utf8_written2 - 1];
5843  CHECK_EQ((u1 & 0xf8), 0xf0);
5844  CHECK_EQ((u2 & 0xc0), 0x80);
5845  CHECK_EQ((u3 & 0xc0), 0x80);
5846  CHECK_EQ((u4 & 0xc0), 0x80);
5847  uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
5848  CHECK_EQ((u4 & 0x3f), (c & 0x3f));
5849  CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
5850  CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
5851  CHECK_EQ((u1 & 0x3), c >> 18);
5852  }
5853  }
5854  }
5855  }
5856 }
5857 
5858 
5860  LocalContext context;
5861  v8::HandleScope scope;
5862  CompileRun(
5863  "var pad = '01234567890123456789';"
5864  "var p = [];"
5865  "var plens = [20, 3, 3];"
5866  "p.push('01234567890123456789');"
5867  "var lead = 0xd800;"
5868  "var trail = 0xdc00;"
5869  "p.push(String.fromCharCode(0xd800));"
5870  "p.push(String.fromCharCode(0xdc00));"
5871  "var a = [];"
5872  "var b = [];"
5873  "var c = [];"
5874  "var alens = [];"
5875  "for (var i = 0; i < 3; i++) {"
5876  " p[1] = String.fromCharCode(lead++);"
5877  " for (var j = 0; j < 3; j++) {"
5878  " p[2] = String.fromCharCode(trail++);"
5879  " a.push(p[i] + p[j]);"
5880  " b.push(p[i] + p[j]);"
5881  " c.push(p[i] + p[j]);"
5882  " alens.push(plens[i] + plens[j]);"
5883  " }"
5884  "}"
5885  "alens[5] -= 2;" // Here the surrogate pairs match up.
5886  "var a2 = [];"
5887  "var b2 = [];"
5888  "var c2 = [];"
5889  "var a2lens = [];"
5890  "for (var m = 0; m < 9; m++) {"
5891  " for (var n = 0; n < 9; n++) {"
5892  " a2.push(a[m] + a[n]);"
5893  " b2.push(b[m] + b[n]);"
5894  " var newc = 'x' + c[m] + c[n] + 'y';"
5895  " c2.push(newc.substring(1, newc.length - 1));"
5896  " var utf = alens[m] + alens[n];" // And here.
5897  // The 'n's that start with 0xdc.. are 6-8
5898  // The 'm's that end with 0xd8.. are 1, 4 and 7
5899  " if ((m % 3) == 1 && n >= 6) utf -= 2;"
5900  " a2lens.push(utf);"
5901  " }"
5902  "}");
5903  Utf16Helper(context, "a", "alens", 9);
5904  Utf16Helper(context, "a2", "a2lens", 81);
5905  WriteUtf8Helper(context, "b", "alens", 9);
5906  WriteUtf8Helper(context, "b2", "a2lens", 81);
5907  WriteUtf8Helper(context, "c2", "a2lens", 81);
5908 }
5909 
5910 
5911 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
5914  return *is1 == *is2;
5915 }
5916 
5917 
5918 static void SameSymbolHelper(const char* a, const char* b) {
5919  Handle<String> symbol1 = v8::String::NewSymbol(a);
5920  Handle<String> symbol2 = v8::String::NewSymbol(b);
5921  CHECK(SameSymbol(symbol1, symbol2));
5922 }
5923 
5924 
5925 THREADED_TEST(Utf16Symbol) {
5926  LocalContext context;
5927  v8::HandleScope scope;
5928 
5929  Handle<String> symbol1 = v8::String::NewSymbol("abc");
5930  Handle<String> symbol2 = v8::String::NewSymbol("abc");
5931  CHECK(SameSymbol(symbol1, symbol2));
5932 
5933  SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
5934  "\355\240\201\355\260\205"); // 2 3-byte surrogates.
5935  SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
5936  "\360\220\220\206"); // 4 byte encoding.
5937  SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
5938  "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
5939  SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
5940  "x\360\220\220\206"); // 4 byte encoding.
5941  CompileRun(
5942  "var sym0 = 'benedictus';"
5943  "var sym0b = 'S\303\270ren';"
5944  "var sym1 = '\355\240\201\355\260\207';"
5945  "var sym2 = '\360\220\220\210';"
5946  "var sym3 = 'x\355\240\201\355\260\207';"
5947  "var sym4 = 'x\360\220\220\210';"
5948  "if (sym1.length != 2) throw sym1;"
5949  "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
5950  "if (sym2.length != 2) throw sym2;"
5951  "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
5952  "if (sym3.length != 3) throw sym3;"
5953  "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
5954  "if (sym4.length != 3) throw sym4;"
5955  "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
5956  Handle<String> sym0 = v8::String::NewSymbol("benedictus");
5957  Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
5958  Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
5959  Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
5960  Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
5961  Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
5962  v8::Local<v8::Object> global = context->Global();
5963  Local<Value> s0 = global->Get(v8_str("sym0"));
5964  Local<Value> s0b = global->Get(v8_str("sym0b"));
5965  Local<Value> s1 = global->Get(v8_str("sym1"));
5966  Local<Value> s2 = global->Get(v8_str("sym2"));
5967  Local<Value> s3 = global->Get(v8_str("sym3"));
5968  Local<Value> s4 = global->Get(v8_str("sym4"));
5969  CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
5970  CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
5971  CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
5972  CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
5973  CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
5974  CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
5975 }
5976 
5977 
5978 THREADED_TEST(ToArrayIndex) {
5979  v8::HandleScope scope;
5980  LocalContext context;
5981 
5982  v8::Handle<String> str = v8_str("42");
5983  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5984  CHECK(!index.IsEmpty());
5985  CHECK_EQ(42.0, index->Uint32Value());
5986  str = v8_str("42asdf");
5987  index = str->ToArrayIndex();
5988  CHECK(index.IsEmpty());
5989  str = v8_str("-42");
5990  index = str->ToArrayIndex();
5991  CHECK(index.IsEmpty());
5992  str = v8_str("4294967295");
5993  index = str->ToArrayIndex();
5994  CHECK(!index.IsEmpty());
5995  CHECK_EQ(4294967295.0, index->Uint32Value());
5997  index = num->ToArrayIndex();
5998  CHECK(!index.IsEmpty());
5999  CHECK_EQ(1.0, index->Uint32Value());
6000  num = v8::Number::New(-1);
6001  index = num->ToArrayIndex();
6002  CHECK(index.IsEmpty());
6004  index = obj->ToArrayIndex();
6005  CHECK(index.IsEmpty());
6006 }
6007 
6008 
6009 THREADED_TEST(ErrorConstruction) {
6010  v8::HandleScope scope;
6011  LocalContext context;
6012 
6013  v8::Handle<String> foo = v8_str("foo");
6014  v8::Handle<String> message = v8_str("message");
6015  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6016  CHECK(range_error->IsObject());
6017  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
6018  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6019  CHECK(reference_error->IsObject());
6020  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
6021  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6022  CHECK(syntax_error->IsObject());
6023  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
6024  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6025  CHECK(type_error->IsObject());
6026  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
6028  CHECK(error->IsObject());
6029  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
6030 }
6031 
6032 
6033 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6035  return v8_num(10);
6036 }
6037 
6038 
6039 static void YSetter(Local<String> name,
6040  Local<Value> value,
6041  const AccessorInfo& info) {
6042  if (info.This()->Has(name)) {
6043  info.This()->Delete(name);
6044  }
6045  info.This()->Set(name, value);
6046 }
6047 
6048 
6049 THREADED_TEST(DeleteAccessor) {
6050  v8::HandleScope scope;
6051  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6052  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6053  LocalContext context;
6054  v8::Handle<v8::Object> holder = obj->NewInstance();
6055  context->Global()->Set(v8_str("holder"), holder);
6056  v8::Handle<Value> result = CompileRun(
6057  "holder.y = 11; holder.y = 12; holder.y");
6058  CHECK_EQ(12, result->Uint32Value());
6059 }
6060 
6061 
6062 THREADED_TEST(TypeSwitch) {
6063  v8::HandleScope scope;
6067  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6068  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6069  LocalContext context;
6071  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6072  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6073  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6074  for (int i = 0; i < 10; i++) {
6075  CHECK_EQ(0, type_switch->match(obj0));
6076  CHECK_EQ(1, type_switch->match(obj1));
6077  CHECK_EQ(2, type_switch->match(obj2));
6078  CHECK_EQ(3, type_switch->match(obj3));
6079  CHECK_EQ(3, type_switch->match(obj3));
6080  CHECK_EQ(2, type_switch->match(obj2));
6081  CHECK_EQ(1, type_switch->match(obj1));
6082  CHECK_EQ(0, type_switch->match(obj0));
6083  }
6084 }
6085 
6086 
6087 // For use within the TestSecurityHandler() test.
6088 static bool g_security_callback_result = false;
6089 static bool NamedSecurityTestCallback(Local<v8::Object> global,
6090  Local<Value> name,
6092  Local<Value> data) {
6093  // Always allow read access.
6094  if (type == v8::ACCESS_GET)
6095  return true;
6096 
6097  // Sometimes allow other access.
6098  return g_security_callback_result;
6099 }
6100 
6101 
6102 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6103  uint32_t key,
6104  v8::AccessType type,
6105  Local<Value> data) {
6106  // Always allow read access.
6107  if (type == v8::ACCESS_GET)
6108  return true;
6109 
6110  // Sometimes allow other access.
6111  return g_security_callback_result;
6112 }
6113 
6114 
6115 static int trouble_nesting = 0;
6116 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6118  trouble_nesting++;
6119 
6120  // Call a JS function that throws an uncaught exception.
6121  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6122  Local<Value> trouble_callee = (trouble_nesting == 3) ?
6123  arg_this->Get(v8_str("trouble_callee")) :
6124  arg_this->Get(v8_str("trouble_caller"));
6125  CHECK(trouble_callee->IsFunction());
6126  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6127 }
6128 
6129 
6130 static int report_count = 0;
6131 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6133  report_count++;
6134 }
6135 
6136 
6137 // Counts uncaught exceptions, but other tests running in parallel
6138 // also have uncaught exceptions.
6139 TEST(ApiUncaughtException) {
6140  report_count = 0;
6141  v8::HandleScope scope;
6142  LocalContext env;
6143  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6144 
6145  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6146  v8::Local<v8::Object> global = env->Global();
6147  global->Set(v8_str("trouble"), fun->GetFunction());
6148 
6149  Script::Compile(v8_str("function trouble_callee() {"
6150  " var x = null;"
6151  " return x.foo;"
6152  "};"
6153  "function trouble_caller() {"
6154  " trouble();"
6155  "};"))->Run();
6156  Local<Value> trouble = global->Get(v8_str("trouble"));
6157  CHECK(trouble->IsFunction());
6158  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6159  CHECK(trouble_callee->IsFunction());
6160  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6161  CHECK(trouble_caller->IsFunction());
6162  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6163  CHECK_EQ(1, report_count);
6164  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6165 }
6166 
6167 static const char* script_resource_name = "ExceptionInNativeScript.js";
6168 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6170  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6171  CHECK(!name_val.IsEmpty() && name_val->IsString());
6173  CHECK_EQ(script_resource_name, *name);
6174  CHECK_EQ(3, message->GetLineNumber());
6175  v8::String::AsciiValue source_line(message->GetSourceLine());
6176  CHECK_EQ(" new o.foo();", *source_line);
6177 }
6178 
6179 TEST(ExceptionInNativeScript) {
6180  v8::HandleScope scope;
6181  LocalContext env;
6182  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6183 
6184  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6185  v8::Local<v8::Object> global = env->Global();
6186  global->Set(v8_str("trouble"), fun->GetFunction());
6187 
6188  Script::Compile(v8_str("function trouble() {\n"
6189  " var o = {};\n"
6190  " new o.foo();\n"
6191  "};"), v8::String::New(script_resource_name))->Run();
6192  Local<Value> trouble = global->Get(v8_str("trouble"));
6193  CHECK(trouble->IsFunction());
6194  Function::Cast(*trouble)->Call(global, 0, NULL);
6195  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6196 }
6197 
6198 
6199 TEST(CompilationErrorUsingTryCatchHandler) {
6200  v8::HandleScope scope;
6201  LocalContext env;
6202  v8::TryCatch try_catch;
6203  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6204  CHECK_NE(NULL, *try_catch.Exception());
6205  CHECK(try_catch.HasCaught());
6206 }
6207 
6208 
6209 TEST(TryCatchFinallyUsingTryCatchHandler) {
6210  v8::HandleScope scope;
6211  LocalContext env;
6212  v8::TryCatch try_catch;
6213  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6214  CHECK(!try_catch.HasCaught());
6215  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6216  CHECK(try_catch.HasCaught());
6217  try_catch.Reset();
6218  Script::Compile(v8_str("(function() {"
6219  "try { throw ''; } finally { return; }"
6220  "})()"))->Run();
6221  CHECK(!try_catch.HasCaught());
6222  Script::Compile(v8_str("(function()"
6223  " { try { throw ''; } finally { throw 0; }"
6224  "})()"))->Run();
6225  CHECK(try_catch.HasCaught());
6226 }
6227 
6228 
6229 // SecurityHandler can't be run twice
6230 TEST(SecurityHandler) {
6231  v8::HandleScope scope0;
6233  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6234  IndexedSecurityTestCallback);
6235  // Create an environment
6236  v8::Persistent<Context> context0 =
6237  Context::New(NULL, global_template);
6238  context0->Enter();
6239 
6240  v8::Handle<v8::Object> global0 = context0->Global();
6241  v8::Handle<Script> script0 = v8_compile("foo = 111");
6242  script0->Run();
6243  global0->Set(v8_str("0"), v8_num(999));
6244  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6245  CHECK_EQ(111, foo0->Int32Value());
6246  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6247  CHECK_EQ(999, z0->Int32Value());
6248 
6249  // Create another environment, should fail security checks.
6250  v8::HandleScope scope1;
6251 
6252  v8::Persistent<Context> context1 =
6253  Context::New(NULL, global_template);
6254  context1->Enter();
6255 
6256  v8::Handle<v8::Object> global1 = context1->Global();
6257  global1->Set(v8_str("othercontext"), global0);
6258  // This set will fail the security check.
6259  v8::Handle<Script> script1 =
6260  v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6261  script1->Run();
6262  // This read will pass the security check.
6263  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6264  CHECK_EQ(111, foo1->Int32Value());
6265  // This read will pass the security check.
6266  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6267  CHECK_EQ(999, z1->Int32Value());
6268 
6269  // Create another environment, should pass security checks.
6270  { g_security_callback_result = true; // allow security handler to pass.
6271  v8::HandleScope scope2;
6272  LocalContext context2;
6273  v8::Handle<v8::Object> global2 = context2->Global();
6274  global2->Set(v8_str("othercontext"), global0);
6275  v8::Handle<Script> script2 =
6276  v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6277  script2->Run();
6278  v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6279  CHECK_EQ(333, foo2->Int32Value());
6280  v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6281  CHECK_EQ(888, z2->Int32Value());
6282  }
6283 
6284  context1->Exit();
6285  context1.Dispose();
6286 
6287  context0->Exit();
6288  context0.Dispose();
6289 }
6290 
6291 
6292 THREADED_TEST(SecurityChecks) {
6293  v8::HandleScope handle_scope;
6294  LocalContext env1;
6295  v8::Persistent<Context> env2 = Context::New();
6296 
6297  Local<Value> foo = v8_str("foo");
6298  Local<Value> bar = v8_str("bar");
6299 
6300  // Set to the same domain.
6301  env1->SetSecurityToken(foo);
6302 
6303  // Create a function in env1.
6304  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6305  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6306  CHECK(spy->IsFunction());
6307 
6308  // Create another function accessing global objects.
6309  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
6310  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6311  CHECK(spy2->IsFunction());
6312 
6313  // Switch to env2 in the same domain and invoke spy on env2.
6314  {
6315  env2->SetSecurityToken(foo);
6316  // Enter env2
6317  Context::Scope scope_env2(env2);
6318  Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6319  CHECK(result->IsFunction());
6320  }
6321 
6322  {
6323  env2->SetSecurityToken(bar);
6324  Context::Scope scope_env2(env2);
6325 
6326  // Call cross_domain_call, it should throw an exception
6327  v8::TryCatch try_catch;
6328  Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6329  CHECK(try_catch.HasCaught());
6330  }
6331 
6332  env2.Dispose();
6333 }
6334 
6335 
6336 // Regression test case for issue 1183439.
6337 THREADED_TEST(SecurityChecksForPrototypeChain) {
6338  v8::HandleScope scope;
6339  LocalContext current;
6340  v8::Persistent<Context> other = Context::New();
6341 
6342  // Change context to be able to get to the Object function in the
6343  // other context without hitting the security checks.
6344  v8::Local<Value> other_object;
6345  { Context::Scope scope(other);
6346  other_object = other->Global()->Get(v8_str("Object"));
6347  other->Global()->Set(v8_num(42), v8_num(87));
6348  }
6349 
6350  current->Global()->Set(v8_str("other"), other->Global());
6351  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6352 
6353  // Make sure the security check fails here and we get an undefined
6354  // result instead of getting the Object function. Repeat in a loop
6355  // to make sure to exercise the IC code.
6356  v8::Local<Script> access_other0 = v8_compile("other.Object");
6357  v8::Local<Script> access_other1 = v8_compile("other[42]");
6358  for (int i = 0; i < 5; i++) {
6359  CHECK(!access_other0->Run()->Equals(other_object));
6360  CHECK(access_other0->Run()->IsUndefined());
6361  CHECK(!access_other1->Run()->Equals(v8_num(87)));
6362  CHECK(access_other1->Run()->IsUndefined());
6363  }
6364 
6365  // Create an object that has 'other' in its prototype chain and make
6366  // sure we cannot access the Object function indirectly through
6367  // that. Repeat in a loop to make sure to exercise the IC code.
6368  v8_compile("function F() { };"
6369  "F.prototype = other;"
6370  "var f = new F();")->Run();
6371  v8::Local<Script> access_f0 = v8_compile("f.Object");
6372  v8::Local<Script> access_f1 = v8_compile("f[42]");
6373  for (int j = 0; j < 5; j++) {
6374  CHECK(!access_f0->Run()->Equals(other_object));
6375  CHECK(access_f0->Run()->IsUndefined());
6376  CHECK(!access_f1->Run()->Equals(v8_num(87)));
6377  CHECK(access_f1->Run()->IsUndefined());
6378  }
6379 
6380  // Now it gets hairy: Set the prototype for the other global object
6381  // to be the current global object. The prototype chain for 'f' now
6382  // goes through 'other' but ends up in the current global object.
6383  { Context::Scope scope(other);
6384  other->Global()->Set(v8_str("__proto__"), current->Global());
6385  }
6386  // Set a named and an index property on the current global
6387  // object. To force the lookup to go through the other global object,
6388  // the properties must not exist in the other global object.
6389  current->Global()->Set(v8_str("foo"), v8_num(100));
6390  current->Global()->Set(v8_num(99), v8_num(101));
6391  // Try to read the properties from f and make sure that the access
6392  // gets stopped by the security checks on the other global object.
6393  Local<Script> access_f2 = v8_compile("f.foo");
6394  Local<Script> access_f3 = v8_compile("f[99]");
6395  for (int k = 0; k < 5; k++) {
6396  CHECK(!access_f2->Run()->Equals(v8_num(100)));
6397  CHECK(access_f2->Run()->IsUndefined());
6398  CHECK(!access_f3->Run()->Equals(v8_num(101)));
6399  CHECK(access_f3->Run()->IsUndefined());
6400  }
6401  other.Dispose();
6402 }
6403 
6404 
6405 THREADED_TEST(CrossDomainDelete) {
6406  v8::HandleScope handle_scope;
6407  LocalContext env1;
6408  v8::Persistent<Context> env2 = Context::New();
6409 
6410  Local<Value> foo = v8_str("foo");
6411  Local<Value> bar = v8_str("bar");
6412 
6413  // Set to the same domain.
6414  env1->SetSecurityToken(foo);
6415  env2->SetSecurityToken(foo);
6416 
6417  env1->Global()->Set(v8_str("prop"), v8_num(3));
6418  env2->Global()->Set(v8_str("env1"), env1->Global());
6419 
6420  // Change env2 to a different domain and delete env1.prop.
6421  env2->SetSecurityToken(bar);
6422  {
6423  Context::Scope scope_env2(env2);
6424  Local<Value> result =
6425  Script::Compile(v8_str("delete env1.prop"))->Run();
6426  CHECK(result->IsFalse());
6427  }
6428 
6429  // Check that env1.prop still exists.
6430  Local<Value> v = env1->Global()->Get(v8_str("prop"));
6431  CHECK(v->IsNumber());
6432  CHECK_EQ(3, v->Int32Value());
6433 
6434  env2.Dispose();
6435 }
6436 
6437 
6438 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6439  v8::HandleScope handle_scope;
6440  LocalContext env1;
6441  v8::Persistent<Context> env2 = Context::New();
6442 
6443  Local<Value> foo = v8_str("foo");
6444  Local<Value> bar = v8_str("bar");
6445 
6446  // Set to the same domain.
6447  env1->SetSecurityToken(foo);
6448  env2->SetSecurityToken(foo);
6449 
6450  env1->Global()->Set(v8_str("prop"), v8_num(3));
6451  env2->Global()->Set(v8_str("env1"), env1->Global());
6452 
6453  // env1.prop is enumerable in env2.
6454  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6455  {
6456  Context::Scope scope_env2(env2);
6457  Local<Value> result = Script::Compile(test)->Run();
6458  CHECK(result->IsTrue());
6459  }
6460 
6461  // Change env2 to a different domain and test again.
6462  env2->SetSecurityToken(bar);
6463  {
6464  Context::Scope scope_env2(env2);
6465  Local<Value> result = Script::Compile(test)->Run();
6466  CHECK(result->IsFalse());
6467  }
6468 
6469  env2.Dispose();
6470 }
6471 
6472 
6473 THREADED_TEST(CrossDomainForIn) {
6474  v8::HandleScope handle_scope;
6475  LocalContext env1;
6476  v8::Persistent<Context> env2 = Context::New();
6477 
6478  Local<Value> foo = v8_str("foo");
6479  Local<Value> bar = v8_str("bar");
6480 
6481  // Set to the same domain.
6482  env1->SetSecurityToken(foo);
6483  env2->SetSecurityToken(foo);
6484 
6485  env1->Global()->Set(v8_str("prop"), v8_num(3));
6486  env2->Global()->Set(v8_str("env1"), env1->Global());
6487 
6488  // Change env2 to a different domain and set env1's global object
6489  // as the __proto__ of an object in env2 and enumerate properties
6490  // in for-in. It shouldn't enumerate properties on env1's global
6491  // object.
6492  env2->SetSecurityToken(bar);
6493  {
6494  Context::Scope scope_env2(env2);
6495  Local<Value> result =
6496  CompileRun("(function(){var obj = {'__proto__':env1};"
6497  "for (var p in obj)"
6498  " if (p == 'prop') return false;"
6499  "return true;})()");
6500  CHECK(result->IsTrue());
6501  }
6502  env2.Dispose();
6503 }
6504 
6505 
6506 TEST(ContextDetachGlobal) {
6507  v8::HandleScope handle_scope;
6508  LocalContext env1;
6509  v8::Persistent<Context> env2 = Context::New();
6510 
6511  Local<v8::Object> global1 = env1->Global();
6512 
6513  Local<Value> foo = v8_str("foo");
6514 
6515  // Set to the same domain.
6516  env1->SetSecurityToken(foo);
6517  env2->SetSecurityToken(foo);
6518 
6519  // Enter env2
6520  env2->Enter();
6521 
6522  // Create a function in env2 and add a reference to it in env1.
6523  Local<v8::Object> global2 = env2->Global();
6524  global2->Set(v8_str("prop"), v8::Integer::New(1));
6525  CompileRun("function getProp() {return prop;}");
6526 
6527  env1->Global()->Set(v8_str("getProp"),
6528  global2->Get(v8_str("getProp")));
6529 
6530  // Detach env2's global, and reuse the global object of env2
6531  env2->Exit();
6532  env2->DetachGlobal();
6533  // env2 has a new global object.
6534  CHECK(!env2->Global()->Equals(global2));
6535 
6537  Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6538  env3->SetSecurityToken(v8_str("bar"));
6539  env3->Enter();
6540 
6541  Local<v8::Object> global3 = env3->Global();
6542  CHECK_EQ(global2, global3);
6543  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6544  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6545  global3->Set(v8_str("prop"), v8::Integer::New(-1));
6546  global3->Set(v8_str("prop2"), v8::Integer::New(2));
6547  env3->Exit();
6548 
6549  // Call getProp in env1, and it should return the value 1
6550  {
6551  Local<Value> get_prop = global1->Get(v8_str("getProp"));
6552  CHECK(get_prop->IsFunction());
6553  v8::TryCatch try_catch;
6554  Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6555  CHECK(!try_catch.HasCaught());
6556  CHECK_EQ(1, r->Int32Value());
6557  }
6558 
6559  // Check that env3 is not accessible from env1
6560  {
6561  Local<Value> r = global3->Get(v8_str("prop2"));
6562  CHECK(r->IsUndefined());
6563  }
6564 
6565  env2.Dispose();
6566  env3.Dispose();
6567 }
6568 
6569 
6570 TEST(DetachAndReattachGlobal) {
6571  v8::HandleScope scope;
6572  LocalContext env1;
6573 
6574  // Create second environment.
6575  v8::Persistent<Context> env2 = Context::New();
6576 
6577  Local<Value> foo = v8_str("foo");
6578 
6579  // Set same security token for env1 and env2.
6580  env1->SetSecurityToken(foo);
6581  env2->SetSecurityToken(foo);
6582 
6583  // Create a property on the global object in env2.
6584  {
6585  v8::Context::Scope scope(env2);
6586  env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6587  }
6588 
6589  // Create a reference to env2 global from env1 global.
6590  env1->Global()->Set(v8_str("other"), env2->Global());
6591 
6592  // Check that we have access to other.p in env2 from env1.
6593  Local<Value> result = CompileRun("other.p");
6594  CHECK(result->IsInt32());
6595  CHECK_EQ(42, result->Int32Value());
6596 
6597  // Hold on to global from env2 and detach global from env2.
6598  Local<v8::Object> global2 = env2->Global();
6599  env2->DetachGlobal();
6600 
6601  // Check that the global has been detached. No other.p property can
6602  // be found.
6603  result = CompileRun("other.p");
6604  CHECK(result->IsUndefined());
6605 
6606  // Reuse global2 for env3.
6608  Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6609  CHECK_EQ(global2, env3->Global());
6610 
6611  // Start by using the same security token for env3 as for env1 and env2.
6612  env3->SetSecurityToken(foo);
6613 
6614  // Create a property on the global object in env3.
6615  {
6616  v8::Context::Scope scope(env3);
6617  env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6618  }
6619 
6620  // Check that other.p is now the property in env3 and that we have access.
6621  result = CompileRun("other.p");
6622  CHECK(result->IsInt32());
6623  CHECK_EQ(24, result->Int32Value());
6624 
6625  // Change security token for env3 to something different from env1 and env2.
6626  env3->SetSecurityToken(v8_str("bar"));
6627 
6628  // Check that we do not have access to other.p in env1. |other| is now
6629  // the global object for env3 which has a different security token,
6630  // so access should be blocked.
6631  result = CompileRun("other.p");
6632  CHECK(result->IsUndefined());
6633 
6634  // Detach the global for env3 and reattach it to env2.
6635  env3->DetachGlobal();
6636  env2->ReattachGlobal(global2);
6637 
6638  // Check that we have access to other.p again in env1. |other| is now
6639  // the global object for env2 which has the same security token as env1.
6640  result = CompileRun("other.p");
6641  CHECK(result->IsInt32());
6642  CHECK_EQ(42, result->Int32Value());
6643 
6644  env2.Dispose();
6645  env3.Dispose();
6646 }
6647 
6648 
6649 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6650 static bool NamedAccessBlocker(Local<v8::Object> global,
6651  Local<Value> name,
6652  v8::AccessType type,
6653  Local<Value> data) {
6654  return Context::GetCurrent()->Global()->Equals(global) ||
6655  allowed_access_type[type];
6656 }
6657 
6658 
6659 static bool IndexedAccessBlocker(Local<v8::Object> global,
6660  uint32_t key,
6661  v8::AccessType type,
6662  Local<Value> data) {
6663  return Context::GetCurrent()->Global()->Equals(global) ||
6664  allowed_access_type[type];
6665 }
6666 
6667 
6668 static int g_echo_value = -1;
6669 static v8::Handle<Value> EchoGetter(Local<String> name,
6670  const AccessorInfo& info) {
6671  return v8_num(g_echo_value);
6672 }
6673 
6674 
6675 static void EchoSetter(Local<String> name,
6676  Local<Value> value,
6677  const AccessorInfo&) {
6678  if (value->IsNumber())
6679  g_echo_value = value->Int32Value();
6680 }
6681 
6682 
6683 static v8::Handle<Value> UnreachableGetter(Local<String> name,
6684  const AccessorInfo& info) {
6685  CHECK(false); // This function should not be called..
6686  return v8::Undefined();
6687 }
6688 
6689 
6690 static void UnreachableSetter(Local<String>, Local<Value>,
6691  const AccessorInfo&) {
6692  CHECK(false); // This function should nto be called.
6693 }
6694 
6695 
6697  v8::HandleScope handle_scope;
6699 
6700  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6701  IndexedAccessBlocker);
6702 
6703  // Add an accessor accessible by cross-domain JS code.
6704  global_template->SetAccessor(
6705  v8_str("accessible_prop"),
6706  EchoGetter, EchoSetter,
6709 
6710  // Add an accessor that is not accessible by cross-domain JS code.
6711  global_template->SetAccessor(v8_str("blocked_prop"),
6712  UnreachableGetter, UnreachableSetter,
6714  v8::DEFAULT);
6715 
6716  // Create an environment
6717  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6718  context0->Enter();
6719 
6720  v8::Handle<v8::Object> global0 = context0->Global();
6721 
6722  // Define a property with JS getter and setter.
6723  CompileRun(
6724  "function getter() { return 'getter'; };\n"
6725  "function setter() { return 'setter'; }\n"
6726  "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6727 
6728  Local<Value> getter = global0->Get(v8_str("getter"));
6729  Local<Value> setter = global0->Get(v8_str("setter"));
6730 
6731  // And define normal element.
6732  global0->Set(239, v8_str("239"));
6733 
6734  // Define an element with JS getter and setter.
6735  CompileRun(
6736  "function el_getter() { return 'el_getter'; };\n"
6737  "function el_setter() { return 'el_setter'; };\n"
6738  "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6739 
6740  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6741  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6742 
6743  v8::HandleScope scope1;
6744 
6745  v8::Persistent<Context> context1 = Context::New();
6746  context1->Enter();
6747 
6748  v8::Handle<v8::Object> global1 = context1->Global();
6749  global1->Set(v8_str("other"), global0);
6750 
6751  // Access blocked property.
6752  CompileRun("other.blocked_prop = 1");
6753 
6754  ExpectUndefined("other.blocked_prop");
6755  ExpectUndefined(
6756  "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6757  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6758 
6759  // Enable ACCESS_HAS
6760  allowed_access_type[v8::ACCESS_HAS] = true;
6761  ExpectUndefined("other.blocked_prop");
6762  // ... and now we can get the descriptor...
6763  ExpectUndefined(
6764  "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6765  // ... and enumerate the property.
6766  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6767  allowed_access_type[v8::ACCESS_HAS] = false;
6768 
6769  // Access blocked element.
6770  CompileRun("other[239] = 1");
6771 
6772  ExpectUndefined("other[239]");
6773  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6774  ExpectFalse("propertyIsEnumerable.call(other, '239')");
6775 
6776  // Enable ACCESS_HAS
6777  allowed_access_type[v8::ACCESS_HAS] = true;
6778  ExpectUndefined("other[239]");
6779  // ... and now we can get the descriptor...
6780  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6781  // ... and enumerate the property.
6782  ExpectTrue("propertyIsEnumerable.call(other, '239')");
6783  allowed_access_type[v8::ACCESS_HAS] = false;
6784 
6785  // Access a property with JS accessor.
6786  CompileRun("other.js_accessor_p = 2");
6787 
6788  ExpectUndefined("other.js_accessor_p");
6789  ExpectUndefined(
6790  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6791 
6792  // Enable ACCESS_HAS.
6793  allowed_access_type[v8::ACCESS_HAS] = true;
6794  ExpectUndefined("other.js_accessor_p");
6795  ExpectUndefined(
6796  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6797  ExpectUndefined(
6798  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6799  ExpectUndefined(
6800  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6801  allowed_access_type[v8::ACCESS_HAS] = false;
6802 
6803  // Enable both ACCESS_HAS and ACCESS_GET.
6804  allowed_access_type[v8::ACCESS_HAS] = true;
6805  allowed_access_type[v8::ACCESS_GET] = true;
6806 
6807  ExpectString("other.js_accessor_p", "getter");
6808  ExpectObject(
6809  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6810  ExpectUndefined(
6811  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6812  ExpectUndefined(
6813  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6814 
6815  allowed_access_type[v8::ACCESS_GET] = false;
6816  allowed_access_type[v8::ACCESS_HAS] = false;
6817 
6818  // Enable both ACCESS_HAS and ACCESS_SET.
6819  allowed_access_type[v8::ACCESS_HAS] = true;
6820  allowed_access_type[v8::ACCESS_SET] = true;
6821 
6822  ExpectUndefined("other.js_accessor_p");
6823  ExpectUndefined(
6824  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6825  ExpectObject(
6826  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6827  ExpectUndefined(
6828  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6829 
6830  allowed_access_type[v8::ACCESS_SET] = false;
6831  allowed_access_type[v8::ACCESS_HAS] = false;
6832 
6833  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6834  allowed_access_type[v8::ACCESS_HAS] = true;
6835  allowed_access_type[v8::ACCESS_GET] = true;
6836  allowed_access_type[v8::ACCESS_SET] = true;
6837 
6838  ExpectString("other.js_accessor_p", "getter");
6839  ExpectObject(
6840  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6841  ExpectObject(
6842  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6843  ExpectUndefined(
6844  "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6845 
6846  allowed_access_type[v8::ACCESS_SET] = false;
6847  allowed_access_type[v8::ACCESS_GET] = false;
6848  allowed_access_type[v8::ACCESS_HAS] = false;
6849 
6850  // Access an element with JS accessor.
6851  CompileRun("other[42] = 2");
6852 
6853  ExpectUndefined("other[42]");
6854  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6855 
6856  // Enable ACCESS_HAS.
6857  allowed_access_type[v8::ACCESS_HAS] = true;
6858  ExpectUndefined("other[42]");
6859  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6860  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6861  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6862  allowed_access_type[v8::ACCESS_HAS] = false;
6863 
6864  // Enable both ACCESS_HAS and ACCESS_GET.
6865  allowed_access_type[v8::ACCESS_HAS] = true;
6866  allowed_access_type[v8::ACCESS_GET] = true;
6867 
6868  ExpectString("other[42]", "el_getter");
6869  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6870  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6871  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6872 
6873  allowed_access_type[v8::ACCESS_GET] = false;
6874  allowed_access_type[v8::ACCESS_HAS] = false;
6875 
6876  // Enable both ACCESS_HAS and ACCESS_SET.
6877  allowed_access_type[v8::ACCESS_HAS] = true;
6878  allowed_access_type[v8::ACCESS_SET] = true;
6879 
6880  ExpectUndefined("other[42]");
6881  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6882  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6883  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6884 
6885  allowed_access_type[v8::ACCESS_SET] = false;
6886  allowed_access_type[v8::ACCESS_HAS] = false;
6887 
6888  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6889  allowed_access_type[v8::ACCESS_HAS] = true;
6890  allowed_access_type[v8::ACCESS_GET] = true;
6891  allowed_access_type[v8::ACCESS_SET] = true;
6892 
6893  ExpectString("other[42]", "el_getter");
6894  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6895  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6896  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6897 
6898  allowed_access_type[v8::ACCESS_SET] = false;
6899  allowed_access_type[v8::ACCESS_GET] = false;
6900  allowed_access_type[v8::ACCESS_HAS] = false;
6901 
6902  v8::Handle<Value> value;
6903 
6904  // Access accessible property
6905  value = CompileRun("other.accessible_prop = 3");
6906  CHECK(value->IsNumber());
6907  CHECK_EQ(3, value->Int32Value());
6908  CHECK_EQ(3, g_echo_value);
6909 
6910  value = CompileRun("other.accessible_prop");
6911  CHECK(value->IsNumber());
6912  CHECK_EQ(3, value->Int32Value());
6913 
6914  value = CompileRun(
6915  "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6916  CHECK(value->IsNumber());
6917  CHECK_EQ(3, value->Int32Value());
6918 
6919  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
6920  CHECK(value->IsTrue());
6921 
6922  // Enumeration doesn't enumerate accessors from inaccessible objects in
6923  // the prototype chain even if the accessors are in themselves accessible.
6924  value =
6925  CompileRun("(function(){var obj = {'__proto__':other};"
6926  "for (var p in obj)"
6927  " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6928  " return false;"
6929  " }"
6930  "return true;})()");
6931  CHECK(value->IsTrue());
6932 
6933  context1->Exit();
6934  context0->Exit();
6935  context1.Dispose();
6936  context0.Dispose();
6937 }
6938 
6939 
6940 TEST(AccessControlES5) {
6941  v8::HandleScope handle_scope;
6943 
6944  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6945  IndexedAccessBlocker);
6946 
6947  // Add accessible accessor.
6948  global_template->SetAccessor(
6949  v8_str("accessible_prop"),
6950  EchoGetter, EchoSetter,
6953 
6954 
6955  // Add an accessor that is not accessible by cross-domain JS code.
6956  global_template->SetAccessor(v8_str("blocked_prop"),
6957  UnreachableGetter, UnreachableSetter,
6959  v8::DEFAULT);
6960 
6961  // Create an environment
6962  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6963  context0->Enter();
6964 
6965  v8::Handle<v8::Object> global0 = context0->Global();
6966 
6967  v8::Persistent<Context> context1 = Context::New();
6968  context1->Enter();
6969  v8::Handle<v8::Object> global1 = context1->Global();
6970  global1->Set(v8_str("other"), global0);
6971 
6972  // Regression test for issue 1154.
6973  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6974 
6975  ExpectUndefined("other.blocked_prop");
6976 
6977  // Regression test for issue 1027.
6978  CompileRun("Object.defineProperty(\n"
6979  " other, 'blocked_prop', {configurable: false})");
6980  ExpectUndefined("other.blocked_prop");
6981  ExpectUndefined(
6982  "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6983 
6984  // Regression test for issue 1171.
6985  ExpectTrue("Object.isExtensible(other)");
6986  CompileRun("Object.preventExtensions(other)");
6987  ExpectTrue("Object.isExtensible(other)");
6988 
6989  // Object.seal and Object.freeze.
6990  CompileRun("Object.freeze(other)");
6991  ExpectTrue("Object.isExtensible(other)");
6992 
6993  CompileRun("Object.seal(other)");
6994  ExpectTrue("Object.isExtensible(other)");
6995 
6996  // Regression test for issue 1250.
6997  // Make sure that we can set the accessible accessors value using normal
6998  // assignment.
6999  CompileRun("other.accessible_prop = 42");
7000  CHECK_EQ(42, g_echo_value);
7001 
7002  v8::Handle<Value> value;
7003  // We follow Safari in ignoring assignments to host object accessors.
7004  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7005  value = CompileRun("other.accessible_prop == 42");
7006  CHECK(value->IsTrue());
7007 }
7008 
7009 
7010 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7011  Local<Value> name,
7012  v8::AccessType type,
7013  Local<Value> data) {
7014  return false;
7015 }
7016 
7017 
7018 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7019  uint32_t key,
7020  v8::AccessType type,
7021  Local<Value> data) {
7022  return false;
7023 }
7024 
7025 
7026 THREADED_TEST(AccessControlGetOwnPropertyNames) {
7027  v8::HandleScope handle_scope;
7029 
7030  obj_template->Set(v8_str("x"), v8::Integer::New(42));
7031  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7032  GetOwnPropertyNamesIndexedBlocker);
7033 
7034  // Create an environment
7035  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7036  context0->Enter();
7037 
7038  v8::Handle<v8::Object> global0 = context0->Global();
7039 
7040  v8::HandleScope scope1;
7041 
7042  v8::Persistent<Context> context1 = Context::New();
7043  context1->Enter();
7044 
7045  v8::Handle<v8::Object> global1 = context1->Global();
7046  global1->Set(v8_str("other"), global0);
7047  global1->Set(v8_str("object"), obj_template->NewInstance());
7048 
7049  v8::Handle<Value> value;
7050 
7051  // Attempt to get the property names of the other global object and
7052  // of an object that requires access checks. Accessing the other
7053  // global object should be blocked by access checks on the global
7054  // proxy object. Accessing the object that requires access checks
7055  // is blocked by the access checks on the object itself.
7056  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7057  CHECK(value->IsTrue());
7058 
7059  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7060  CHECK(value->IsTrue());
7061 
7062  context1->Exit();
7063  context0->Exit();
7064  context1.Dispose();
7065  context0.Dispose();
7066 }
7067 
7068 
7069 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7071  result->Set(0, v8_str("x"));
7072  return result;
7073 }
7074 
7075 
7076 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7077  v8::HandleScope handle_scope;
7079 
7080  obj_template->Set(v8_str("x"), v8::Integer::New(42));
7081  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7082  NamedPropertyEnumerator);
7083 
7084  LocalContext context;
7085  v8::Handle<v8::Object> global = context->Global();
7086  global->Set(v8_str("object"), obj_template->NewInstance());
7087 
7088  v8::Handle<Value> value =
7089  CompileRun("Object.getOwnPropertyNames(object).join(',')");
7090  CHECK_EQ(v8_str("x"), value);
7091 }
7092 
7093 
7094 static v8::Handle<Value> ConstTenGetter(Local<String> name,
7095  const AccessorInfo& info) {
7096  return v8_num(10);
7097 }
7098 
7099 
7100 THREADED_TEST(CrossDomainAccessors) {
7101  v8::HandleScope handle_scope;
7102 
7104 
7105  v8::Handle<v8::ObjectTemplate> global_template =
7106  func_template->InstanceTemplate();
7107 
7108  v8::Handle<v8::ObjectTemplate> proto_template =
7109  func_template->PrototypeTemplate();
7110 
7111  // Add an accessor to proto that's accessible by cross-domain JS code.
7112  proto_template->SetAccessor(v8_str("accessible"),
7113  ConstTenGetter, 0,
7116 
7117  // Add an accessor that is not accessible by cross-domain JS code.
7118  global_template->SetAccessor(v8_str("unreachable"),
7119  UnreachableGetter, 0,
7121  v8::DEFAULT);
7122 
7123  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7124  context0->Enter();
7125 
7126  Local<v8::Object> global = context0->Global();
7127  // Add a normal property that shadows 'accessible'
7128  global->Set(v8_str("accessible"), v8_num(11));
7129 
7130  // Enter a new context.
7131  v8::HandleScope scope1;
7132  v8::Persistent<Context> context1 = Context::New();
7133  context1->Enter();
7134 
7135  v8::Handle<v8::Object> global1 = context1->Global();
7136  global1->Set(v8_str("other"), global);
7137 
7138  // Should return 10, instead of 11
7139  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7140  CHECK(value->IsNumber());
7141  CHECK_EQ(10, value->Int32Value());
7142 
7143  value = v8_compile("other.unreachable")->Run();
7144  CHECK(value->IsUndefined());
7145 
7146  context1->Exit();
7147  context0->Exit();
7148  context1.Dispose();
7149  context0.Dispose();
7150 }
7151 
7152 
7153 static int named_access_count = 0;
7154 static int indexed_access_count = 0;
7155 
7156 static bool NamedAccessCounter(Local<v8::Object> global,
7157  Local<Value> name,
7158  v8::AccessType type,
7159  Local<Value> data) {
7160  named_access_count++;
7161  return true;
7162 }
7163 
7164 
7165 static bool IndexedAccessCounter(Local<v8::Object> global,
7166  uint32_t key,
7167  v8::AccessType type,
7168  Local<Value> data) {
7169  indexed_access_count++;
7170  return true;
7171 }
7172 
7173 
7174 // This one is too easily disturbed by other tests.
7175 TEST(AccessControlIC) {
7176  named_access_count = 0;
7177  indexed_access_count = 0;
7178 
7179  v8::HandleScope handle_scope;
7180 
7181  // Create an environment.
7182  v8::Persistent<Context> context0 = Context::New();
7183  context0->Enter();
7184 
7185  // Create an object that requires access-check functions to be
7186  // called for cross-domain access.
7188  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7189  IndexedAccessCounter);
7190  Local<v8::Object> object = object_template->NewInstance();
7191 
7192  v8::HandleScope scope1;
7193 
7194  // Create another environment.
7195  v8::Persistent<Context> context1 = Context::New();
7196  context1->Enter();
7197 
7198  // Make easy access to the object from the other environment.
7199  v8::Handle<v8::Object> global1 = context1->Global();
7200  global1->Set(v8_str("obj"), object);
7201 
7202  v8::Handle<Value> value;
7203 
7204  // Check that the named access-control function is called every time.
7205  CompileRun("function testProp(obj) {"
7206  " for (var i = 0; i < 10; i++) obj.prop = 1;"
7207  " for (var j = 0; j < 10; j++) obj.prop;"
7208  " return obj.prop"
7209  "}");
7210  value = CompileRun("testProp(obj)");
7211  CHECK(value->IsNumber());
7212  CHECK_EQ(1, value->Int32Value());
7213  CHECK_EQ(21, named_access_count);
7214 
7215  // Check that the named access-control function is called every time.
7216  CompileRun("var p = 'prop';"
7217  "function testKeyed(obj) {"
7218  " for (var i = 0; i < 10; i++) obj[p] = 1;"
7219  " for (var j = 0; j < 10; j++) obj[p];"
7220  " return obj[p];"
7221  "}");
7222  // Use obj which requires access checks. No inline caching is used
7223  // in that case.
7224  value = CompileRun("testKeyed(obj)");
7225  CHECK(value->IsNumber());
7226  CHECK_EQ(1, value->Int32Value());
7227  CHECK_EQ(42, named_access_count);
7228  // Force the inline caches into generic state and try again.
7229  CompileRun("testKeyed({ a: 0 })");
7230  CompileRun("testKeyed({ b: 0 })");
7231  value = CompileRun("testKeyed(obj)");
7232  CHECK(value->IsNumber());
7233  CHECK_EQ(1, value->Int32Value());
7234  CHECK_EQ(63, named_access_count);
7235 
7236  // Check that the indexed access-control function is called every time.
7237  CompileRun("function testIndexed(obj) {"
7238  " for (var i = 0; i < 10; i++) obj[0] = 1;"
7239  " for (var j = 0; j < 10; j++) obj[0];"
7240  " return obj[0]"
7241  "}");
7242  value = CompileRun("testIndexed(obj)");
7243  CHECK(value->IsNumber());
7244  CHECK_EQ(1, value->Int32Value());
7245  CHECK_EQ(21, indexed_access_count);
7246  // Force the inline caches into generic state.
7247  CompileRun("testIndexed(new Array(1))");
7248  // Test that the indexed access check is called.
7249  value = CompileRun("testIndexed(obj)");
7250  CHECK(value->IsNumber());
7251  CHECK_EQ(1, value->Int32Value());
7252  CHECK_EQ(42, indexed_access_count);
7253 
7254  // Check that the named access check is called when invoking
7255  // functions on an object that requires access checks.
7256  CompileRun("obj.f = function() {}");
7257  CompileRun("function testCallNormal(obj) {"
7258  " for (var i = 0; i < 10; i++) obj.f();"
7259  "}");
7260  CompileRun("testCallNormal(obj)");
7261  CHECK_EQ(74, named_access_count);
7262 
7263  // Force obj into slow case.
7264  value = CompileRun("delete obj.prop");
7265  CHECK(value->BooleanValue());
7266  // Force inline caches into dictionary probing mode.
7267  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7268  // Test that the named access check is called.
7269  value = CompileRun("testProp(obj);");
7270  CHECK(value->IsNumber());
7271  CHECK_EQ(1, value->Int32Value());
7272  CHECK_EQ(96, named_access_count);
7273 
7274  // Force the call inline cache into dictionary probing mode.
7275  CompileRun("o.f = function() {}; testCallNormal(o)");
7276  // Test that the named access check is still called for each
7277  // invocation of the function.
7278  value = CompileRun("testCallNormal(obj)");
7279  CHECK_EQ(106, named_access_count);
7280 
7281  context1->Exit();
7282  context0->Exit();
7283  context1.Dispose();
7284  context0.Dispose();
7285 }
7286 
7287 
7288 static bool NamedAccessFlatten(Local<v8::Object> global,
7289  Local<Value> name,
7290  v8::AccessType type,
7291  Local<Value> data) {
7292  char buf[100];
7293  int len;
7294 
7295  CHECK(name->IsString());
7296 
7297  memset(buf, 0x1, sizeof(buf));
7298  len = name.As<String>()->WriteAscii(buf);
7299  CHECK_EQ(4, len);
7300 
7301  uint16_t buf2[100];
7302 
7303  memset(buf, 0x1, sizeof(buf));
7304  len = name.As<String>()->Write(buf2);
7305  CHECK_EQ(4, len);
7306 
7307  return true;
7308 }
7309 
7310 
7311 static bool IndexedAccessFlatten(Local<v8::Object> global,
7312  uint32_t key,
7313  v8::AccessType type,
7314  Local<Value> data) {
7315  return true;
7316 }
7317 
7318 
7319 // Regression test. In access checks, operations that may cause
7320 // garbage collection are not allowed. It used to be the case that
7321 // using the Write operation on a string could cause a garbage
7322 // collection due to flattening of the string. This is no longer the
7323 // case.
7324 THREADED_TEST(AccessControlFlatten) {
7325  named_access_count = 0;
7326  indexed_access_count = 0;
7327 
7328  v8::HandleScope handle_scope;
7329 
7330  // Create an environment.
7331  v8::Persistent<Context> context0 = Context::New();
7332  context0->Enter();
7333 
7334  // Create an object that requires access-check functions to be
7335  // called for cross-domain access.
7337  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7338  IndexedAccessFlatten);
7339  Local<v8::Object> object = object_template->NewInstance();
7340 
7341  v8::HandleScope scope1;
7342 
7343  // Create another environment.
7344  v8::Persistent<Context> context1 = Context::New();
7345  context1->Enter();
7346 
7347  // Make easy access to the object from the other environment.
7348  v8::Handle<v8::Object> global1 = context1->Global();
7349  global1->Set(v8_str("obj"), object);
7350 
7351  v8::Handle<Value> value;
7352 
7353  value = v8_compile("var p = 'as' + 'df';")->Run();
7354  value = v8_compile("obj[p];")->Run();
7355 
7356  context1->Exit();
7357  context0->Exit();
7358  context1.Dispose();
7359  context0.Dispose();
7360 }
7361 
7362 
7363 static v8::Handle<Value> AccessControlNamedGetter(
7364  Local<String>, const AccessorInfo&) {
7365  return v8::Integer::New(42);
7366 }
7367 
7368 
7369 static v8::Handle<Value> AccessControlNamedSetter(
7370  Local<String>, Local<Value> value, const AccessorInfo&) {
7371  return value;
7372 }
7373 
7374 
7375 static v8::Handle<Value> AccessControlIndexedGetter(
7376  uint32_t index,
7377  const AccessorInfo& info) {
7378  return v8_num(42);
7379 }
7380 
7381 
7382 static v8::Handle<Value> AccessControlIndexedSetter(
7383  uint32_t, Local<Value> value, const AccessorInfo&) {
7384  return value;
7385 }
7386 
7387 
7388 THREADED_TEST(AccessControlInterceptorIC) {
7389  named_access_count = 0;
7390  indexed_access_count = 0;
7391 
7392  v8::HandleScope handle_scope;
7393 
7394  // Create an environment.
7395  v8::Persistent<Context> context0 = Context::New();
7396  context0->Enter();
7397 
7398  // Create an object that requires access-check functions to be
7399  // called for cross-domain access. The object also has interceptors
7400  // interceptor.
7402  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7403  IndexedAccessCounter);
7404  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7405  AccessControlNamedSetter);
7406  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7407  AccessControlIndexedSetter);
7408  Local<v8::Object> object = object_template->NewInstance();
7409 
7410  v8::HandleScope scope1;
7411 
7412  // Create another environment.
7413  v8::Persistent<Context> context1 = Context::New();
7414  context1->Enter();
7415 
7416  // Make easy access to the object from the other environment.
7417  v8::Handle<v8::Object> global1 = context1->Global();
7418  global1->Set(v8_str("obj"), object);
7419 
7420  v8::Handle<Value> value;
7421 
7422  // Check that the named access-control function is called every time
7423  // eventhough there is an interceptor on the object.
7424  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7425  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7426  "obj.x")->Run();
7427  CHECK(value->IsNumber());
7428  CHECK_EQ(42, value->Int32Value());
7429  CHECK_EQ(21, named_access_count);
7430 
7431  value = v8_compile("var p = 'x';")->Run();
7432  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7433  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7434  "obj[p]")->Run();
7435  CHECK(value->IsNumber());
7436  CHECK_EQ(42, value->Int32Value());
7437  CHECK_EQ(42, named_access_count);
7438 
7439  // Check that the indexed access-control function is called every
7440  // time eventhough there is an interceptor on the object.
7441  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7442  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7443  "obj[0]")->Run();
7444  CHECK(value->IsNumber());
7445  CHECK_EQ(42, value->Int32Value());
7446  CHECK_EQ(21, indexed_access_count);
7447 
7448  context1->Exit();
7449  context0->Exit();
7450  context1.Dispose();
7451  context0.Dispose();
7452 }
7453 
7454 
7457 }
7458 
7459 
7460 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7462  return v8_num(12);
7463 }
7464 
7465 
7466 THREADED_TEST(InstanceProperties) {
7467  v8::HandleScope handle_scope;
7468  LocalContext context;
7469 
7470  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7471  Local<ObjectTemplate> instance = t->InstanceTemplate();
7472 
7473  instance->Set(v8_str("x"), v8_num(42));
7474  instance->Set(v8_str("f"),
7475  v8::FunctionTemplate::New(InstanceFunctionCallback));
7476 
7477  Local<Value> o = t->GetFunction()->NewInstance();
7478 
7479  context->Global()->Set(v8_str("i"), o);
7480  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7481  CHECK_EQ(42, value->Int32Value());
7482 
7483  value = Script::Compile(v8_str("i.f()"))->Run();
7484  CHECK_EQ(12, value->Int32Value());
7485 }
7486 
7487 
7488 static v8::Handle<Value>
7489 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7491  return v8::Handle<Value>();
7492 }
7493 
7494 
7495 THREADED_TEST(GlobalObjectInstanceProperties) {
7496  v8::HandleScope handle_scope;
7497 
7498  Local<Value> global_object;
7499 
7500  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7501  t->InstanceTemplate()->SetNamedPropertyHandler(
7502  GlobalObjectInstancePropertiesGet);
7503  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7504  instance_template->Set(v8_str("x"), v8_num(42));
7505  instance_template->Set(v8_str("f"),
7506  v8::FunctionTemplate::New(InstanceFunctionCallback));
7507 
7508  // The script to check how Crankshaft compiles missing global function
7509  // invocations. function g is not defined and should throw on call.
7510  const char* script =
7511  "function wrapper(call) {"
7512  " var x = 0, y = 1;"
7513  " for (var i = 0; i < 1000; i++) {"
7514  " x += i * 100;"
7515  " y += i * 100;"
7516  " }"
7517  " if (call) g();"
7518  "}"
7519  "for (var i = 0; i < 17; i++) wrapper(false);"
7520  "var thrown = 0;"
7521  "try { wrapper(true); } catch (e) { thrown = 1; };"
7522  "thrown";
7523 
7524  {
7525  LocalContext env(NULL, instance_template);
7526  // Hold on to the global object so it can be used again in another
7527  // environment initialization.
7528  global_object = env->Global();
7529 
7530  Local<Value> value = Script::Compile(v8_str("x"))->Run();
7531  CHECK_EQ(42, value->Int32Value());
7532  value = Script::Compile(v8_str("f()"))->Run();
7533  CHECK_EQ(12, value->Int32Value());
7534  value = Script::Compile(v8_str(script))->Run();
7535  CHECK_EQ(1, value->Int32Value());
7536  }
7537 
7538  {
7539  // Create new environment reusing the global object.
7540  LocalContext env(NULL, instance_template, global_object);
7541  Local<Value> value = Script::Compile(v8_str("x"))->Run();
7542  CHECK_EQ(42, value->Int32Value());
7543  value = Script::Compile(v8_str("f()"))->Run();
7544  CHECK_EQ(12, value->Int32Value());
7545  value = Script::Compile(v8_str(script))->Run();
7546  CHECK_EQ(1, value->Int32Value());
7547  }
7548 }
7549 
7550 
7551 THREADED_TEST(CallKnownGlobalReceiver) {
7552  v8::HandleScope handle_scope;
7553 
7554  Local<Value> global_object;
7555 
7556  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7557  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7558 
7559  // The script to check that we leave global object not
7560  // global object proxy on stack when we deoptimize from inside
7561  // arguments evaluation.
7562  // To provoke error we need to both force deoptimization
7563  // from arguments evaluation and to force CallIC to take
7564  // CallIC_Miss code path that can't cope with global proxy.
7565  const char* script =
7566  "function bar(x, y) { try { } finally { } }"
7567  "function baz(x) { try { } finally { } }"
7568  "function bom(x) { try { } finally { } }"
7569  "function foo(x) { bar([x], bom(2)); }"
7570  "for (var i = 0; i < 10000; i++) foo(1);"
7571  "foo";
7572 
7573  Local<Value> foo;
7574  {
7575  LocalContext env(NULL, instance_template);
7576  // Hold on to the global object so it can be used again in another
7577  // environment initialization.
7578  global_object = env->Global();
7579  foo = Script::Compile(v8_str(script))->Run();
7580  }
7581 
7582  {
7583  // Create new environment reusing the global object.
7584  LocalContext env(NULL, instance_template, global_object);
7585  env->Global()->Set(v8_str("foo"), foo);
7586  Script::Compile(v8_str("foo()"))->Run();
7587  }
7588 }
7589 
7590 
7591 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7593  return v8_num(42);
7594 }
7595 
7596 
7597 static int shadow_y;
7598 static int shadow_y_setter_call_count;
7599 static int shadow_y_getter_call_count;
7600 
7601 
7602 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7603  shadow_y_setter_call_count++;
7604  shadow_y = 42;
7605 }
7606 
7607 
7608 static v8::Handle<Value> ShadowYGetter(Local<String> name,
7609  const AccessorInfo& info) {
7611  shadow_y_getter_call_count++;
7612  return v8_num(shadow_y);
7613 }
7614 
7615 
7616 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7617  const AccessorInfo& info) {
7618  return v8::Handle<Value>();
7619 }
7620 
7621 
7622 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7623  const AccessorInfo&) {
7624  return v8::Handle<Value>();
7625 }
7626 
7627 
7628 THREADED_TEST(ShadowObject) {
7629  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7630  v8::HandleScope handle_scope;
7631 
7632  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7633  LocalContext context(NULL, global_template);
7634 
7635  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7636  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7637  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7638  Local<ObjectTemplate> proto = t->PrototypeTemplate();
7639  Local<ObjectTemplate> instance = t->InstanceTemplate();
7640 
7641  // Only allow calls of f on instances of t.
7642  Local<v8::Signature> signature = v8::Signature::New(t);
7643  proto->Set(v8_str("f"),
7644  v8::FunctionTemplate::New(ShadowFunctionCallback,
7645  Local<Value>(),
7646  signature));
7647  proto->Set(v8_str("x"), v8_num(12));
7648 
7649  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7650 
7651  Local<Value> o = t->GetFunction()->NewInstance();
7652  context->Global()->Set(v8_str("__proto__"), o);
7653 
7654  Local<Value> value =
7655  Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7656  CHECK(value->IsBoolean());
7657  CHECK(!value->BooleanValue());
7658 
7659  value = Script::Compile(v8_str("x"))->Run();
7660  CHECK_EQ(12, value->Int32Value());
7661 
7662  value = Script::Compile(v8_str("f()"))->Run();
7663  CHECK_EQ(42, value->Int32Value());
7664 
7665  Script::Compile(v8_str("y = 43"))->Run();
7666  CHECK_EQ(1, shadow_y_setter_call_count);
7667  value = Script::Compile(v8_str("y"))->Run();
7668  CHECK_EQ(1, shadow_y_getter_call_count);
7669  CHECK_EQ(42, value->Int32Value());
7670 }
7671 
7672 
7673 THREADED_TEST(HiddenPrototype) {
7674  v8::HandleScope handle_scope;
7675  LocalContext context;
7676 
7677  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7678  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7679  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7680  t1->SetHiddenPrototype(true);
7681  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7682  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7683  t2->SetHiddenPrototype(true);
7684  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7685  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7686  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7687 
7688  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7689  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7690  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7691  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7692 
7693  // Setting the prototype on an object skips hidden prototypes.
7694  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7695  o0->Set(v8_str("__proto__"), o1);
7696  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7697  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7698  o0->Set(v8_str("__proto__"), o2);
7699  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7700  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7701  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7702  o0->Set(v8_str("__proto__"), o3);
7703  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7704  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7705  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7706  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7707 
7708  // Getting the prototype of o0 should get the first visible one
7709  // which is o3. Therefore, z should not be defined on the prototype
7710  // object.
7711  Local<Value> proto = o0->Get(v8_str("__proto__"));
7712  CHECK(proto->IsObject());
7713  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7714 }
7715 
7716 
7718  v8::HandleScope handle_scope;
7719  LocalContext context;
7720 
7721  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7722  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7723  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7724  t1->SetHiddenPrototype(true);
7725  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7726  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7727  t2->SetHiddenPrototype(true);
7728  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7729  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7730  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7731 
7732  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7733  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7734  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7735  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7736 
7737  // Setting the prototype on an object does not skip hidden prototypes.
7738  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7739  CHECK(o0->SetPrototype(o1));
7740  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7741  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7742  CHECK(o1->SetPrototype(o2));
7743  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7744  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7745  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7746  CHECK(o2->SetPrototype(o3));
7747  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7748  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7749  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7750  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7751 
7752  // Getting the prototype of o0 should get the first visible one
7753  // which is o3. Therefore, z should not be defined on the prototype
7754  // object.
7755  Local<Value> proto = o0->Get(v8_str("__proto__"));
7756  CHECK(proto->IsObject());
7757  CHECK_EQ(proto.As<v8::Object>(), o3);
7758 
7759  // However, Object::GetPrototype ignores hidden prototype.
7760  Local<Value> proto0 = o0->GetPrototype();
7761  CHECK(proto0->IsObject());
7762  CHECK_EQ(proto0.As<v8::Object>(), o1);
7763 
7764  Local<Value> proto1 = o1->GetPrototype();
7765  CHECK(proto1->IsObject());
7766  CHECK_EQ(proto1.As<v8::Object>(), o2);
7767 
7768  Local<Value> proto2 = o2->GetPrototype();
7769  CHECK(proto2->IsObject());
7770  CHECK_EQ(proto2.As<v8::Object>(), o3);
7771 }
7772 
7773 
7774 // Getting property names of an object with a prototype chain that
7775 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
7776 // crash the runtime.
7777 THREADED_TEST(Regress91517) {
7778  i::FLAG_allow_natives_syntax = true;
7779  v8::HandleScope handle_scope;
7780  LocalContext context;
7781 
7782  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7783  t1->SetHiddenPrototype(true);
7784  t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7785  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7786  t2->SetHiddenPrototype(true);
7787  t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7788  t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7789  t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7790  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7791  t3->SetHiddenPrototype(true);
7792  t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7793  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7794  t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7795 
7796  // Force dictionary-based properties.
7797  i::ScopedVector<char> name_buf(1024);
7798  for (int i = 1; i <= 1000; i++) {
7799  i::OS::SNPrintF(name_buf, "sdf%d", i);
7800  t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7801  }
7802 
7803  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7804  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7805  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7806  Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7807 
7808  // Create prototype chain of hidden prototypes.
7809  CHECK(o4->SetPrototype(o3));
7810  CHECK(o3->SetPrototype(o2));
7811  CHECK(o2->SetPrototype(o1));
7812 
7813  // Call the runtime version of GetLocalPropertyNames() on the natively
7814  // created object through JavaScript.
7815  context->Global()->Set(v8_str("obj"), o4);
7816  CompileRun("var names = %GetLocalPropertyNames(obj);");
7817 
7818  ExpectInt32("names.length", 1006);
7819  ExpectTrue("names.indexOf(\"baz\") >= 0");
7820  ExpectTrue("names.indexOf(\"boo\") >= 0");
7821  ExpectTrue("names.indexOf(\"foo\") >= 0");
7822  ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7823  ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7824  ExpectFalse("names[1005] == undefined");
7825 }
7826 
7827 
7828 THREADED_TEST(FunctionReadOnlyPrototype) {
7829  v8::HandleScope handle_scope;
7830  LocalContext context;
7831 
7832  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7833  t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7834  t1->ReadOnlyPrototype();
7835  context->Global()->Set(v8_str("func1"), t1->GetFunction());
7836  // Configured value of ReadOnly flag.
7837  CHECK(CompileRun(
7838  "(function() {"
7839  " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7840  " return (descriptor['writable'] == false);"
7841  "})()")->BooleanValue());
7842  CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7843  CHECK_EQ(42,
7844  CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
7845 
7846  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7847  t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7848  context->Global()->Set(v8_str("func2"), t2->GetFunction());
7849  // Default value of ReadOnly flag.
7850  CHECK(CompileRun(
7851  "(function() {"
7852  " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7853  " return (descriptor['writable'] == true);"
7854  "})()")->BooleanValue());
7855  CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
7856 }
7857 
7858 
7859 THREADED_TEST(SetPrototypeThrows) {
7860  v8::HandleScope handle_scope;
7861  LocalContext context;
7862 
7863  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7864 
7865  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7866  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7867 
7868  CHECK(o0->SetPrototype(o1));
7869  // If setting the prototype leads to the cycle, SetPrototype should
7870  // return false and keep VM in sane state.
7871  v8::TryCatch try_catch;
7872  CHECK(!o1->SetPrototype(o0));
7873  CHECK(!try_catch.HasCaught());
7874  ASSERT(!i::Isolate::Current()->has_pending_exception());
7875 
7876  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7877 }
7878 
7879 
7880 THREADED_TEST(GetterSetterExceptions) {
7881  v8::HandleScope handle_scope;
7882  LocalContext context;
7883  CompileRun(
7884  "function Foo() { };"
7885  "function Throw() { throw 5; };"
7886  "var x = { };"
7887  "x.__defineSetter__('set', Throw);"
7888  "x.__defineGetter__('get', Throw);");
7889  Local<v8::Object> x =
7890  Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7891  v8::TryCatch try_catch;
7892  x->Set(v8_str("set"), v8::Integer::New(8));
7893  x->Get(v8_str("get"));
7894  x->Set(v8_str("set"), v8::Integer::New(8));
7895  x->Get(v8_str("get"));
7896  x->Set(v8_str("set"), v8::Integer::New(8));
7897  x->Get(v8_str("get"));
7898  x->Set(v8_str("set"), v8::Integer::New(8));
7899  x->Get(v8_str("get"));
7900 }
7901 
7902 
7903 THREADED_TEST(Constructor) {
7904  v8::HandleScope handle_scope;
7905  LocalContext context;
7906  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7907  templ->SetClassName(v8_str("Fun"));
7908  Local<Function> cons = templ->GetFunction();
7909  context->Global()->Set(v8_str("Fun"), cons);
7910  Local<v8::Object> inst = cons->NewInstance();
7912  CHECK(obj->IsJSObject());
7913  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7914  CHECK(value->BooleanValue());
7915 }
7916 
7917 
7918 static Handle<Value> ConstructorCallback(const Arguments& args) {
7920  Local<Object> This;
7921 
7922  if (args.IsConstructCall()) {
7923  Local<Object> Holder = args.Holder();
7924  This = Object::New();
7925  Local<Value> proto = Holder->GetPrototype();
7926  if (proto->IsObject()) {
7927  This->SetPrototype(proto);
7928  }
7929  } else {
7930  This = args.This();
7931  }
7932 
7933  This->Set(v8_str("a"), args[0]);
7934  return This;
7935 }
7936 
7937 
7938 static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7940  return args[0];
7941 }
7942 
7943 
7944 THREADED_TEST(ConstructorForObject) {
7945  v8::HandleScope handle_scope;
7946  LocalContext context;
7947 
7948  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7949  instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7950  Local<Object> instance = instance_template->NewInstance();
7951  context->Global()->Set(v8_str("obj"), instance);
7952  v8::TryCatch try_catch;
7953  Local<Value> value;
7954  CHECK(!try_catch.HasCaught());
7955 
7956  // Call the Object's constructor with a 32-bit signed integer.
7957  value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7958  CHECK(!try_catch.HasCaught());
7959  CHECK(value->IsInt32());
7960  CHECK_EQ(28, value->Int32Value());
7961 
7962  Local<Value> args1[] = { v8_num(28) };
7963  Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7964  CHECK(value_obj1->IsObject());
7965  Local<Object> object1 = Local<Object>::Cast(value_obj1);
7966  value = object1->Get(v8_str("a"));
7967  CHECK(value->IsInt32());
7968  CHECK(!try_catch.HasCaught());
7969  CHECK_EQ(28, value->Int32Value());
7970 
7971  // Call the Object's constructor with a String.
7972  value = CompileRun(
7973  "(function() { var o = new obj('tipli'); return o.a; })()");
7974  CHECK(!try_catch.HasCaught());
7975  CHECK(value->IsString());
7976  String::AsciiValue string_value1(value->ToString());
7977  CHECK_EQ("tipli", *string_value1);
7978 
7979  Local<Value> args2[] = { v8_str("tipli") };
7980  Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7981  CHECK(value_obj2->IsObject());
7982  Local<Object> object2 = Local<Object>::Cast(value_obj2);
7983  value = object2->Get(v8_str("a"));
7984  CHECK(!try_catch.HasCaught());
7985  CHECK(value->IsString());
7986  String::AsciiValue string_value2(value->ToString());
7987  CHECK_EQ("tipli", *string_value2);
7988 
7989  // Call the Object's constructor with a Boolean.
7990  value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7991  CHECK(!try_catch.HasCaught());
7992  CHECK(value->IsBoolean());
7993  CHECK_EQ(true, value->BooleanValue());
7994 
7995  Handle<Value> args3[] = { v8::True() };
7996  Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7997  CHECK(value_obj3->IsObject());
7998  Local<Object> object3 = Local<Object>::Cast(value_obj3);
7999  value = object3->Get(v8_str("a"));
8000  CHECK(!try_catch.HasCaught());
8001  CHECK(value->IsBoolean());
8002  CHECK_EQ(true, value->BooleanValue());
8003 
8004  // Call the Object's constructor with undefined.
8005  Handle<Value> args4[] = { v8::Undefined() };
8006  Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8007  CHECK(value_obj4->IsObject());
8008  Local<Object> object4 = Local<Object>::Cast(value_obj4);
8009  value = object4->Get(v8_str("a"));
8010  CHECK(!try_catch.HasCaught());
8011  CHECK(value->IsUndefined());
8012 
8013  // Call the Object's constructor with null.
8014  Handle<Value> args5[] = { v8::Null() };
8015  Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8016  CHECK(value_obj5->IsObject());
8017  Local<Object> object5 = Local<Object>::Cast(value_obj5);
8018  value = object5->Get(v8_str("a"));
8019  CHECK(!try_catch.HasCaught());
8020  CHECK(value->IsNull());
8021  }
8022 
8023  // Check exception handling when there is no constructor set for the Object.
8024  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8025  Local<Object> instance = instance_template->NewInstance();
8026  context->Global()->Set(v8_str("obj2"), instance);
8027  v8::TryCatch try_catch;
8028  Local<Value> value;
8029  CHECK(!try_catch.HasCaught());
8030 
8031  value = CompileRun("new obj2(28)");
8032  CHECK(try_catch.HasCaught());
8033  String::AsciiValue exception_value1(try_catch.Exception());
8034  CHECK_EQ("TypeError: object is not a function", *exception_value1);
8035  try_catch.Reset();
8036 
8037  Local<Value> args[] = { v8_num(29) };
8038  value = instance->CallAsConstructor(1, args);
8039  CHECK(try_catch.HasCaught());
8040  String::AsciiValue exception_value2(try_catch.Exception());
8041  CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8042  try_catch.Reset();
8043  }
8044 
8045  // Check the case when constructor throws exception.
8046  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8047  instance_template->SetCallAsFunctionHandler(ThrowValue);
8048  Local<Object> instance = instance_template->NewInstance();
8049  context->Global()->Set(v8_str("obj3"), instance);
8050  v8::TryCatch try_catch;
8051  Local<Value> value;
8052  CHECK(!try_catch.HasCaught());
8053 
8054  value = CompileRun("new obj3(22)");
8055  CHECK(try_catch.HasCaught());
8056  String::AsciiValue exception_value1(try_catch.Exception());
8057  CHECK_EQ("22", *exception_value1);
8058  try_catch.Reset();
8059 
8060  Local<Value> args[] = { v8_num(23) };
8061  value = instance->CallAsConstructor(1, args);
8062  CHECK(try_catch.HasCaught());
8063  String::AsciiValue exception_value2(try_catch.Exception());
8064  CHECK_EQ("23", *exception_value2);
8065  try_catch.Reset();
8066  }
8067 
8068  // Check whether constructor returns with an object or non-object.
8069  { Local<FunctionTemplate> function_template =
8070  FunctionTemplate::New(FakeConstructorCallback);
8071  Local<Function> function = function_template->GetFunction();
8072  Local<Object> instance1 = function;
8073  context->Global()->Set(v8_str("obj4"), instance1);
8074  v8::TryCatch try_catch;
8075  Local<Value> value;
8076  CHECK(!try_catch.HasCaught());
8077 
8078  CHECK(instance1->IsObject());
8079  CHECK(instance1->IsFunction());
8080 
8081  value = CompileRun("new obj4(28)");
8082  CHECK(!try_catch.HasCaught());
8083  CHECK(value->IsObject());
8084 
8085  Local<Value> args1[] = { v8_num(28) };
8086  value = instance1->CallAsConstructor(1, args1);
8087  CHECK(!try_catch.HasCaught());
8088  CHECK(value->IsObject());
8089 
8090  Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8091  instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8092  Local<Object> instance2 = instance_template->NewInstance();
8093  context->Global()->Set(v8_str("obj5"), instance2);
8094  CHECK(!try_catch.HasCaught());
8095 
8096  CHECK(instance2->IsObject());
8097  CHECK(!instance2->IsFunction());
8098 
8099  value = CompileRun("new obj5(28)");
8100  CHECK(!try_catch.HasCaught());
8101  CHECK(!value->IsObject());
8102 
8103  Local<Value> args2[] = { v8_num(28) };
8104  value = instance2->CallAsConstructor(1, args2);
8105  CHECK(!try_catch.HasCaught());
8106  CHECK(!value->IsObject());
8107  }
8108 }
8109 
8110 
8111 THREADED_TEST(FunctionDescriptorException) {
8112  v8::HandleScope handle_scope;
8113  LocalContext context;
8114  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8115  templ->SetClassName(v8_str("Fun"));
8116  Local<Function> cons = templ->GetFunction();
8117  context->Global()->Set(v8_str("Fun"), cons);
8118  Local<Value> value = CompileRun(
8119  "function test() {"
8120  " try {"
8121  " (new Fun()).blah()"
8122  " } catch (e) {"
8123  " var str = String(e);"
8124  " if (str.indexOf('TypeError') == -1) return 1;"
8125  " if (str.indexOf('[object Fun]') != -1) return 2;"
8126  " if (str.indexOf('#<Fun>') == -1) return 3;"
8127  " return 0;"
8128  " }"
8129  " return 4;"
8130  "}"
8131  "test();");
8132  CHECK_EQ(0, value->Int32Value());
8133 }
8134 
8135 
8136 THREADED_TEST(EvalAliasedDynamic) {
8137  v8::HandleScope scope;
8138  LocalContext current;
8139 
8140  // Tests where aliased eval can only be resolved dynamically.
8141  Local<Script> script =
8142  Script::Compile(v8_str("function f(x) { "
8143  " var foo = 2;"
8144  " with (x) { return eval('foo'); }"
8145  "}"
8146  "foo = 0;"
8147  "result1 = f(new Object());"
8148  "result2 = f(this);"
8149  "var x = new Object();"
8150  "x.eval = function(x) { return 1; };"
8151  "result3 = f(x);"));
8152  script->Run();
8153  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8154  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8155  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8156 
8157  v8::TryCatch try_catch;
8158  script =
8159  Script::Compile(v8_str("function f(x) { "
8160  " var bar = 2;"
8161  " with (x) { return eval('bar'); }"
8162  "}"
8163  "result4 = f(this)"));
8164  script->Run();
8165  CHECK(!try_catch.HasCaught());
8166  CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8167 
8168  try_catch.Reset();
8169 }
8170 
8171 
8172 THREADED_TEST(CrossEval) {
8173  v8::HandleScope scope;
8174  LocalContext other;
8175  LocalContext current;
8176 
8177  Local<String> token = v8_str("<security token>");
8178  other->SetSecurityToken(token);
8179  current->SetSecurityToken(token);
8180 
8181  // Set up reference from current to other.
8182  current->Global()->Set(v8_str("other"), other->Global());
8183 
8184  // Check that new variables are introduced in other context.
8185  Local<Script> script =
8186  Script::Compile(v8_str("other.eval('var foo = 1234')"));
8187  script->Run();
8188  Local<Value> foo = other->Global()->Get(v8_str("foo"));
8189  CHECK_EQ(1234, foo->Int32Value());
8190  CHECK(!current->Global()->Has(v8_str("foo")));
8191 
8192  // Check that writing to non-existing properties introduces them in
8193  // the other context.
8194  script =
8195  Script::Compile(v8_str("other.eval('na = 1234')"));
8196  script->Run();
8197  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8198  CHECK(!current->Global()->Has(v8_str("na")));
8199 
8200  // Check that global variables in current context are not visible in other
8201  // context.
8202  v8::TryCatch try_catch;
8203  script =
8204  Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
8205  Local<Value> result = script->Run();
8206  CHECK(try_catch.HasCaught());
8207  try_catch.Reset();
8208 
8209  // Check that local variables in current context are not visible in other
8210  // context.
8211  script =
8212  Script::Compile(v8_str("(function() { "
8213  " var baz = 87;"
8214  " return other.eval('baz');"
8215  "})();"));
8216  result = script->Run();
8217  CHECK(try_catch.HasCaught());
8218  try_catch.Reset();
8219 
8220  // Check that global variables in the other environment are visible
8221  // when evaluting code.
8222  other->Global()->Set(v8_str("bis"), v8_num(1234));
8223  script = Script::Compile(v8_str("other.eval('bis')"));
8224  CHECK_EQ(1234, script->Run()->Int32Value());
8225  CHECK(!try_catch.HasCaught());
8226 
8227  // Check that the 'this' pointer points to the global object evaluating
8228  // code.
8229  other->Global()->Set(v8_str("t"), other->Global());
8230  script = Script::Compile(v8_str("other.eval('this == t')"));
8231  result = script->Run();
8232  CHECK(result->IsTrue());
8233  CHECK(!try_catch.HasCaught());
8234 
8235  // Check that variables introduced in with-statement are not visible in
8236  // other context.
8237  script =
8238  Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8239  result = script->Run();
8240  CHECK(try_catch.HasCaught());
8241  try_catch.Reset();
8242 
8243  // Check that you cannot use 'eval.call' with another object than the
8244  // current global object.
8245  script =
8246  Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8247  result = script->Run();
8248  CHECK(try_catch.HasCaught());
8249 }
8250 
8251 
8252 // Test that calling eval in a context which has been detached from
8253 // its global throws an exception. This behavior is consistent with
8254 // other JavaScript implementations.
8255 THREADED_TEST(EvalInDetachedGlobal) {
8256  v8::HandleScope scope;
8257 
8258  v8::Persistent<Context> context0 = Context::New();
8259  v8::Persistent<Context> context1 = Context::New();
8260 
8261  // Set up function in context0 that uses eval from context0.
8262  context0->Enter();
8263  v8::Handle<v8::Value> fun =
8264  CompileRun("var x = 42;"
8265  "(function() {"
8266  " var e = eval;"
8267  " return function(s) { return e(s); }"
8268  "})()");
8269  context0->Exit();
8270 
8271  // Put the function into context1 and call it before and after
8272  // detaching the global. Before detaching, the call succeeds and
8273  // after detaching and exception is thrown.
8274  context1->Enter();
8275  context1->Global()->Set(v8_str("fun"), fun);
8276  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8277  CHECK_EQ(42, x_value->Int32Value());
8278  context0->DetachGlobal();
8279  v8::TryCatch catcher;
8280  x_value = CompileRun("fun('x')");
8281  CHECK(x_value.IsEmpty());
8282  CHECK(catcher.HasCaught());
8283  context1->Exit();
8284 
8285  context1.Dispose();
8286  context0.Dispose();
8287 }
8288 
8289 
8290 THREADED_TEST(CrossLazyLoad) {
8291  v8::HandleScope scope;
8292  LocalContext other;
8293  LocalContext current;
8294 
8295  Local<String> token = v8_str("<security token>");
8296  other->SetSecurityToken(token);
8297  current->SetSecurityToken(token);
8298 
8299  // Set up reference from current to other.
8300  current->Global()->Set(v8_str("other"), other->Global());
8301 
8302  // Trigger lazy loading in other context.
8303  Local<Script> script =
8304  Script::Compile(v8_str("other.eval('new Date(42)')"));
8305  Local<Value> value = script->Run();
8306  CHECK_EQ(42.0, value->NumberValue());
8307 }
8308 
8309 
8310 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8312  if (args.IsConstructCall()) {
8313  if (args[0]->IsInt32()) {
8314  return v8_num(-args[0]->Int32Value());
8315  }
8316  }
8317 
8318  return args[0];
8319 }
8320 
8321 
8322 // Test that a call handler can be set for objects which will allow
8323 // non-function objects created through the API to be called as
8324 // functions.
8325 THREADED_TEST(CallAsFunction) {
8326  v8::HandleScope scope;
8327  LocalContext context;
8328 
8329  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8330  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8331  instance_template->SetCallAsFunctionHandler(call_as_function);
8332  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8333  context->Global()->Set(v8_str("obj"), instance);
8334  v8::TryCatch try_catch;
8335  Local<Value> value;
8336  CHECK(!try_catch.HasCaught());
8337 
8338  value = CompileRun("obj(42)");
8339  CHECK(!try_catch.HasCaught());
8340  CHECK_EQ(42, value->Int32Value());
8341 
8342  value = CompileRun("(function(o){return o(49)})(obj)");
8343  CHECK(!try_catch.HasCaught());
8344  CHECK_EQ(49, value->Int32Value());
8345 
8346  // test special case of call as function
8347  value = CompileRun("[obj]['0'](45)");
8348  CHECK(!try_catch.HasCaught());
8349  CHECK_EQ(45, value->Int32Value());
8350 
8351  value = CompileRun("obj.call = Function.prototype.call;"
8352  "obj.call(null, 87)");
8353  CHECK(!try_catch.HasCaught());
8354  CHECK_EQ(87, value->Int32Value());
8355 
8356  // Regression tests for bug #1116356: Calling call through call/apply
8357  // must work for non-function receivers.
8358  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8359  value = CompileRun(apply_99);
8360  CHECK(!try_catch.HasCaught());
8361  CHECK_EQ(99, value->Int32Value());
8362 
8363  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8364  value = CompileRun(call_17);
8365  CHECK(!try_catch.HasCaught());
8366  CHECK_EQ(17, value->Int32Value());
8367 
8368  // Check that the call-as-function handler can be called through
8369  // new.
8370  value = CompileRun("new obj(43)");
8371  CHECK(!try_catch.HasCaught());
8372  CHECK_EQ(-43, value->Int32Value());
8373 
8374  // Check that the call-as-function handler can be called through
8375  // the API.
8376  v8::Handle<Value> args[] = { v8_num(28) };
8377  value = instance->CallAsFunction(instance, 1, args);
8378  CHECK(!try_catch.HasCaught());
8379  CHECK_EQ(28, value->Int32Value());
8380  }
8381 
8382  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8383  Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8384  USE(instance_template);
8385  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8386  context->Global()->Set(v8_str("obj2"), instance);
8387  v8::TryCatch try_catch;
8388  Local<Value> value;
8389  CHECK(!try_catch.HasCaught());
8390 
8391  // Call an object without call-as-function handler through the JS
8392  value = CompileRun("obj2(28)");
8393  CHECK(value.IsEmpty());
8394  CHECK(try_catch.HasCaught());
8395  String::AsciiValue exception_value1(try_catch.Exception());
8396  CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8397  *exception_value1);
8398  try_catch.Reset();
8399 
8400  // Call an object without call-as-function handler through the API
8401  value = CompileRun("obj2(28)");
8402  v8::Handle<Value> args[] = { v8_num(28) };
8403  value = instance->CallAsFunction(instance, 1, args);
8404  CHECK(value.IsEmpty());
8405  CHECK(try_catch.HasCaught());
8406  String::AsciiValue exception_value2(try_catch.Exception());
8407  CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8408  try_catch.Reset();
8409  }
8410 
8411  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8412  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8413  instance_template->SetCallAsFunctionHandler(ThrowValue);
8414  Local<v8::Object> instance = t->GetFunction()->NewInstance();
8415  context->Global()->Set(v8_str("obj3"), instance);
8416  v8::TryCatch try_catch;
8417  Local<Value> value;
8418  CHECK(!try_catch.HasCaught());
8419 
8420  // Catch the exception which is thrown by call-as-function handler
8421  value = CompileRun("obj3(22)");
8422  CHECK(try_catch.HasCaught());
8423  String::AsciiValue exception_value1(try_catch.Exception());
8424  CHECK_EQ("22", *exception_value1);
8425  try_catch.Reset();
8426 
8427  v8::Handle<Value> args[] = { v8_num(23) };
8428  value = instance->CallAsFunction(instance, 1, args);
8429  CHECK(try_catch.HasCaught());
8430  String::AsciiValue exception_value2(try_catch.Exception());
8431  CHECK_EQ("23", *exception_value2);
8432  try_catch.Reset();
8433  }
8434 }
8435 
8436 
8437 // Check whether a non-function object is callable.
8438 THREADED_TEST(CallableObject) {
8439  v8::HandleScope scope;
8440  LocalContext context;
8441 
8442  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8443  instance_template->SetCallAsFunctionHandler(call_as_function);
8444  Local<Object> instance = instance_template->NewInstance();
8445  v8::TryCatch try_catch;
8446 
8447  CHECK(instance->IsCallable());
8448  CHECK(!try_catch.HasCaught());
8449  }
8450 
8451  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8452  Local<Object> instance = instance_template->NewInstance();
8453  v8::TryCatch try_catch;
8454 
8455  CHECK(!instance->IsCallable());
8456  CHECK(!try_catch.HasCaught());
8457  }
8458 
8459  { Local<FunctionTemplate> function_template =
8460  FunctionTemplate::New(call_as_function);
8461  Local<Function> function = function_template->GetFunction();
8462  Local<Object> instance = function;
8463  v8::TryCatch try_catch;
8464 
8465  CHECK(instance->IsCallable());
8466  CHECK(!try_catch.HasCaught());
8467  }
8468 
8469  { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8470  Local<Function> function = function_template->GetFunction();
8471  Local<Object> instance = function;
8472  v8::TryCatch try_catch;
8473 
8474  CHECK(instance->IsCallable());
8475  CHECK(!try_catch.HasCaught());
8476  }
8477 }
8478 
8479 
8480 static int CountHandles() {
8482 }
8483 
8484 
8485 static int Recurse(int depth, int iterations) {
8486  v8::HandleScope scope;
8487  if (depth == 0) return CountHandles();
8488  for (int i = 0; i < iterations; i++) {
8489  Local<v8::Number> n(v8::Integer::New(42));
8490  }
8491  return Recurse(depth - 1, iterations);
8492 }
8493 
8494 
8495 THREADED_TEST(HandleIteration) {
8496  static const int kIterations = 500;
8497  static const int kNesting = 200;
8498  CHECK_EQ(0, CountHandles());
8499  {
8500  v8::HandleScope scope1;
8501  CHECK_EQ(0, CountHandles());
8502  for (int i = 0; i < kIterations; i++) {
8503  Local<v8::Number> n(v8::Integer::New(42));
8504  CHECK_EQ(i + 1, CountHandles());
8505  }
8506 
8507  CHECK_EQ(kIterations, CountHandles());
8508  {
8509  v8::HandleScope scope2;
8510  for (int j = 0; j < kIterations; j++) {
8511  Local<v8::Number> n(v8::Integer::New(42));
8512  CHECK_EQ(j + 1 + kIterations, CountHandles());
8513  }
8514  }
8515  CHECK_EQ(kIterations, CountHandles());
8516  }
8517  CHECK_EQ(0, CountHandles());
8518  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8519 }
8520 
8521 
8522 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8523  Local<String> name,
8524  const AccessorInfo& info) {
8526  return v8::Handle<Value>();
8527 }
8528 
8529 
8530 THREADED_TEST(InterceptorHasOwnProperty) {
8531  v8::HandleScope scope;
8532  LocalContext context;
8533  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8534  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8535  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8536  Local<Function> function = fun_templ->GetFunction();
8537  context->Global()->Set(v8_str("constructor"), function);
8538  v8::Handle<Value> value = CompileRun(
8539  "var o = new constructor();"
8540  "o.hasOwnProperty('ostehaps');");
8541  CHECK_EQ(false, value->BooleanValue());
8542  value = CompileRun(
8543  "o.ostehaps = 42;"
8544  "o.hasOwnProperty('ostehaps');");
8545  CHECK_EQ(true, value->BooleanValue());
8546  value = CompileRun(
8547  "var p = new constructor();"
8548  "p.hasOwnProperty('ostehaps');");
8549  CHECK_EQ(false, value->BooleanValue());
8550 }
8551 
8552 
8553 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8554  Local<String> name,
8555  const AccessorInfo& info) {
8557  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8558  return v8::Handle<Value>();
8559 }
8560 
8561 
8562 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8563  v8::HandleScope scope;
8564  LocalContext context;
8565  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8566  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8567  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8568  Local<Function> function = fun_templ->GetFunction();
8569  context->Global()->Set(v8_str("constructor"), function);
8570  // Let's first make some stuff so we can be sure to get a good GC.
8571  CompileRun(
8572  "function makestr(size) {"
8573  " switch (size) {"
8574  " case 1: return 'f';"
8575  " case 2: return 'fo';"
8576  " case 3: return 'foo';"
8577  " }"
8578  " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8579  "}"
8580  "var x = makestr(12345);"
8581  "x = makestr(31415);"
8582  "x = makestr(23456);");
8583  v8::Handle<Value> value = CompileRun(
8584  "var o = new constructor();"
8585  "o.__proto__ = new String(x);"
8586  "o.hasOwnProperty('ostehaps');");
8587  CHECK_EQ(false, value->BooleanValue());
8588 }
8589 
8590 
8591 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8592  const AccessorInfo& info);
8593 
8594 
8595 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8596  const char* source,
8597  int expected) {
8598  v8::HandleScope scope;
8599  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8600  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8601  LocalContext context;
8602  context->Global()->Set(v8_str("o"), templ->NewInstance());
8603  v8::Handle<Value> value = CompileRun(source);
8604  CHECK_EQ(expected, value->Int32Value());
8605 }
8606 
8607 
8608 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8609  const AccessorInfo& info) {
8611  v8::Isolate* isolate = v8::Isolate::GetCurrent();
8612  CHECK_EQ(isolate, info.GetIsolate());
8613  CHECK_EQ(v8_str("data"), info.Data());
8614  CHECK_EQ(v8_str("x"), name);
8615  return v8::Integer::New(42);
8616 }
8617 
8618 
8619 // This test should hit the load IC for the interceptor case.
8620 THREADED_TEST(InterceptorLoadIC) {
8621  CheckInterceptorLoadIC(InterceptorLoadICGetter,
8622  "var result = 0;"
8623  "for (var i = 0; i < 1000; i++) {"
8624  " result = o.x;"
8625  "}",
8626  42);
8627 }
8628 
8629 
8630 // Below go several tests which verify that JITing for various
8631 // configurations of interceptor and explicit fields works fine
8632 // (those cases are special cased to get better performance).
8633 
8634 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8635  const AccessorInfo& info) {
8637  return v8_str("x")->Equals(name)
8638  ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8639 }
8640 
8641 
8642 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8643  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8644  "var result = 0;"
8645  "o.y = 239;"
8646  "for (var i = 0; i < 1000; i++) {"
8647  " result = o.y;"
8648  "}",
8649  239);
8650 }
8651 
8652 
8653 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8654  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8655  "var result = 0;"
8656  "o.__proto__ = { 'y': 239 };"
8657  "for (var i = 0; i < 1000; i++) {"
8658  " result = o.y + o.x;"
8659  "}",
8660  239 + 42);
8661 }
8662 
8663 
8664 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8665  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8666  "var result = 0;"
8667  "o.__proto__.y = 239;"
8668  "for (var i = 0; i < 1000; i++) {"
8669  " result = o.y + o.x;"
8670  "}",
8671  239 + 42);
8672 }
8673 
8674 
8675 THREADED_TEST(InterceptorLoadICUndefined) {
8676  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8677  "var result = 0;"
8678  "for (var i = 0; i < 1000; i++) {"
8679  " result = (o.y == undefined) ? 239 : 42;"
8680  "}",
8681  239);
8682 }
8683 
8684 
8685 THREADED_TEST(InterceptorLoadICWithOverride) {
8686  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8687  "fst = new Object(); fst.__proto__ = o;"
8688  "snd = new Object(); snd.__proto__ = fst;"
8689  "var result1 = 0;"
8690  "for (var i = 0; i < 1000; i++) {"
8691  " result1 = snd.x;"
8692  "}"
8693  "fst.x = 239;"
8694  "var result = 0;"
8695  "for (var i = 0; i < 1000; i++) {"
8696  " result = snd.x;"
8697  "}"
8698  "result + result1",
8699  239 + 42);
8700 }
8701 
8702 
8703 // Test the case when we stored field into
8704 // a stub, but interceptor produced value on its own.
8705 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8706  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8707  "proto = new Object();"
8708  "o.__proto__ = proto;"
8709  "proto.x = 239;"
8710  "for (var i = 0; i < 1000; i++) {"
8711  " o.x;"
8712  // Now it should be ICed and keep a reference to x defined on proto
8713  "}"
8714  "var result = 0;"
8715  "for (var i = 0; i < 1000; i++) {"
8716  " result += o.x;"
8717  "}"
8718  "result;",
8719  42 * 1000);
8720 }
8721 
8722 
8723 // Test the case when we stored field into
8724 // a stub, but it got invalidated later on.
8725 THREADED_TEST(InterceptorLoadICInvalidatedField) {
8726  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8727  "proto1 = new Object();"
8728  "proto2 = new Object();"
8729  "o.__proto__ = proto1;"
8730  "proto1.__proto__ = proto2;"
8731  "proto2.y = 239;"
8732  "for (var i = 0; i < 1000; i++) {"
8733  " o.y;"
8734  // Now it should be ICed and keep a reference to y defined on proto2
8735  "}"
8736  "proto1.y = 42;"
8737  "var result = 0;"
8738  "for (var i = 0; i < 1000; i++) {"
8739  " result += o.y;"
8740  "}"
8741  "result;",
8742  42 * 1000);
8743 }
8744 
8745 
8746 static int interceptor_load_not_handled_calls = 0;
8747 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8748  const AccessorInfo& info) {
8749  ++interceptor_load_not_handled_calls;
8750  return v8::Handle<v8::Value>();
8751 }
8752 
8753 
8754 // Test how post-interceptor lookups are done in the non-cacheable
8755 // case: the interceptor should not be invoked during this lookup.
8756 THREADED_TEST(InterceptorLoadICPostInterceptor) {
8757  interceptor_load_not_handled_calls = 0;
8758  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8759  "receiver = new Object();"
8760  "receiver.__proto__ = o;"
8761  "proto = new Object();"
8762  "/* Make proto a slow-case object. */"
8763  "for (var i = 0; i < 1000; i++) {"
8764  " proto[\"xxxxxxxx\" + i] = [];"
8765  "}"
8766  "proto.x = 17;"
8767  "o.__proto__ = proto;"
8768  "var result = 0;"
8769  "for (var i = 0; i < 1000; i++) {"
8770  " result += receiver.x;"
8771  "}"
8772  "result;",
8773  17 * 1000);
8774  CHECK_EQ(1000, interceptor_load_not_handled_calls);
8775 }
8776 
8777 
8778 // Test the case when we stored field into
8779 // a stub, but it got invalidated later on due to override on
8780 // global object which is between interceptor and fields' holders.
8781 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8782  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8783  "o.__proto__ = this;" // set a global to be a proto of o.
8784  "this.__proto__.y = 239;"
8785  "for (var i = 0; i < 10; i++) {"
8786  " if (o.y != 239) throw 'oops: ' + o.y;"
8787  // Now it should be ICed and keep a reference to y defined on field_holder.
8788  "}"
8789  "this.y = 42;" // Assign on a global.
8790  "var result = 0;"
8791  "for (var i = 0; i < 10; i++) {"
8792  " result += o.y;"
8793  "}"
8794  "result;",
8795  42 * 10);
8796 }
8797 
8798 
8799 static void SetOnThis(Local<String> name,
8800  Local<Value> value,
8801  const AccessorInfo& info) {
8802  info.This()->ForceSet(name, value);
8803 }
8804 
8805 
8806 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8807  v8::HandleScope scope;
8808  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8809  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8810  templ->SetAccessor(v8_str("y"), Return239);
8811  LocalContext context;
8812  context->Global()->Set(v8_str("o"), templ->NewInstance());
8813 
8814  // Check the case when receiver and interceptor's holder
8815  // are the same objects.
8816  v8::Handle<Value> value = CompileRun(
8817  "var result = 0;"
8818  "for (var i = 0; i < 7; i++) {"
8819  " result = o.y;"
8820  "}");
8821  CHECK_EQ(239, value->Int32Value());
8822 
8823  // Check the case when interceptor's holder is in proto chain
8824  // of receiver.
8825  value = CompileRun(
8826  "r = { __proto__: o };"
8827  "var result = 0;"
8828  "for (var i = 0; i < 7; i++) {"
8829  " result = r.y;"
8830  "}");
8831  CHECK_EQ(239, value->Int32Value());
8832 }
8833 
8834 
8835 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8836  v8::HandleScope scope;
8837  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8838  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8839  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8840  templ_p->SetAccessor(v8_str("y"), Return239);
8841 
8842  LocalContext context;
8843  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8844  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8845 
8846  // Check the case when receiver and interceptor's holder
8847  // are the same objects.
8848  v8::Handle<Value> value = CompileRun(
8849  "o.__proto__ = p;"
8850  "var result = 0;"
8851  "for (var i = 0; i < 7; i++) {"
8852  " result = o.x + o.y;"
8853  "}");
8854  CHECK_EQ(239 + 42, value->Int32Value());
8855 
8856  // Check the case when interceptor's holder is in proto chain
8857  // of receiver.
8858  value = CompileRun(
8859  "r = { __proto__: o };"
8860  "var result = 0;"
8861  "for (var i = 0; i < 7; i++) {"
8862  " result = r.x + r.y;"
8863  "}");
8864  CHECK_EQ(239 + 42, value->Int32Value());
8865 }
8866 
8867 
8868 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8869  v8::HandleScope scope;
8870  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8871  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8872  templ->SetAccessor(v8_str("y"), Return239);
8873 
8874  LocalContext context;
8875  context->Global()->Set(v8_str("o"), templ->NewInstance());
8876 
8877  v8::Handle<Value> value = CompileRun(
8878  "fst = new Object(); fst.__proto__ = o;"
8879  "snd = new Object(); snd.__proto__ = fst;"
8880  "var result1 = 0;"
8881  "for (var i = 0; i < 7; i++) {"
8882  " result1 = snd.x;"
8883  "}"
8884  "fst.x = 239;"
8885  "var result = 0;"
8886  "for (var i = 0; i < 7; i++) {"
8887  " result = snd.x;"
8888  "}"
8889  "result + result1");
8890  CHECK_EQ(239 + 42, value->Int32Value());
8891 }
8892 
8893 
8894 // Test the case when we stored callback into
8895 // a stub, but interceptor produced value on its own.
8896 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8897  v8::HandleScope scope;
8898  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8899  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8900  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8901  templ_p->SetAccessor(v8_str("y"), Return239);
8902 
8903  LocalContext context;
8904  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8905  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8906 
8907  v8::Handle<Value> value = CompileRun(
8908  "o.__proto__ = p;"
8909  "for (var i = 0; i < 7; i++) {"
8910  " o.x;"
8911  // Now it should be ICed and keep a reference to x defined on p
8912  "}"
8913  "var result = 0;"
8914  "for (var i = 0; i < 7; i++) {"
8915  " result += o.x;"
8916  "}"
8917  "result");
8918  CHECK_EQ(42 * 7, value->Int32Value());
8919 }
8920 
8921 
8922 // Test the case when we stored callback into
8923 // a stub, but it got invalidated later on.
8924 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8925  v8::HandleScope scope;
8926  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8927  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8928  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8929  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8930 
8931  LocalContext context;
8932  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8933  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8934 
8935  v8::Handle<Value> value = CompileRun(
8936  "inbetween = new Object();"
8937  "o.__proto__ = inbetween;"
8938  "inbetween.__proto__ = p;"
8939  "for (var i = 0; i < 10; i++) {"
8940  " o.y;"
8941  // Now it should be ICed and keep a reference to y defined on p
8942  "}"
8943  "inbetween.y = 42;"
8944  "var result = 0;"
8945  "for (var i = 0; i < 10; i++) {"
8946  " result += o.y;"
8947  "}"
8948  "result");
8949  CHECK_EQ(42 * 10, value->Int32Value());
8950 }
8951 
8952 
8953 // Test the case when we stored callback into
8954 // a stub, but it got invalidated later on due to override on
8955 // global object which is between interceptor and callbacks' holders.
8956 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8957  v8::HandleScope scope;
8958  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8959  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8960  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8961  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8962 
8963  LocalContext context;
8964  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8965  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8966 
8967  v8::Handle<Value> value = CompileRun(
8968  "o.__proto__ = this;"
8969  "this.__proto__ = p;"
8970  "for (var i = 0; i < 10; i++) {"
8971  " if (o.y != 239) throw 'oops: ' + o.y;"
8972  // Now it should be ICed and keep a reference to y defined on p
8973  "}"
8974  "this.y = 42;"
8975  "var result = 0;"
8976  "for (var i = 0; i < 10; i++) {"
8977  " result += o.y;"
8978  "}"
8979  "result");
8980  CHECK_EQ(42 * 10, value->Int32Value());
8981 }
8982 
8983 
8984 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8985  const AccessorInfo& info) {
8987  CHECK(v8_str("x")->Equals(name));
8988  return v8::Integer::New(0);
8989 }
8990 
8991 
8992 THREADED_TEST(InterceptorReturningZero) {
8993  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8994  "o.x == undefined ? 1 : 0",
8995  0);
8996 }
8997 
8998 
8999 static v8::Handle<Value> InterceptorStoreICSetter(
9000  Local<String> key, Local<Value> value, const AccessorInfo&) {
9001  CHECK(v8_str("x")->Equals(key));
9002  CHECK_EQ(42, value->Int32Value());
9003  return value;
9004 }
9005 
9006 
9007 // This test should hit the store IC for the interceptor case.
9008 THREADED_TEST(InterceptorStoreIC) {
9009  v8::HandleScope scope;
9010  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9011  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
9012  InterceptorStoreICSetter,
9013  0, 0, 0, v8_str("data"));
9014  LocalContext context;
9015  context->Global()->Set(v8_str("o"), templ->NewInstance());
9016  CompileRun(
9017  "for (var i = 0; i < 1000; i++) {"
9018  " o.x = 42;"
9019  "}");
9020 }
9021 
9022 
9023 THREADED_TEST(InterceptorStoreICWithNoSetter) {
9024  v8::HandleScope scope;
9025  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9026  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9027  LocalContext context;
9028  context->Global()->Set(v8_str("o"), templ->NewInstance());
9029  v8::Handle<Value> value = CompileRun(
9030  "for (var i = 0; i < 1000; i++) {"
9031  " o.y = 239;"
9032  "}"
9033  "42 + o.y");
9034  CHECK_EQ(239 + 42, value->Int32Value());
9035 }
9036 
9037 
9038 
9039 
9043 
9044 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9045  const AccessorInfo& info) {
9047  CHECK(v8_str("x")->Equals(name));
9048  return call_ic_function;
9049 }
9050 
9051 
9052 // This test should hit the call IC for the interceptor case.
9053 THREADED_TEST(InterceptorCallIC) {
9054  v8::HandleScope scope;
9055  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9056  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9057  LocalContext context;
9058  context->Global()->Set(v8_str("o"), templ->NewInstance());
9059  call_ic_function =
9060  v8_compile("function f(x) { return x + 1; }; f")->Run();
9061  v8::Handle<Value> value = CompileRun(
9062  "var result = 0;"
9063  "for (var i = 0; i < 1000; i++) {"
9064  " result = o.x(41);"
9065  "}");
9066  CHECK_EQ(42, value->Int32Value());
9067 }
9068 
9069 
9070 // This test checks that if interceptor doesn't provide
9071 // a value, we can fetch regular value.
9072 THREADED_TEST(InterceptorCallICSeesOthers) {
9073  v8::HandleScope scope;
9074  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9075  templ->SetNamedPropertyHandler(NoBlockGetterX);
9076  LocalContext context;
9077  context->Global()->Set(v8_str("o"), templ->NewInstance());
9078  v8::Handle<Value> value = CompileRun(
9079  "o.x = function f(x) { return x + 1; };"
9080  "var result = 0;"
9081  "for (var i = 0; i < 7; i++) {"
9082  " result = o.x(41);"
9083  "}");
9084  CHECK_EQ(42, value->Int32Value());
9085 }
9086 
9087 
9088 static v8::Handle<Value> call_ic_function4;
9089 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9090  const AccessorInfo& info) {
9092  CHECK(v8_str("x")->Equals(name));
9093  return call_ic_function4;
9094 }
9095 
9096 
9097 // This test checks that if interceptor provides a function,
9098 // even if we cached shadowed variant, interceptor's function
9099 // is invoked
9100 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9101  v8::HandleScope scope;
9102  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9103  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9104  LocalContext context;
9105  context->Global()->Set(v8_str("o"), templ->NewInstance());
9106  call_ic_function4 =
9107  v8_compile("function f(x) { return x - 1; }; f")->Run();
9108  v8::Handle<Value> value = CompileRun(
9109  "o.__proto__.x = function(x) { return x + 1; };"
9110  "var result = 0;"
9111  "for (var i = 0; i < 1000; i++) {"
9112  " result = o.x(42);"
9113  "}");
9114  CHECK_EQ(41, value->Int32Value());
9115 }
9116 
9117 
9118 // Test the case when we stored cacheable lookup into
9119 // a stub, but it got invalidated later on
9120 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9121  v8::HandleScope scope;
9122  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9123  templ->SetNamedPropertyHandler(NoBlockGetterX);
9124  LocalContext context;
9125  context->Global()->Set(v8_str("o"), templ->NewInstance());
9126  v8::Handle<Value> value = CompileRun(
9127  "proto1 = new Object();"
9128  "proto2 = new Object();"
9129  "o.__proto__ = proto1;"
9130  "proto1.__proto__ = proto2;"
9131  "proto2.y = function(x) { return x + 1; };"
9132  // Invoke it many times to compile a stub
9133  "for (var i = 0; i < 7; i++) {"
9134  " o.y(42);"
9135  "}"
9136  "proto1.y = function(x) { return x - 1; };"
9137  "var result = 0;"
9138  "for (var i = 0; i < 7; i++) {"
9139  " result += o.y(42);"
9140  "}");
9141  CHECK_EQ(41 * 7, value->Int32Value());
9142 }
9143 
9144 
9145 // This test checks that if interceptor doesn't provide a function,
9146 // cached constant function is used
9147 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9148  v8::HandleScope scope;
9149  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9150  templ->SetNamedPropertyHandler(NoBlockGetterX);
9151  LocalContext context;
9152  context->Global()->Set(v8_str("o"), templ->NewInstance());
9153  v8::Handle<Value> value = CompileRun(
9154  "function inc(x) { return x + 1; };"
9155  "inc(1);"
9156  "o.x = inc;"
9157  "var result = 0;"
9158  "for (var i = 0; i < 1000; i++) {"
9159  " result = o.x(42);"
9160  "}");
9161  CHECK_EQ(43, value->Int32Value());
9162 }
9163 
9164 
9165 static v8::Handle<Value> call_ic_function5;
9166 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9167  const AccessorInfo& info) {
9169  if (v8_str("x")->Equals(name))
9170  return call_ic_function5;
9171  else
9172  return Local<Value>();
9173 }
9174 
9175 
9176 // This test checks that if interceptor provides a function,
9177 // even if we cached constant function, interceptor's function
9178 // is invoked
9179 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9180  v8::HandleScope scope;
9181  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9182  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9183  LocalContext context;
9184  context->Global()->Set(v8_str("o"), templ->NewInstance());
9185  call_ic_function5 =
9186  v8_compile("function f(x) { return x - 1; }; f")->Run();
9187  v8::Handle<Value> value = CompileRun(
9188  "function inc(x) { return x + 1; };"
9189  "inc(1);"
9190  "o.x = inc;"
9191  "var result = 0;"
9192  "for (var i = 0; i < 1000; i++) {"
9193  " result = o.x(42);"
9194  "}");
9195  CHECK_EQ(41, value->Int32Value());
9196 }
9197 
9198 
9199 static v8::Handle<Value> call_ic_function6;
9200 static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9201  const AccessorInfo& info) {
9203  if (v8_str("x")->Equals(name))
9204  return call_ic_function6;
9205  else
9206  return Local<Value>();
9207 }
9208 
9209 
9210 // Same test as above, except the code is wrapped in a function
9211 // to test the optimized compiler.
9212 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9213  i::FLAG_allow_natives_syntax = true;
9214  v8::HandleScope scope;
9215  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9216  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9217  LocalContext context;
9218  context->Global()->Set(v8_str("o"), templ->NewInstance());
9219  call_ic_function6 =
9220  v8_compile("function f(x) { return x - 1; }; f")->Run();
9221  v8::Handle<Value> value = CompileRun(
9222  "function inc(x) { return x + 1; };"
9223  "inc(1);"
9224  "o.x = inc;"
9225  "function test() {"
9226  " var result = 0;"
9227  " for (var i = 0; i < 1000; i++) {"
9228  " result = o.x(42);"
9229  " }"
9230  " return result;"
9231  "};"
9232  "test();"
9233  "test();"
9234  "test();"
9235  "%OptimizeFunctionOnNextCall(test);"
9236  "test()");
9237  CHECK_EQ(41, value->Int32Value());
9238 }
9239 
9240 
9241 // Test the case when we stored constant function into
9242 // a stub, but it got invalidated later on
9243 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9244  v8::HandleScope scope;
9245  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9246  templ->SetNamedPropertyHandler(NoBlockGetterX);
9247  LocalContext context;
9248  context->Global()->Set(v8_str("o"), templ->NewInstance());
9249  v8::Handle<Value> value = CompileRun(
9250  "function inc(x) { return x + 1; };"
9251  "inc(1);"
9252  "proto1 = new Object();"
9253  "proto2 = new Object();"
9254  "o.__proto__ = proto1;"
9255  "proto1.__proto__ = proto2;"
9256  "proto2.y = inc;"
9257  // Invoke it many times to compile a stub
9258  "for (var i = 0; i < 7; i++) {"
9259  " o.y(42);"
9260  "}"
9261  "proto1.y = function(x) { return x - 1; };"
9262  "var result = 0;"
9263  "for (var i = 0; i < 7; i++) {"
9264  " result += o.y(42);"
9265  "}");
9266  CHECK_EQ(41 * 7, value->Int32Value());
9267 }
9268 
9269 
9270 // Test the case when we stored constant function into
9271 // a stub, but it got invalidated later on due to override on
9272 // global object which is between interceptor and constant function' holders.
9273 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9274  v8::HandleScope scope;
9275  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9276  templ->SetNamedPropertyHandler(NoBlockGetterX);
9277  LocalContext context;
9278  context->Global()->Set(v8_str("o"), templ->NewInstance());
9279  v8::Handle<Value> value = CompileRun(
9280  "function inc(x) { return x + 1; };"
9281  "inc(1);"
9282  "o.__proto__ = this;"
9283  "this.__proto__.y = inc;"
9284  // Invoke it many times to compile a stub
9285  "for (var i = 0; i < 7; i++) {"
9286  " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9287  "}"
9288  "this.y = function(x) { return x - 1; };"
9289  "var result = 0;"
9290  "for (var i = 0; i < 7; i++) {"
9291  " result += o.y(42);"
9292  "}");
9293  CHECK_EQ(41 * 7, value->Int32Value());
9294 }
9295 
9296 
9297 // Test the case when actual function to call sits on global object.
9298 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9299  v8::HandleScope scope;
9300  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9301  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9302 
9303  LocalContext context;
9304  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9305 
9306  v8::Handle<Value> value = CompileRun(
9307  "try {"
9308  " o.__proto__ = this;"
9309  " for (var i = 0; i < 10; i++) {"
9310  " var v = o.parseFloat('239');"
9311  " if (v != 239) throw v;"
9312  // Now it should be ICed and keep a reference to parseFloat.
9313  " }"
9314  " var result = 0;"
9315  " for (var i = 0; i < 10; i++) {"
9316  " result += o.parseFloat('239');"
9317  " }"
9318  " result"
9319  "} catch(e) {"
9320  " e"
9321  "};");
9322  CHECK_EQ(239 * 10, value->Int32Value());
9323 }
9324 
9325 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9326  const AccessorInfo& info) {
9328  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9329  ++(*call_count);
9330  if ((*call_count) % 20 == 0) {
9331  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
9332  }
9333  return v8::Handle<Value>();
9334 }
9335 
9336 static v8::Handle<Value> FastApiCallback_TrivialSignature(
9337  const v8::Arguments& args) {
9339  v8::Isolate* isolate = v8::Isolate::GetCurrent();
9340  CHECK_EQ(isolate, args.GetIsolate());
9341  CHECK_EQ(args.This(), args.Holder());
9342  CHECK(args.Data()->Equals(v8_str("method_data")));
9343  return v8::Integer::New(args[0]->Int32Value() + 1);
9344 }
9345 
9346 static v8::Handle<Value> FastApiCallback_SimpleSignature(
9347  const v8::Arguments& args) {
9349  v8::Isolate* isolate = v8::Isolate::GetCurrent();
9350  CHECK_EQ(isolate, args.GetIsolate());
9351  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9352  CHECK(args.Data()->Equals(v8_str("method_data")));
9353  // Note, we're using HasRealNamedProperty instead of Has to avoid
9354  // invoking the interceptor again.
9355  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9356  return v8::Integer::New(args[0]->Int32Value() + 1);
9357 }
9358 
9359 // Helper to maximize the odds of object moving.
9360 static void GenerateSomeGarbage() {
9361  CompileRun(
9362  "var garbage;"
9363  "for (var i = 0; i < 1000; i++) {"
9364  " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9365  "}"
9366  "garbage = undefined;");
9367 }
9368 
9369 
9371  static int count = 0;
9372  if (count++ % 3 == 0) {
9373  HEAP-> CollectAllGarbage(true); // This should move the stub
9374  GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9375  }
9376  return v8::Handle<v8::Value>();
9377 }
9378 
9379 
9380 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9381  v8::HandleScope scope;
9382  LocalContext context;
9384  nativeobject_templ->Set("callback",
9386  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9387  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9388  // call the api function multiple times to ensure direct call stub creation.
9389  CompileRun(
9390  "function f() {"
9391  " for (var i = 1; i <= 30; i++) {"
9392  " nativeobject.callback();"
9393  " }"
9394  "}"
9395  "f();");
9396 }
9397 
9398 
9400  return v8::ThrowException(v8_str("g"));
9401 }
9402 
9403 
9404 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9405  v8::HandleScope scope;
9406  LocalContext context;
9408  nativeobject_templ->Set("callback",
9410  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9411  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9412  // call the api function multiple times to ensure direct call stub creation.
9413  v8::Handle<Value> result = CompileRun(
9414  "var result = '';"
9415  "function f() {"
9416  " for (var i = 1; i <= 5; i++) {"
9417  " try { nativeobject.callback(); } catch (e) { result += e; }"
9418  " }"
9419  "}"
9420  "f(); result;");
9421  CHECK_EQ(v8_str("ggggg"), result);
9422 }
9423 
9424 
9426  const v8::AccessorInfo& info) {
9427  if (++p_getter_count % 3 == 0) {
9428  HEAP->CollectAllGarbage(true);
9429  GenerateSomeGarbage();
9430  }
9431  return v8::Handle<v8::Value>();
9432 }
9433 
9434 
9435 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9436  v8::HandleScope scope;
9437  LocalContext context;
9439  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9440  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9441  p_getter_count = 0;
9442  CompileRun(
9443  "function f() {"
9444  " for (var i = 0; i < 30; i++) o1.p1;"
9445  "}"
9446  "f();");
9447  CHECK_EQ(30, p_getter_count);
9448 }
9449 
9450 
9452  Local<String> name, const v8::AccessorInfo& info) {
9453  return v8::ThrowException(v8_str("g"));
9454 }
9455 
9456 
9457 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9458  v8::HandleScope scope;
9459  LocalContext context;
9461  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9462  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9463  v8::Handle<Value> result = CompileRun(
9464  "var result = '';"
9465  "for (var i = 0; i < 5; i++) {"
9466  " try { o1.p1; } catch (e) { result += e; }"
9467  "}"
9468  "result;");
9469  CHECK_EQ(v8_str("ggggg"), result);
9470 }
9471 
9472 
9473 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9474  int interceptor_call_count = 0;
9475  v8::HandleScope scope;
9477  v8::Handle<v8::FunctionTemplate> method_templ =
9478  v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9479  v8_str("method_data"),
9481  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9482  proto_templ->Set(v8_str("method"), method_templ);
9483  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9484  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9485  NULL, NULL, NULL, NULL,
9486  v8::External::Wrap(&interceptor_call_count));
9487  LocalContext context;
9488  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9489  GenerateSomeGarbage();
9490  context->Global()->Set(v8_str("o"), fun->NewInstance());
9491  CompileRun(
9492  "var result = 0;"
9493  "for (var i = 0; i < 100; i++) {"
9494  " result = o.method(41);"
9495  "}");
9496  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9497  CHECK_EQ(100, interceptor_call_count);
9498 }
9499 
9500 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9501  int interceptor_call_count = 0;
9502  v8::HandleScope scope;
9504  v8::Handle<v8::FunctionTemplate> method_templ =
9505  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9506  v8_str("method_data"),
9507  v8::Signature::New(fun_templ));
9508  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9509  proto_templ->Set(v8_str("method"), method_templ);
9510  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9511  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9512  NULL, NULL, NULL, NULL,
9513  v8::External::Wrap(&interceptor_call_count));
9514  LocalContext context;
9515  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9516  GenerateSomeGarbage();
9517  context->Global()->Set(v8_str("o"), fun->NewInstance());
9518  CompileRun(
9519  "o.foo = 17;"
9520  "var receiver = {};"
9521  "receiver.__proto__ = o;"
9522  "var result = 0;"
9523  "for (var i = 0; i < 100; i++) {"
9524  " result = receiver.method(41);"
9525  "}");
9526  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9527  CHECK_EQ(100, interceptor_call_count);
9528 }
9529 
9530 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9531  int interceptor_call_count = 0;
9532  v8::HandleScope scope;
9534  v8::Handle<v8::FunctionTemplate> method_templ =
9535  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9536  v8_str("method_data"),
9537  v8::Signature::New(fun_templ));
9538  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9539  proto_templ->Set(v8_str("method"), method_templ);
9540  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9541  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9542  NULL, NULL, NULL, NULL,
9543  v8::External::Wrap(&interceptor_call_count));
9544  LocalContext context;
9545  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9546  GenerateSomeGarbage();
9547  context->Global()->Set(v8_str("o"), fun->NewInstance());
9548  CompileRun(
9549  "o.foo = 17;"
9550  "var receiver = {};"
9551  "receiver.__proto__ = o;"
9552  "var result = 0;"
9553  "var saved_result = 0;"
9554  "for (var i = 0; i < 100; i++) {"
9555  " result = receiver.method(41);"
9556  " if (i == 50) {"
9557  " saved_result = result;"
9558  " receiver = {method: function(x) { return x - 1 }};"
9559  " }"
9560  "}");
9561  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9562  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9563  CHECK_GE(interceptor_call_count, 50);
9564 }
9565 
9566 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9567  int interceptor_call_count = 0;
9568  v8::HandleScope scope;
9570  v8::Handle<v8::FunctionTemplate> method_templ =
9571  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9572  v8_str("method_data"),
9573  v8::Signature::New(fun_templ));
9574  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9575  proto_templ->Set(v8_str("method"), method_templ);
9576  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9577  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9578  NULL, NULL, NULL, NULL,
9579  v8::External::Wrap(&interceptor_call_count));
9580  LocalContext context;
9581  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9582  GenerateSomeGarbage();
9583  context->Global()->Set(v8_str("o"), fun->NewInstance());
9584  CompileRun(
9585  "o.foo = 17;"
9586  "var receiver = {};"
9587  "receiver.__proto__ = o;"
9588  "var result = 0;"
9589  "var saved_result = 0;"
9590  "for (var i = 0; i < 100; i++) {"
9591  " result = receiver.method(41);"
9592  " if (i == 50) {"
9593  " saved_result = result;"
9594  " o.method = function(x) { return x - 1 };"
9595  " }"
9596  "}");
9597  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9598  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9599  CHECK_GE(interceptor_call_count, 50);
9600 }
9601 
9602 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9603  int interceptor_call_count = 0;
9604  v8::HandleScope scope;
9606  v8::Handle<v8::FunctionTemplate> method_templ =
9607  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9608  v8_str("method_data"),
9609  v8::Signature::New(fun_templ));
9610  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9611  proto_templ->Set(v8_str("method"), method_templ);
9612  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9613  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9614  NULL, NULL, NULL, NULL,
9615  v8::External::Wrap(&interceptor_call_count));
9616  LocalContext context;
9617  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9618  GenerateSomeGarbage();
9619  context->Global()->Set(v8_str("o"), fun->NewInstance());
9620  v8::TryCatch try_catch;
9621  CompileRun(
9622  "o.foo = 17;"
9623  "var receiver = {};"
9624  "receiver.__proto__ = o;"
9625  "var result = 0;"
9626  "var saved_result = 0;"
9627  "for (var i = 0; i < 100; i++) {"
9628  " result = receiver.method(41);"
9629  " if (i == 50) {"
9630  " saved_result = result;"
9631  " receiver = 333;"
9632  " }"
9633  "}");
9634  CHECK(try_catch.HasCaught());
9635  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9636  try_catch.Exception()->ToString());
9637  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9638  CHECK_GE(interceptor_call_count, 50);
9639 }
9640 
9641 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9642  int interceptor_call_count = 0;
9643  v8::HandleScope scope;
9645  v8::Handle<v8::FunctionTemplate> method_templ =
9646  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9647  v8_str("method_data"),
9648  v8::Signature::New(fun_templ));
9649  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9650  proto_templ->Set(v8_str("method"), method_templ);
9651  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9652  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9653  NULL, NULL, NULL, NULL,
9654  v8::External::Wrap(&interceptor_call_count));
9655  LocalContext context;
9656  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9657  GenerateSomeGarbage();
9658  context->Global()->Set(v8_str("o"), fun->NewInstance());
9659  v8::TryCatch try_catch;
9660  CompileRun(
9661  "o.foo = 17;"
9662  "var receiver = {};"
9663  "receiver.__proto__ = o;"
9664  "var result = 0;"
9665  "var saved_result = 0;"
9666  "for (var i = 0; i < 100; i++) {"
9667  " result = receiver.method(41);"
9668  " if (i == 50) {"
9669  " saved_result = result;"
9670  " receiver = {method: receiver.method};"
9671  " }"
9672  "}");
9673  CHECK(try_catch.HasCaught());
9674  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9675  try_catch.Exception()->ToString());
9676  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9677  CHECK_GE(interceptor_call_count, 50);
9678 }
9679 
9680 THREADED_TEST(CallICFastApi_TrivialSignature) {
9681  v8::HandleScope scope;
9683  v8::Handle<v8::FunctionTemplate> method_templ =
9684  v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9685  v8_str("method_data"),
9687  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9688  proto_templ->Set(v8_str("method"), method_templ);
9690  USE(templ);
9691  LocalContext context;
9692  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9693  GenerateSomeGarbage();
9694  context->Global()->Set(v8_str("o"), fun->NewInstance());
9695  CompileRun(
9696  "var result = 0;"
9697  "for (var i = 0; i < 100; i++) {"
9698  " result = o.method(41);"
9699  "}");
9700 
9701  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9702 }
9703 
9704 THREADED_TEST(CallICFastApi_SimpleSignature) {
9705  v8::HandleScope scope;
9707  v8::Handle<v8::FunctionTemplate> method_templ =
9708  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9709  v8_str("method_data"),
9710  v8::Signature::New(fun_templ));
9711  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9712  proto_templ->Set(v8_str("method"), method_templ);
9714  CHECK(!templ.IsEmpty());
9715  LocalContext context;
9716  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9717  GenerateSomeGarbage();
9718  context->Global()->Set(v8_str("o"), fun->NewInstance());
9719  CompileRun(
9720  "o.foo = 17;"
9721  "var receiver = {};"
9722  "receiver.__proto__ = o;"
9723  "var result = 0;"
9724  "for (var i = 0; i < 100; i++) {"
9725  " result = receiver.method(41);"
9726  "}");
9727 
9728  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9729 }
9730 
9731 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9732  v8::HandleScope scope;
9734  v8::Handle<v8::FunctionTemplate> method_templ =
9735  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9736  v8_str("method_data"),
9737  v8::Signature::New(fun_templ));
9738  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9739  proto_templ->Set(v8_str("method"), method_templ);
9741  CHECK(!templ.IsEmpty());
9742  LocalContext context;
9743  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9744  GenerateSomeGarbage();
9745  context->Global()->Set(v8_str("o"), fun->NewInstance());
9746  CompileRun(
9747  "o.foo = 17;"
9748  "var receiver = {};"
9749  "receiver.__proto__ = o;"
9750  "var result = 0;"
9751  "var saved_result = 0;"
9752  "for (var i = 0; i < 100; i++) {"
9753  " result = receiver.method(41);"
9754  " if (i == 50) {"
9755  " saved_result = result;"
9756  " receiver = {method: function(x) { return x - 1 }};"
9757  " }"
9758  "}");
9759  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9760  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9761 }
9762 
9763 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9764  v8::HandleScope scope;
9766  v8::Handle<v8::FunctionTemplate> method_templ =
9767  v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9768  v8_str("method_data"),
9769  v8::Signature::New(fun_templ));
9770  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9771  proto_templ->Set(v8_str("method"), method_templ);
9773  CHECK(!templ.IsEmpty());
9774  LocalContext context;
9775  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9776  GenerateSomeGarbage();
9777  context->Global()->Set(v8_str("o"), fun->NewInstance());
9778  v8::TryCatch try_catch;
9779  CompileRun(
9780  "o.foo = 17;"
9781  "var receiver = {};"
9782  "receiver.__proto__ = o;"
9783  "var result = 0;"
9784  "var saved_result = 0;"
9785  "for (var i = 0; i < 100; i++) {"
9786  " result = receiver.method(41);"
9787  " if (i == 50) {"
9788  " saved_result = result;"
9789  " receiver = 333;"
9790  " }"
9791  "}");
9792  CHECK(try_catch.HasCaught());
9793  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9794  try_catch.Exception()->ToString());
9795  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9796 }
9797 
9798 
9800 
9801 static v8::Handle<Value> InterceptorKeyedCallICGetter(
9802  Local<String> name, const AccessorInfo& info) {
9804  if (v8_str("x")->Equals(name)) {
9805  return keyed_call_ic_function;
9806  }
9807  return v8::Handle<Value>();
9808 }
9809 
9810 
9811 // Test the case when we stored cacheable lookup into
9812 // a stub, but the function name changed (to another cacheable function).
9813 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9814  v8::HandleScope scope;
9815  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9816  templ->SetNamedPropertyHandler(NoBlockGetterX);
9817  LocalContext context;
9818  context->Global()->Set(v8_str("o"), templ->NewInstance());
9819  CompileRun(
9820  "proto = new Object();"
9821  "proto.y = function(x) { return x + 1; };"
9822  "proto.z = function(x) { return x - 1; };"
9823  "o.__proto__ = proto;"
9824  "var result = 0;"
9825  "var method = 'y';"
9826  "for (var i = 0; i < 10; i++) {"
9827  " if (i == 5) { method = 'z'; };"
9828  " result += o[method](41);"
9829  "}");
9830  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9831 }
9832 
9833 
9834 // Test the case when we stored cacheable lookup into
9835 // a stub, but the function name changed (and the new function is present
9836 // both before and after the interceptor in the prototype chain).
9837 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9838  v8::HandleScope scope;
9839  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9840  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9841  LocalContext context;
9842  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9843  keyed_call_ic_function =
9844  v8_compile("function f(x) { return x - 1; }; f")->Run();
9845  CompileRun(
9846  "o = new Object();"
9847  "proto2 = new Object();"
9848  "o.y = function(x) { return x + 1; };"
9849  "proto2.y = function(x) { return x + 2; };"
9850  "o.__proto__ = proto1;"
9851  "proto1.__proto__ = proto2;"
9852  "var result = 0;"
9853  "var method = 'x';"
9854  "for (var i = 0; i < 10; i++) {"
9855  " if (i == 5) { method = 'y'; };"
9856  " result += o[method](41);"
9857  "}");
9858  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9859 }
9860 
9861 
9862 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9863 // on the global object.
9864 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9865  v8::HandleScope scope;
9866  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9867  templ->SetNamedPropertyHandler(NoBlockGetterX);
9868  LocalContext context;
9869  context->Global()->Set(v8_str("o"), templ->NewInstance());
9870  CompileRun(
9871  "function inc(x) { return x + 1; };"
9872  "inc(1);"
9873  "function dec(x) { return x - 1; };"
9874  "dec(1);"
9875  "o.__proto__ = this;"
9876  "this.__proto__.x = inc;"
9877  "this.__proto__.y = dec;"
9878  "var result = 0;"
9879  "var method = 'x';"
9880  "for (var i = 0; i < 10; i++) {"
9881  " if (i == 5) { method = 'y'; };"
9882  " result += o[method](41);"
9883  "}");
9884  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9885 }
9886 
9887 
9888 // Test the case when actual function to call sits on global object.
9889 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9890  v8::HandleScope scope;
9891  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9892  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9893  LocalContext context;
9894  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9895 
9896  CompileRun(
9897  "function len(x) { return x.length; };"
9898  "o.__proto__ = this;"
9899  "var m = 'parseFloat';"
9900  "var result = 0;"
9901  "for (var i = 0; i < 10; i++) {"
9902  " if (i == 5) {"
9903  " m = 'len';"
9904  " saved_result = result;"
9905  " };"
9906  " result = o[m]('239');"
9907  "}");
9908  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9909  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9910 }
9911 
9912 // Test the map transition before the interceptor.
9913 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9914  v8::HandleScope scope;
9915  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9916  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9917  LocalContext context;
9918  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9919 
9920  CompileRun(
9921  "var o = new Object();"
9922  "o.__proto__ = proto;"
9923  "o.method = function(x) { return x + 1; };"
9924  "var m = 'method';"
9925  "var result = 0;"
9926  "for (var i = 0; i < 10; i++) {"
9927  " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9928  " result += o[m](41);"
9929  "}");
9930  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9931 }
9932 
9933 
9934 // Test the map transition after the interceptor.
9935 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9936  v8::HandleScope scope;
9937  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9938  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9939  LocalContext context;
9940  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9941 
9942  CompileRun(
9943  "var proto = new Object();"
9944  "o.__proto__ = proto;"
9945  "proto.method = function(x) { return x + 1; };"
9946  "var m = 'method';"
9947  "var result = 0;"
9948  "for (var i = 0; i < 10; i++) {"
9949  " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9950  " result += o[m](41);"
9951  "}");
9952  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9953 }
9954 
9955 
9956 static int interceptor_call_count = 0;
9957 
9958 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9959  const AccessorInfo& info) {
9961  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9962  return call_ic_function2;
9963  }
9964  return v8::Handle<Value>();
9965 }
9966 
9967 
9968 // This test should hit load and call ICs for the interceptor case.
9969 // Once in a while, the interceptor will reply that a property was not
9970 // found in which case we should get a reference error.
9971 THREADED_TEST(InterceptorICReferenceErrors) {
9972  v8::HandleScope scope;
9973  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9974  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9975  LocalContext context(0, templ, v8::Handle<Value>());
9976  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9977  v8::Handle<Value> value = CompileRun(
9978  "function f() {"
9979  " for (var i = 0; i < 1000; i++) {"
9980  " try { x; } catch(e) { return true; }"
9981  " }"
9982  " return false;"
9983  "};"
9984  "f();");
9985  CHECK_EQ(true, value->BooleanValue());
9986  interceptor_call_count = 0;
9987  value = CompileRun(
9988  "function g() {"
9989  " for (var i = 0; i < 1000; i++) {"
9990  " try { x(42); } catch(e) { return true; }"
9991  " }"
9992  " return false;"
9993  "};"
9994  "g();");
9995  CHECK_EQ(true, value->BooleanValue());
9996 }
9997 
9998 
9999 static int interceptor_ic_exception_get_count = 0;
10000 
10001 static v8::Handle<Value> InterceptorICExceptionGetter(
10002  Local<String> name,
10003  const AccessorInfo& info) {
10005  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10006  return call_ic_function3;
10007  }
10008  if (interceptor_ic_exception_get_count == 20) {
10009  return v8::ThrowException(v8_num(42));
10010  }
10011  // Do not handle get for properties other than x.
10012  return v8::Handle<Value>();
10013 }
10014 
10015 // Test interceptor load/call IC where the interceptor throws an
10016 // exception once in a while.
10017 THREADED_TEST(InterceptorICGetterExceptions) {
10018  interceptor_ic_exception_get_count = 0;
10019  v8::HandleScope scope;
10020  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10021  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10022  LocalContext context(0, templ, v8::Handle<Value>());
10023  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10024  v8::Handle<Value> value = CompileRun(
10025  "function f() {"
10026  " for (var i = 0; i < 100; i++) {"
10027  " try { x; } catch(e) { return true; }"
10028  " }"
10029  " return false;"
10030  "};"
10031  "f();");
10032  CHECK_EQ(true, value->BooleanValue());
10033  interceptor_ic_exception_get_count = 0;
10034  value = CompileRun(
10035  "function f() {"
10036  " for (var i = 0; i < 100; i++) {"
10037  " try { x(42); } catch(e) { return true; }"
10038  " }"
10039  " return false;"
10040  "};"
10041  "f();");
10042  CHECK_EQ(true, value->BooleanValue());
10043 }
10044 
10045 
10046 static int interceptor_ic_exception_set_count = 0;
10047 
10048 static v8::Handle<Value> InterceptorICExceptionSetter(
10049  Local<String> key, Local<Value> value, const AccessorInfo&) {
10051  if (++interceptor_ic_exception_set_count > 20) {
10052  return v8::ThrowException(v8_num(42));
10053  }
10054  // Do not actually handle setting.
10055  return v8::Handle<Value>();
10056 }
10057 
10058 // Test interceptor store IC where the interceptor throws an exception
10059 // once in a while.
10060 THREADED_TEST(InterceptorICSetterExceptions) {
10061  interceptor_ic_exception_set_count = 0;
10062  v8::HandleScope scope;
10063  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10064  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10065  LocalContext context(0, templ, v8::Handle<Value>());
10066  v8::Handle<Value> value = CompileRun(
10067  "function f() {"
10068  " for (var i = 0; i < 100; i++) {"
10069  " try { x = 42; } catch(e) { return true; }"
10070  " }"
10071  " return false;"
10072  "};"
10073  "f();");
10074  CHECK_EQ(true, value->BooleanValue());
10075 }
10076 
10077 
10078 // Test that we ignore null interceptors.
10079 THREADED_TEST(NullNamedInterceptor) {
10080  v8::HandleScope scope;
10081  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10082  templ->SetNamedPropertyHandler(0);
10083  LocalContext context;
10084  templ->Set("x", v8_num(42));
10085  v8::Handle<v8::Object> obj = templ->NewInstance();
10086  context->Global()->Set(v8_str("obj"), obj);
10087  v8::Handle<Value> value = CompileRun("obj.x");
10088  CHECK(value->IsInt32());
10089  CHECK_EQ(42, value->Int32Value());
10090 }
10091 
10092 
10093 // Test that we ignore null interceptors.
10094 THREADED_TEST(NullIndexedInterceptor) {
10095  v8::HandleScope scope;
10096  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10097  templ->SetIndexedPropertyHandler(0);
10098  LocalContext context;
10099  templ->Set("42", v8_num(42));
10100  v8::Handle<v8::Object> obj = templ->NewInstance();
10101  context->Global()->Set(v8_str("obj"), obj);
10102  v8::Handle<Value> value = CompileRun("obj[42]");
10103  CHECK(value->IsInt32());
10104  CHECK_EQ(42, value->Int32Value());
10105 }
10106 
10107 
10108 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10109  v8::HandleScope scope;
10111  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10112  LocalContext env;
10113  env->Global()->Set(v8_str("obj"),
10114  templ->GetFunction()->NewInstance());
10115  ExpectTrue("obj.x === 42");
10116  ExpectTrue("!obj.propertyIsEnumerable('x')");
10117 }
10118 
10119 
10120 static Handle<Value> ThrowingGetter(Local<String> name,
10121  const AccessorInfo& info) {
10123  ThrowException(Handle<Value>());
10124  return Undefined();
10125 }
10126 
10127 
10128 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10129  HandleScope scope;
10130  LocalContext context;
10131 
10132  Local<FunctionTemplate> templ = FunctionTemplate::New();
10133  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10134  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10135 
10136  Local<Object> instance = templ->GetFunction()->NewInstance();
10137 
10138  Local<Object> another = Object::New();
10139  another->SetPrototype(instance);
10140 
10141  Local<Object> with_js_getter = CompileRun(
10142  "o = {};\n"
10143  "o.__defineGetter__('f', function() { throw undefined; });\n"
10144  "o\n").As<Object>();
10145  CHECK(!with_js_getter.IsEmpty());
10146 
10147  TryCatch try_catch;
10148 
10149  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10150  CHECK(try_catch.HasCaught());
10151  try_catch.Reset();
10152  CHECK(result.IsEmpty());
10153 
10154  result = another->GetRealNamedProperty(v8_str("f"));
10155  CHECK(try_catch.HasCaught());
10156  try_catch.Reset();
10157  CHECK(result.IsEmpty());
10158 
10159  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10160  CHECK(try_catch.HasCaught());
10161  try_catch.Reset();
10162  CHECK(result.IsEmpty());
10163 
10164  result = another->Get(v8_str("f"));
10165  CHECK(try_catch.HasCaught());
10166  try_catch.Reset();
10167  CHECK(result.IsEmpty());
10168 
10169  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10170  CHECK(try_catch.HasCaught());
10171  try_catch.Reset();
10172  CHECK(result.IsEmpty());
10173 
10174  result = with_js_getter->Get(v8_str("f"));
10175  CHECK(try_catch.HasCaught());
10176  try_catch.Reset();
10177  CHECK(result.IsEmpty());
10178 }
10179 
10180 
10181 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10182  TryCatch try_catch;
10183  // Verboseness is important: it triggers message delivery which can call into
10184  // external code.
10185  try_catch.SetVerbose(true);
10186  CompileRun("throw 'from JS';");
10187  CHECK(try_catch.HasCaught());
10188  CHECK(!i::Isolate::Current()->has_pending_exception());
10189  CHECK(!i::Isolate::Current()->has_scheduled_exception());
10190  return Undefined();
10191 }
10192 
10193 
10194 static int call_depth;
10195 
10196 
10197 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10198  TryCatch try_catch;
10199 }
10200 
10201 
10202 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10203  if (--call_depth) CompileRun("throw 'ThrowInJS';");
10204 }
10205 
10206 
10207 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10208  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
10209 }
10210 
10211 
10212 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10213  Handle<String> errorMessageString = message->Get();
10214  CHECK(!errorMessageString.IsEmpty());
10215  message->GetStackTrace();
10216  message->GetScriptResourceName();
10217 }
10218 
10219 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10220  HandleScope scope;
10221  LocalContext context;
10222 
10223  Local<Function> func =
10224  FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10225  context->Global()->Set(v8_str("func"), func);
10226 
10227  MessageCallback callbacks[] =
10228  { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10229  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10230  MessageCallback callback = callbacks[i];
10231  if (callback != NULL) {
10232  V8::AddMessageListener(callback);
10233  }
10234  // Some small number to control number of times message handler should
10235  // throw an exception.
10236  call_depth = 5;
10237  ExpectFalse(
10238  "var thrown = false;\n"
10239  "try { func(); } catch(e) { thrown = true; }\n"
10240  "thrown\n");
10241  if (callback != NULL) {
10242  V8::RemoveMessageListeners(callback);
10243  }
10244  }
10245 }
10246 
10247 
10248 static v8::Handle<Value> ParentGetter(Local<String> name,
10249  const AccessorInfo& info) {
10251  return v8_num(1);
10252 }
10253 
10254 
10255 static v8::Handle<Value> ChildGetter(Local<String> name,
10256  const AccessorInfo& info) {
10258  return v8_num(42);
10259 }
10260 
10261 
10262 THREADED_TEST(Overriding) {
10263  i::FLAG_es5_readonly = true;
10264  v8::HandleScope scope;
10265  LocalContext context;
10266 
10267  // Parent template.
10268  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10269  Local<ObjectTemplate> parent_instance_templ =
10270  parent_templ->InstanceTemplate();
10271  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10272 
10273  // Template that inherits from the parent template.
10274  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10275  Local<ObjectTemplate> child_instance_templ =
10276  child_templ->InstanceTemplate();
10277  child_templ->Inherit(parent_templ);
10278  // Override 'f'. The child version of 'f' should get called for child
10279  // instances.
10280  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10281  // Add 'g' twice. The 'g' added last should get called for instances.
10282  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10283  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10284 
10285  // Add 'h' as an accessor to the proto template with ReadOnly attributes
10286  // so 'h' can be shadowed on the instance object.
10287  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10288  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10290 
10291  // Add 'i' as an accessor to the instance template with ReadOnly attributes
10292  // but the attribute does not have effect because it is duplicated with
10293  // NULL setter.
10294  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10296 
10297 
10298 
10299  // Instantiate the child template.
10300  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10301 
10302  // Check that the child function overrides the parent one.
10303  context->Global()->Set(v8_str("o"), instance);
10304  Local<Value> value = v8_compile("o.f")->Run();
10305  // Check that the 'g' that was added last is hit.
10306  CHECK_EQ(42, value->Int32Value());
10307  value = v8_compile("o.g")->Run();
10308  CHECK_EQ(42, value->Int32Value());
10309 
10310  // Check that 'h' cannot be shadowed.
10311  value = v8_compile("o.h = 3; o.h")->Run();
10312  CHECK_EQ(1, value->Int32Value());
10313 
10314  // Check that 'i' cannot be shadowed or changed.
10315  value = v8_compile("o.i = 3; o.i")->Run();
10316  CHECK_EQ(42, value->Int32Value());
10317 }
10318 
10319 
10320 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10322  return v8::Boolean::New(args.IsConstructCall());
10323 }
10324 
10325 
10326 THREADED_TEST(IsConstructCall) {
10327  v8::HandleScope scope;
10328 
10329  // Function template with call handler.
10330  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10331  templ->SetCallHandler(IsConstructHandler);
10332 
10333  LocalContext context;
10334 
10335  context->Global()->Set(v8_str("f"), templ->GetFunction());
10336  Local<Value> value = v8_compile("f()")->Run();
10337  CHECK(!value->BooleanValue());
10338  value = v8_compile("new f()")->Run();
10339  CHECK(value->BooleanValue());
10340 }
10341 
10342 
10343 THREADED_TEST(ObjectProtoToString) {
10344  v8::HandleScope scope;
10345  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10346  templ->SetClassName(v8_str("MyClass"));
10347 
10348  LocalContext context;
10349 
10350  Local<String> customized_tostring = v8_str("customized toString");
10351 
10352  // Replace Object.prototype.toString
10353  v8_compile("Object.prototype.toString = function() {"
10354  " return 'customized toString';"
10355  "}")->Run();
10356 
10357  // Normal ToString call should call replaced Object.prototype.toString
10358  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10359  Local<String> value = instance->ToString();
10360  CHECK(value->IsString() && value->Equals(customized_tostring));
10361 
10362  // ObjectProtoToString should not call replace toString function.
10363  value = instance->ObjectProtoToString();
10364  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10365 
10366  // Check global
10367  value = context->Global()->ObjectProtoToString();
10368  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10369 
10370  // Check ordinary object
10371  Local<Value> object = v8_compile("new Object()")->Run();
10372  value = object.As<v8::Object>()->ObjectProtoToString();
10373  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10374 }
10375 
10376 
10377 THREADED_TEST(ObjectGetConstructorName) {
10378  v8::HandleScope scope;
10379  LocalContext context;
10380  v8_compile("function Parent() {};"
10381  "function Child() {};"
10382  "Child.prototype = new Parent();"
10383  "var outer = { inner: function() { } };"
10384  "var p = new Parent();"
10385  "var c = new Child();"
10386  "var x = new outer.inner();")->Run();
10387 
10388  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10389  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10390  v8_str("Parent")));
10391 
10392  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10393  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10394  v8_str("Child")));
10395 
10396  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10397  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10398  v8_str("outer.inner")));
10399 }
10400 
10401 
10402 bool ApiTestFuzzer::fuzzing_ = false;
10403 i::Semaphore* ApiTestFuzzer::all_tests_done_=
10405 int ApiTestFuzzer::active_tests_;
10406 int ApiTestFuzzer::tests_being_run_;
10407 int ApiTestFuzzer::current_;
10408 
10409 
10410 // We are in a callback and want to switch to another thread (if we
10411 // are currently running the thread fuzzing test).
10413  if (!fuzzing_) return;
10414  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10415  test->ContextSwitch();
10416 }
10417 
10418 
10419 // Let the next thread go. Since it is also waiting on the V8 lock it may
10420 // not start immediately.
10421 bool ApiTestFuzzer::NextThread() {
10422  int test_position = GetNextTestNumber();
10423  const char* test_name = RegisterThreadedTest::nth(current_)->name();
10424  if (test_position == current_) {
10425  if (kLogThreading)
10426  printf("Stay with %s\n", test_name);
10427  return false;
10428  }
10429  if (kLogThreading) {
10430  printf("Switch from %s to %s\n",
10431  test_name,
10432  RegisterThreadedTest::nth(test_position)->name());
10433  }
10434  current_ = test_position;
10435  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10436  return true;
10437 }
10438 
10439 
10441  // When it is our turn...
10442  gate_->Wait();
10443  {
10444  // ... get the V8 lock and start running the test.
10445  v8::Locker locker;
10446  CallTest();
10447  }
10448  // This test finished.
10449  active_ = false;
10450  active_tests_--;
10451  // If it was the last then signal that fact.
10452  if (active_tests_ == 0) {
10453  all_tests_done_->Signal();
10454  } else {
10455  // Otherwise select a new test and start that.
10456  NextThread();
10457  }
10458 }
10459 
10460 
10461 static unsigned linear_congruential_generator;
10462 
10463 
10465  linear_congruential_generator = i::FLAG_testing_prng_seed;
10466  fuzzing_ = true;
10467  int count = RegisterThreadedTest::count();
10468  int start = count * part / (LAST_PART + 1);
10469  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10470  active_tests_ = tests_being_run_ = end - start + 1;
10471  for (int i = 0; i < tests_being_run_; i++) {
10472  RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10473  }
10474  for (int i = 0; i < active_tests_; i++) {
10476  }
10477 }
10478 
10479 
10480 static void CallTestNumber(int test_number) {
10481  (RegisterThreadedTest::nth(test_number)->callback())();
10482 }
10483 
10484 
10486  // Set off the first test.
10487  current_ = -1;
10488  NextThread();
10489  // Wait till they are all done.
10490  all_tests_done_->Wait();
10491 }
10492 
10493 
10494 int ApiTestFuzzer::GetNextTestNumber() {
10495  int next_test;
10496  do {
10497  next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10498  linear_congruential_generator *= 1664525u;
10499  linear_congruential_generator += 1013904223u;
10500  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10501  return next_test;
10502 }
10503 
10504 
10505 void ApiTestFuzzer::ContextSwitch() {
10506  // If the new thread is the same as the current thread there is nothing to do.
10507  if (NextThread()) {
10508  // Now it can start.
10509  v8::Unlocker unlocker;
10510  // Wait till someone starts us again.
10511  gate_->Wait();
10512  // And we're off.
10513  }
10514 }
10515 
10516 
10518  fuzzing_ = false;
10519  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10521  if (fuzzer != NULL) fuzzer->Join();
10522  }
10523 }
10524 
10525 
10526 // Lets not be needlessly self-referential.
10527 TEST(Threading) {
10531 }
10532 
10533 TEST(Threading2) {
10537 }
10538 
10539 TEST(Threading3) {
10543 }
10544 
10545 TEST(Threading4) {
10549 }
10550 
10552  if (kLogThreading)
10553  printf("Start test %d\n", test_number_);
10554  CallTestNumber(test_number_);
10555  if (kLogThreading)
10556  printf("End test %d\n", test_number_);
10557 }
10558 
10559 
10560 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10563  v8::Unlocker unlocker;
10564  const char* code = "throw 7;";
10565  {
10566  v8::Locker nested_locker;
10567  v8::HandleScope scope;
10568  v8::Handle<Value> exception;
10569  { v8::TryCatch try_catch;
10570  v8::Handle<Value> value = CompileRun(code);
10571  CHECK(value.IsEmpty());
10572  CHECK(try_catch.HasCaught());
10573  // Make sure to wrap the exception in a new handle because
10574  // the handle returned from the TryCatch is destroyed
10575  // when the TryCatch is destroyed.
10576  exception = Local<Value>::New(try_catch.Exception());
10577  }
10578  return v8::ThrowException(exception);
10579  }
10580 }
10581 
10582 
10583 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10586  v8::Unlocker unlocker;
10587  const char* code = "throw 7;";
10588  {
10589  v8::Locker nested_locker;
10590  v8::HandleScope scope;
10591  v8::Handle<Value> value = CompileRun(code);
10592  CHECK(value.IsEmpty());
10593  return v8_str("foo");
10594  }
10595 }
10596 
10597 
10598 // These are locking tests that don't need to be run again
10599 // as part of the locking aggregation tests.
10600 TEST(NestedLockers) {
10601  v8::Locker locker;
10603  v8::HandleScope scope;
10604  LocalContext env;
10605  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10606  Local<Function> fun = fun_templ->GetFunction();
10607  env->Global()->Set(v8_str("throw_in_js"), fun);
10608  Local<Script> script = v8_compile("(function () {"
10609  " try {"
10610  " throw_in_js();"
10611  " return 42;"
10612  " } catch (e) {"
10613  " return e * 13;"
10614  " }"
10615  "})();");
10616  CHECK_EQ(91, script->Run()->Int32Value());
10617 }
10618 
10619 
10620 // These are locking tests that don't need to be run again
10621 // as part of the locking aggregation tests.
10622 TEST(NestedLockersNoTryCatch) {
10623  v8::Locker locker;
10624  v8::HandleScope scope;
10625  LocalContext env;
10626  Local<v8::FunctionTemplate> fun_templ =
10627  v8::FunctionTemplate::New(ThrowInJSNoCatch);
10628  Local<Function> fun = fun_templ->GetFunction();
10629  env->Global()->Set(v8_str("throw_in_js"), fun);
10630  Local<Script> script = v8_compile("(function () {"
10631  " try {"
10632  " throw_in_js();"
10633  " return 42;"
10634  " } catch (e) {"
10635  " return e * 13;"
10636  " }"
10637  "})();");
10638  CHECK_EQ(91, script->Run()->Int32Value());
10639 }
10640 
10641 
10642 THREADED_TEST(RecursiveLocking) {
10643  v8::Locker locker;
10644  {
10645  v8::Locker locker2;
10647  }
10648 }
10649 
10650 
10651 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10653  v8::Unlocker unlocker;
10654  return v8::Undefined();
10655 }
10656 
10657 
10658 THREADED_TEST(LockUnlockLock) {
10659  {
10660  v8::Locker locker;
10661  v8::HandleScope scope;
10662  LocalContext env;
10663  Local<v8::FunctionTemplate> fun_templ =
10664  v8::FunctionTemplate::New(UnlockForAMoment);
10665  Local<Function> fun = fun_templ->GetFunction();
10666  env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10667  Local<Script> script = v8_compile("(function () {"
10668  " unlock_for_a_moment();"
10669  " return 42;"
10670  "})();");
10671  CHECK_EQ(42, script->Run()->Int32Value());
10672  }
10673  {
10674  v8::Locker locker;
10675  v8::HandleScope scope;
10676  LocalContext env;
10677  Local<v8::FunctionTemplate> fun_templ =
10678  v8::FunctionTemplate::New(UnlockForAMoment);
10679  Local<Function> fun = fun_templ->GetFunction();
10680  env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10681  Local<Script> script = v8_compile("(function () {"
10682  " unlock_for_a_moment();"
10683  " return 42;"
10684  "})();");
10685  CHECK_EQ(42, script->Run()->Int32Value());
10686  }
10687 }
10688 
10689 
10690 static int GetGlobalObjectsCount() {
10691  i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10692  int count = 0;
10693  i::HeapIterator it;
10694  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10695  if (object->IsJSGlobalObject()) count++;
10696  return count;
10697 }
10698 
10699 
10700 static void CheckSurvivingGlobalObjectsCount(int expected) {
10701  // We need to collect all garbage twice to be sure that everything
10702  // has been collected. This is because inline caches are cleared in
10703  // the first garbage collection but some of the maps have already
10704  // been marked at that point. Therefore some of the maps are not
10705  // collected until the second garbage collection.
10706  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10707  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10708  int count = GetGlobalObjectsCount();
10709 #ifdef DEBUG
10710  if (count != expected) HEAP->TracePathToGlobal();
10711 #endif
10712  CHECK_EQ(expected, count);
10713 }
10714 
10715 
10716 TEST(DontLeakGlobalObjects) {
10717  // Regression test for issues 1139850 and 1174891.
10718 
10720 
10721  for (int i = 0; i < 5; i++) {
10722  { v8::HandleScope scope;
10723  LocalContext context;
10724  }
10725  CheckSurvivingGlobalObjectsCount(0);
10726 
10727  { v8::HandleScope scope;
10728  LocalContext context;
10729  v8_compile("Date")->Run();
10730  }
10731  CheckSurvivingGlobalObjectsCount(0);
10732 
10733  { v8::HandleScope scope;
10734  LocalContext context;
10735  v8_compile("/aaa/")->Run();
10736  }
10737  CheckSurvivingGlobalObjectsCount(0);
10738 
10739  { v8::HandleScope scope;
10740  const char* extension_list[] = { "v8/gc" };
10741  v8::ExtensionConfiguration extensions(1, extension_list);
10742  LocalContext context(&extensions);
10743  v8_compile("gc();")->Run();
10744  }
10745  CheckSurvivingGlobalObjectsCount(0);
10746  }
10747 }
10748 
10749 
10752 
10754  v8::HandleScope scope;
10755  bad_handle = v8::Persistent<v8::Object>::New(some_object);
10756  handle.Dispose();
10757 }
10758 
10759 
10760 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10761  LocalContext context;
10762 
10763  v8::Persistent<v8::Object> handle1, handle2;
10764  {
10765  v8::HandleScope scope;
10769  }
10770  // Note: order is implementation dependent alas: currently
10771  // global handle nodes are processed by PostGarbageCollectionProcessing
10772  // in reverse allocation order, so if second allocated handle is deleted,
10773  // weak callback of the first handle would be able to 'reallocate' it.
10775  handle2.Dispose();
10776  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10777 }
10778 
10779 
10781 
10783  to_be_disposed.Dispose();
10784  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10785  handle.Dispose();
10786 }
10787 
10788 
10789 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10790  LocalContext context;
10791 
10792  v8::Persistent<v8::Object> handle1, handle2;
10793  {
10794  v8::HandleScope scope;
10797  }
10799  to_be_disposed = handle2;
10800  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10801 }
10802 
10804  handle.Dispose();
10805 }
10806 
10808  v8::HandleScope scope;
10810  handle.Dispose();
10811 }
10812 
10813 
10814 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10815  LocalContext context;
10816 
10817  v8::Persistent<v8::Object> handle1, handle2, handle3;
10818  {
10819  v8::HandleScope scope;
10823  }
10824  handle2.MakeWeak(NULL, DisposingCallback);
10826  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10827 }
10828 
10829 
10830 THREADED_TEST(CheckForCrossContextObjectLiterals) {
10832 
10833  const int nof = 2;
10834  const char* sources[nof] = {
10835  "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10836  "Object()"
10837  };
10838 
10839  for (int i = 0; i < nof; i++) {
10840  const char* source = sources[i];
10841  { v8::HandleScope scope;
10842  LocalContext context;
10843  CompileRun(source);
10844  }
10845  { v8::HandleScope scope;
10846  LocalContext context;
10847  CompileRun(source);
10848  }
10849  }
10850 }
10851 
10852 
10853 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10854  v8::HandleScope inner;
10855  env->Enter();
10856  v8::Handle<Value> three = v8_num(3);
10857  v8::Handle<Value> value = inner.Close(three);
10858  env->Exit();
10859  return value;
10860 }
10861 
10862 
10863 THREADED_TEST(NestedHandleScopeAndContexts) {
10864  v8::HandleScope outer;
10865  v8::Persistent<Context> env = Context::New();
10866  env->Enter();
10867  v8::Handle<Value> value = NestedScope(env);
10868  v8::Handle<String> str(value->ToString());
10869  CHECK(!str.IsEmpty());
10870  env->Exit();
10871  env.Dispose();
10872 }
10873 
10874 
10875 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
10876 
10877 
10878 THREADED_TEST(ExternalAllocatedMemory) {
10879  v8::HandleScope outer;
10880  v8::Persistent<Context> env(Context::New());
10881  CHECK(!env.IsEmpty());
10882  const intptr_t kSize = 1024*1024;
10884  cast(kSize));
10886  cast(0));
10887 }
10888 
10889 
10890 THREADED_TEST(DisposeEnteredContext) {
10891  v8::HandleScope scope;
10892  LocalContext outer;
10894  inner->Enter();
10895  inner.Dispose();
10896  inner.Clear();
10897  inner->Exit();
10898  }
10899 }
10900 
10901 
10902 // Regression test for issue 54, object templates with internal fields
10903 // but no accessors or interceptors did not get their internal field
10904 // count set on instances.
10905 THREADED_TEST(Regress54) {
10906  v8::HandleScope outer;
10907  LocalContext context;
10909  if (templ.IsEmpty()) {
10910  v8::HandleScope inner;
10912  local->SetInternalFieldCount(1);
10913  templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10914  }
10915  v8::Handle<v8::Object> result = templ->NewInstance();
10916  CHECK_EQ(1, result->InternalFieldCount());
10917 }
10918 
10919 
10920 // If part of the threaded tests, this test makes ThreadingTest fail
10921 // on mac.
10922 TEST(CatchStackOverflow) {
10923  v8::HandleScope scope;
10924  LocalContext context;
10925  v8::TryCatch try_catch;
10927  "function f() {"
10928  " return f();"
10929  "}"
10930  ""
10931  "f();"));
10932  v8::Handle<v8::Value> result = script->Run();
10933  CHECK(result.IsEmpty());
10934 }
10935 
10936 
10937 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10938  const char* resource_name,
10939  int line_offset) {
10940  v8::HandleScope scope;
10941  v8::TryCatch try_catch;
10942  v8::Handle<v8::Value> result = script->Run();
10943  CHECK(result.IsEmpty());
10944  CHECK(try_catch.HasCaught());
10945  v8::Handle<v8::Message> message = try_catch.Message();
10946  CHECK(!message.IsEmpty());
10947  CHECK_EQ(10 + line_offset, message->GetLineNumber());
10948  CHECK_EQ(91, message->GetStartPosition());
10949  CHECK_EQ(92, message->GetEndPosition());
10950  CHECK_EQ(2, message->GetStartColumn());
10951  CHECK_EQ(3, message->GetEndColumn());
10952  v8::String::AsciiValue line(message->GetSourceLine());
10953  CHECK_EQ(" throw 'nirk';", *line);
10954  v8::String::AsciiValue name(message->GetScriptResourceName());
10955  CHECK_EQ(resource_name, *name);
10956 }
10957 
10958 
10959 THREADED_TEST(TryCatchSourceInfo) {
10960  v8::HandleScope scope;
10961  LocalContext context;
10963  "function Foo() {\n"
10964  " return Bar();\n"
10965  "}\n"
10966  "\n"
10967  "function Bar() {\n"
10968  " return Baz();\n"
10969  "}\n"
10970  "\n"
10971  "function Baz() {\n"
10972  " throw 'nirk';\n"
10973  "}\n"
10974  "\n"
10975  "Foo();\n");
10976 
10977  const char* resource_name;
10978  v8::Handle<v8::Script> script;
10979  resource_name = "test.js";
10980  script = v8::Script::Compile(source, v8::String::New(resource_name));
10981  CheckTryCatchSourceInfo(script, resource_name, 0);
10982 
10983  resource_name = "test1.js";
10984  v8::ScriptOrigin origin1(v8::String::New(resource_name));
10985  script = v8::Script::Compile(source, &origin1);
10986  CheckTryCatchSourceInfo(script, resource_name, 0);
10987 
10988  resource_name = "test2.js";
10989  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10990  script = v8::Script::Compile(source, &origin2);
10991  CheckTryCatchSourceInfo(script, resource_name, 7);
10992 }
10993 
10994 
10995 THREADED_TEST(CompilationCache) {
10996  v8::HandleScope scope;
10997  LocalContext context;
10998  v8::Handle<v8::String> source0 = v8::String::New("1234");
10999  v8::Handle<v8::String> source1 = v8::String::New("1234");
11000  v8::Handle<v8::Script> script0 =
11001  v8::Script::Compile(source0, v8::String::New("test.js"));
11002  v8::Handle<v8::Script> script1 =
11003  v8::Script::Compile(source1, v8::String::New("test.js"));
11004  v8::Handle<v8::Script> script2 =
11005  v8::Script::Compile(source0); // different origin
11006  CHECK_EQ(1234, script0->Run()->Int32Value());
11007  CHECK_EQ(1234, script1->Run()->Int32Value());
11008  CHECK_EQ(1234, script2->Run()->Int32Value());
11009 }
11010 
11011 
11012 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11014  return v8_num(42);
11015 }
11016 
11017 
11018 THREADED_TEST(CallbackFunctionName) {
11019  v8::HandleScope scope;
11020  LocalContext context;
11021  Local<ObjectTemplate> t = ObjectTemplate::New();
11022  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11023  context->Global()->Set(v8_str("obj"), t->NewInstance());
11024  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11025  CHECK(value->IsString());
11027  CHECK_EQ("asdf", *name);
11028 }
11029 
11030 
11031 THREADED_TEST(DateAccess) {
11032  v8::HandleScope scope;
11033  LocalContext context;
11034  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11035  CHECK(date->IsDate());
11036  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
11037 }
11038 
11039 
11040 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
11041  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11042  v8::Handle<v8::Array> props = obj->GetPropertyNames();
11043  CHECK_EQ(elmc, props->Length());
11044  for (int i = 0; i < elmc; i++) {
11045  v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11046  CHECK_EQ(elmv[i], *elm);
11047  }
11048 }
11049 
11050 
11052  int elmc,
11053  const char* elmv[]) {
11054  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11056  CHECK_EQ(elmc, props->Length());
11057  for (int i = 0; i < elmc; i++) {
11058  v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11059  CHECK_EQ(elmv[i], *elm);
11060  }
11061 }
11062 
11063 
11064 THREADED_TEST(PropertyEnumeration) {
11065  v8::HandleScope scope;
11066  LocalContext context;
11068  "var result = [];"
11069  "result[0] = {};"
11070  "result[1] = {a: 1, b: 2};"
11071  "result[2] = [1, 2, 3];"
11072  "var proto = {x: 1, y: 2, z: 3};"
11073  "var x = { __proto__: proto, w: 0, z: 1 };"
11074  "result[3] = x;"
11075  "result;"))->Run();
11076  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11077  CHECK_EQ(4, elms->Length());
11078  int elmc0 = 0;
11079  const char** elmv0 = NULL;
11080  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11081  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11082  int elmc1 = 2;
11083  const char* elmv1[] = {"a", "b"};
11084  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11085  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11086  int elmc2 = 3;
11087  const char* elmv2[] = {"0", "1", "2"};
11088  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11089  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11090  int elmc3 = 4;
11091  const char* elmv3[] = {"w", "z", "x", "y"};
11092  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
11093  int elmc4 = 2;
11094  const char* elmv4[] = {"w", "z"};
11095  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
11096 }
11097 
11098 THREADED_TEST(PropertyEnumeration2) {
11099  v8::HandleScope scope;
11100  LocalContext context;
11102  "var result = [];"
11103  "result[0] = {};"
11104  "result[1] = {a: 1, b: 2};"
11105  "result[2] = [1, 2, 3];"
11106  "var proto = {x: 1, y: 2, z: 3};"
11107  "var x = { __proto__: proto, w: 0, z: 1 };"
11108  "result[3] = x;"
11109  "result;"))->Run();
11110  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11111  CHECK_EQ(4, elms->Length());
11112  int elmc0 = 0;
11113  const char** elmv0 = NULL;
11114  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11115 
11116  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11117  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11118  CHECK_EQ(0, props->Length());
11119  for (uint32_t i = 0; i < props->Length(); i++) {
11120  printf("p[%d]\n", i);
11121  }
11122 }
11123 
11124 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11125  Local<Value> name,
11126  v8::AccessType type,
11127  Local<Value> data) {
11128  return type != v8::ACCESS_SET;
11129 }
11130 
11131 
11132 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11133  uint32_t key,
11134  v8::AccessType type,
11135  Local<Value> data) {
11136  return type != v8::ACCESS_SET;
11137 }
11138 
11139 
11140 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11141  v8::HandleScope scope;
11142  LocalContext context;
11143  Local<ObjectTemplate> templ = ObjectTemplate::New();
11144  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11145  IndexedSetAccessBlocker);
11146  templ->Set(v8_str("x"), v8::True());
11147  Local<v8::Object> instance = templ->NewInstance();
11148  context->Global()->Set(v8_str("obj"), instance);
11149  Local<Value> value = CompileRun("obj.x");
11150  CHECK(value->BooleanValue());
11151 }
11152 
11153 
11154 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11155  Local<Value> name,
11156  v8::AccessType type,
11157  Local<Value> data) {
11158  return false;
11159 }
11160 
11161 
11162 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11163  uint32_t key,
11164  v8::AccessType type,
11165  Local<Value> data) {
11166  return false;
11167 }
11168 
11169 
11170 
11171 THREADED_TEST(AccessChecksReenabledCorrectly) {
11172  v8::HandleScope scope;
11173  LocalContext context;
11174  Local<ObjectTemplate> templ = ObjectTemplate::New();
11175  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11176  IndexedGetAccessBlocker);
11177  templ->Set(v8_str("a"), v8_str("a"));
11178  // Add more than 8 (see kMaxFastProperties) properties
11179  // so that the constructor will force copying map.
11180  // Cannot sprintf, gcc complains unsafety.
11181  char buf[4];
11182  for (char i = '0'; i <= '9' ; i++) {
11183  buf[0] = i;
11184  for (char j = '0'; j <= '9'; j++) {
11185  buf[1] = j;
11186  for (char k = '0'; k <= '9'; k++) {
11187  buf[2] = k;
11188  buf[3] = 0;
11189  templ->Set(v8_str(buf), v8::Number::New(k));
11190  }
11191  }
11192  }
11193 
11194  Local<v8::Object> instance_1 = templ->NewInstance();
11195  context->Global()->Set(v8_str("obj_1"), instance_1);
11196 
11197  Local<Value> value_1 = CompileRun("obj_1.a");
11198  CHECK(value_1->IsUndefined());
11199 
11200  Local<v8::Object> instance_2 = templ->NewInstance();
11201  context->Global()->Set(v8_str("obj_2"), instance_2);
11202 
11203  Local<Value> value_2 = CompileRun("obj_2.a");
11204  CHECK(value_2->IsUndefined());
11205 }
11206 
11207 
11208 // This tests that access check information remains on the global
11209 // object template when creating contexts.
11210 THREADED_TEST(AccessControlRepeatedContextCreation) {
11211  v8::HandleScope handle_scope;
11213  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11214  IndexedSetAccessBlocker);
11215  i::Handle<i::ObjectTemplateInfo> internal_template =
11216  v8::Utils::OpenHandle(*global_template);
11217  CHECK(!internal_template->constructor()->IsUndefined());
11219  i::FunctionTemplateInfo::cast(internal_template->constructor()));
11220  CHECK(!constructor->access_check_info()->IsUndefined());
11221  v8::Persistent<Context> context0(Context::New(NULL, global_template));
11222  CHECK(!context0.IsEmpty());
11223  CHECK(!constructor->access_check_info()->IsUndefined());
11224 }
11225 
11226 
11227 THREADED_TEST(TurnOnAccessCheck) {
11228  v8::HandleScope handle_scope;
11229 
11230  // Create an environment with access check to the global object disabled by
11231  // default.
11233  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11234  IndexedGetAccessBlocker,
11236  false);
11237  v8::Persistent<Context> context = Context::New(NULL, global_template);
11238  Context::Scope context_scope(context);
11239 
11240  // Set up a property and a number of functions.
11241  context->Global()->Set(v8_str("a"), v8_num(1));
11242  CompileRun("function f1() {return a;}"
11243  "function f2() {return a;}"
11244  "function g1() {return h();}"
11245  "function g2() {return h();}"
11246  "function h() {return 1;}");
11247  Local<Function> f1 =
11248  Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11249  Local<Function> f2 =
11250  Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11251  Local<Function> g1 =
11252  Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11253  Local<Function> g2 =
11254  Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11255  Local<Function> h =
11256  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11257 
11258  // Get the global object.
11259  v8::Handle<v8::Object> global = context->Global();
11260 
11261  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11262  // uses the runtime system to retreive property a whereas f2 uses global load
11263  // inline cache.
11264  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11265  for (int i = 0; i < 4; i++) {
11266  CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11267  }
11268 
11269  // Same for g1 and g2.
11270  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11271  for (int i = 0; i < 4; i++) {
11272  CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11273  }
11274 
11275  // Detach the global and turn on access check.
11276  context->DetachGlobal();
11277  context->Global()->TurnOnAccessCheck();
11278 
11279  // Failing access check to property get results in undefined.
11280  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11281  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11282 
11283  // Failing access check to function call results in exception.
11284  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11285  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11286 
11287  // No failing access check when just returning a constant.
11288  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11289 }
11290 
11291 
11292 static const char* kPropertyA = "a";
11293 static const char* kPropertyH = "h";
11294 
11295 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11296  Local<Value> name,
11297  v8::AccessType type,
11298  Local<Value> data) {
11299  if (!name->IsString()) return false;
11300  i::Handle<i::String> name_handle =
11301  v8::Utils::OpenHandle(String::Cast(*name));
11302  return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11303  && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
11304 }
11305 
11306 
11307 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11308  v8::HandleScope handle_scope;
11309 
11310  // Create an environment with access check to the global object disabled by
11311  // default. When the registered access checker will block access to properties
11312  // a and h.
11314  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11315  IndexedGetAccessBlocker,
11317  false);
11318  v8::Persistent<Context> context = Context::New(NULL, global_template);
11319  Context::Scope context_scope(context);
11320 
11321  // Set up a property and a number of functions.
11322  context->Global()->Set(v8_str("a"), v8_num(1));
11323  static const char* source = "function f1() {return a;}"
11324  "function f2() {return a;}"
11325  "function g1() {return h();}"
11326  "function g2() {return h();}"
11327  "function h() {return 1;}";
11328 
11329  CompileRun(source);
11330  Local<Function> f1;
11331  Local<Function> f2;
11332  Local<Function> g1;
11333  Local<Function> g2;
11334  Local<Function> h;
11335  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11336  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11337  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11338  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11339  h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11340 
11341  // Get the global object.
11342  v8::Handle<v8::Object> global = context->Global();
11343 
11344  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11345  // uses the runtime system to retreive property a whereas f2 uses global load
11346  // inline cache.
11347  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11348  for (int i = 0; i < 4; i++) {
11349  CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11350  }
11351 
11352  // Same for g1 and g2.
11353  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11354  for (int i = 0; i < 4; i++) {
11355  CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11356  }
11357 
11358  // Detach the global and turn on access check now blocking access to property
11359  // a and function h.
11360  context->DetachGlobal();
11361  context->Global()->TurnOnAccessCheck();
11362 
11363  // Failing access check to property get results in undefined.
11364  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11365  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11366 
11367  // Failing access check to function call results in exception.
11368  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11369  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11370 
11371  // No failing access check when just returning a constant.
11372  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11373 
11374  // Now compile the source again. And get the newly compiled functions, except
11375  // for h for which access is blocked.
11376  CompileRun(source);
11377  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11378  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11379  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11380  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11381  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11382 
11383  // Failing access check to property get results in undefined.
11384  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11385  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11386 
11387  // Failing access check to function call results in exception.
11388  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11389  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11390 }
11391 
11392 
11393 // This test verifies that pre-compilation (aka preparsing) can be called
11394 // without initializing the whole VM. Thus we cannot run this test in a
11395 // multi-threaded setup.
11396 TEST(PreCompile) {
11397  // TODO(155): This test would break without the initialization of V8. This is
11398  // a workaround for now to make this test not fail.
11400  const char* script = "function foo(a) { return a+1; }";
11401  v8::ScriptData* sd =
11402  v8::ScriptData::PreCompile(script, i::StrLength(script));
11403  CHECK_NE(sd->Length(), 0);
11404  CHECK_NE(sd->Data(), NULL);
11405  CHECK(!sd->HasError());
11406  delete sd;
11407 }
11408 
11409 
11410 TEST(PreCompileWithError) {
11412  const char* script = "function foo(a) { return 1 * * 2; }";
11413  v8::ScriptData* sd =
11414  v8::ScriptData::PreCompile(script, i::StrLength(script));
11415  CHECK(sd->HasError());
11416  delete sd;
11417 }
11418 
11419 
11420 TEST(Regress31661) {
11422  const char* script = " The Definintive Guide";
11423  v8::ScriptData* sd =
11424  v8::ScriptData::PreCompile(script, i::StrLength(script));
11425  CHECK(sd->HasError());
11426  delete sd;
11427 }
11428 
11429 
11430 // Tests that ScriptData can be serialized and deserialized.
11431 TEST(PreCompileSerialization) {
11433  const char* script = "function foo(a) { return a+1; }";
11434  v8::ScriptData* sd =
11435  v8::ScriptData::PreCompile(script, i::StrLength(script));
11436 
11437  // Serialize.
11438  int serialized_data_length = sd->Length();
11439  char* serialized_data = i::NewArray<char>(serialized_data_length);
11440  memcpy(serialized_data, sd->Data(), serialized_data_length);
11441 
11442  // Deserialize.
11443  v8::ScriptData* deserialized_sd =
11444  v8::ScriptData::New(serialized_data, serialized_data_length);
11445 
11446  // Verify that the original is the same as the deserialized.
11447  CHECK_EQ(sd->Length(), deserialized_sd->Length());
11448  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11449  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11450 
11451  delete sd;
11452  delete deserialized_sd;
11453 }
11454 
11455 
11456 // Attempts to deserialize bad data.
11457 TEST(PreCompileDeserializationError) {
11459  const char* data = "DONT CARE";
11460  int invalid_size = 3;
11461  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11462 
11463  CHECK_EQ(0, sd->Length());
11464 
11465  delete sd;
11466 }
11467 
11468 
11469 // Attempts to deserialize bad data.
11470 TEST(PreCompileInvalidPreparseDataError) {
11472  v8::HandleScope scope;
11473  LocalContext context;
11474 
11475  const char* script = "function foo(){ return 5;}\n"
11476  "function bar(){ return 6 + 7;} foo();";
11477  v8::ScriptData* sd =
11478  v8::ScriptData::PreCompile(script, i::StrLength(script));
11479  CHECK(!sd->HasError());
11480  // ScriptDataImpl private implementation details
11481  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11482  const int kFunctionEntrySize = i::FunctionEntry::kSize;
11483  const int kFunctionEntryStartOffset = 0;
11484  const int kFunctionEntryEndOffset = 1;
11485  unsigned* sd_data =
11486  reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11487 
11488  // Overwrite function bar's end position with 0.
11489  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11490  v8::TryCatch try_catch;
11491 
11492  Local<String> source = String::New(script);
11493  Local<Script> compiled_script = Script::New(source, NULL, sd);
11494  CHECK(try_catch.HasCaught());
11495  String::AsciiValue exception_value(try_catch.Message()->Get());
11496  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11497  *exception_value);
11498 
11499  try_catch.Reset();
11500 
11501  // Overwrite function bar's start position with 200. The function entry
11502  // will not be found when searching for it by position and we should fall
11503  // back on eager compilation.
11504  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11505  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11506  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11507  200;
11508  compiled_script = Script::New(source, NULL, sd);
11509  CHECK(!try_catch.HasCaught());
11510 
11511  delete sd;
11512 }
11513 
11514 
11515 // Verifies that the Handle<String> and const char* versions of the API produce
11516 // the same results (at least for one trivial case).
11517 TEST(PreCompileAPIVariationsAreSame) {
11519  v8::HandleScope scope;
11520 
11521  const char* cstring = "function foo(a) { return a+1; }";
11522 
11523  v8::ScriptData* sd_from_cstring =
11524  v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11525 
11526  TestAsciiResource* resource = new TestAsciiResource(cstring);
11527  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
11528  v8::String::NewExternal(resource));
11529 
11530  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11531  v8::String::New(cstring));
11532 
11533  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
11534  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11535  sd_from_external_string->Data(),
11536  sd_from_cstring->Length()));
11537 
11538  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11539  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11540  sd_from_string->Data(),
11541  sd_from_cstring->Length()));
11542 
11543 
11544  delete sd_from_cstring;
11545  delete sd_from_external_string;
11546  delete sd_from_string;
11547 }
11548 
11549 
11550 // This tests that we do not allow dictionary load/call inline caches
11551 // to use functions that have not yet been compiled. The potential
11552 // problem of loading a function that has not yet been compiled can
11553 // arise because we share code between contexts via the compilation
11554 // cache.
11555 THREADED_TEST(DictionaryICLoadedFunction) {
11556  v8::HandleScope scope;
11557  // Test LoadIC.
11558  for (int i = 0; i < 2; i++) {
11559  LocalContext context;
11560  context->Global()->Set(v8_str("tmp"), v8::True());
11561  context->Global()->Delete(v8_str("tmp"));
11562  CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11563  }
11564  // Test CallIC.
11565  for (int i = 0; i < 2; i++) {
11566  LocalContext context;
11567  context->Global()->Set(v8_str("tmp"), v8::True());
11568  context->Global()->Delete(v8_str("tmp"));
11569  CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11570  }
11571 }
11572 
11573 
11574 // Test that cross-context new calls use the context of the callee to
11575 // create the new JavaScript object.
11576 THREADED_TEST(CrossContextNew) {
11577  v8::HandleScope scope;
11578  v8::Persistent<Context> context0 = Context::New();
11579  v8::Persistent<Context> context1 = Context::New();
11580 
11581  // Allow cross-domain access.
11582  Local<String> token = v8_str("<security token>");
11583  context0->SetSecurityToken(token);
11584  context1->SetSecurityToken(token);
11585 
11586  // Set an 'x' property on the Object prototype and define a
11587  // constructor function in context0.
11588  context0->Enter();
11589  CompileRun("Object.prototype.x = 42; function C() {};");
11590  context0->Exit();
11591 
11592  // Call the constructor function from context0 and check that the
11593  // result has the 'x' property.
11594  context1->Enter();
11595  context1->Global()->Set(v8_str("other"), context0->Global());
11596  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11597  CHECK(value->IsInt32());
11598  CHECK_EQ(42, value->Int32Value());
11599  context1->Exit();
11600 
11601  // Dispose the contexts to allow them to be garbage collected.
11602  context0.Dispose();
11603  context1.Dispose();
11604 }
11605 
11606 
11608  public:
11609  RegExpInterruptTest() : block_(NULL) {}
11610  ~RegExpInterruptTest() { delete block_; }
11611  void RunTest() {
11612  block_ = i::OS::CreateSemaphore(0);
11613  gc_count_ = 0;
11614  gc_during_regexp_ = 0;
11615  regexp_success_ = false;
11616  gc_success_ = false;
11617  GCThread gc_thread(this);
11618  gc_thread.Start();
11620 
11621  LongRunningRegExp();
11622  {
11623  v8::Unlocker unlock;
11624  gc_thread.Join();
11625  }
11627  CHECK(regexp_success_);
11628  CHECK(gc_success_);
11629  }
11630 
11631  private:
11632  // Number of garbage collections required.
11633  static const int kRequiredGCs = 5;
11634 
11635  class GCThread : public i::Thread {
11636  public:
11637  explicit GCThread(RegExpInterruptTest* test)
11638  : Thread("GCThread"), test_(test) {}
11639  virtual void Run() {
11640  test_->CollectGarbage();
11641  }
11642  private:
11643  RegExpInterruptTest* test_;
11644  };
11645 
11646  void CollectGarbage() {
11647  block_->Wait();
11648  while (gc_during_regexp_ < kRequiredGCs) {
11649  {
11650  v8::Locker lock;
11651  // TODO(lrn): Perhaps create some garbage before collecting.
11652  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11653  gc_count_++;
11654  }
11655  i::OS::Sleep(1);
11656  }
11657  gc_success_ = true;
11658  }
11659 
11660  void LongRunningRegExp() {
11661  block_->Signal(); // Enable garbage collection thread on next preemption.
11662  int rounds = 0;
11663  while (gc_during_regexp_ < kRequiredGCs) {
11664  int gc_before = gc_count_;
11665  {
11666  // Match 15-30 "a"'s against 14 and a "b".
11667  const char* c_source =
11668  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11669  ".exec('aaaaaaaaaaaaaaab') === null";
11670  Local<String> source = String::New(c_source);
11671  Local<Script> script = Script::Compile(source);
11672  Local<Value> result = script->Run();
11673  if (!result->BooleanValue()) {
11674  gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11675  return;
11676  }
11677  }
11678  {
11679  // Match 15-30 "a"'s against 15 and a "b".
11680  const char* c_source =
11681  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11682  ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11683  Local<String> source = String::New(c_source);
11684  Local<Script> script = Script::Compile(source);
11685  Local<Value> result = script->Run();
11686  if (!result->BooleanValue()) {
11687  gc_during_regexp_ = kRequiredGCs;
11688  return;
11689  }
11690  }
11691  int gc_after = gc_count_;
11692  gc_during_regexp_ += gc_after - gc_before;
11693  rounds++;
11694  i::OS::Sleep(1);
11695  }
11696  regexp_success_ = true;
11697  }
11698 
11699  i::Semaphore* block_;
11700  int gc_count_;
11701  int gc_during_regexp_;
11702  bool regexp_success_;
11703  bool gc_success_;
11704 };
11705 
11706 
11707 // Test that a regular expression execution can be interrupted and
11708 // survive a garbage collection.
11709 TEST(RegExpInterruption) {
11710  v8::Locker lock;
11712  v8::HandleScope scope;
11713  Local<Context> local_env;
11714  {
11715  LocalContext env;
11716  local_env = env.local();
11717  }
11718 
11719  // Local context should still be live.
11720  CHECK(!local_env.IsEmpty());
11721  local_env->Enter();
11722 
11723  // Should complete without problems.
11725 
11726  local_env->Exit();
11727 }
11728 
11729 
11731  public:
11732  ApplyInterruptTest() : block_(NULL) {}
11733  ~ApplyInterruptTest() { delete block_; }
11734  void RunTest() {
11735  block_ = i::OS::CreateSemaphore(0);
11736  gc_count_ = 0;
11737  gc_during_apply_ = 0;
11738  apply_success_ = false;
11739  gc_success_ = false;
11740  GCThread gc_thread(this);
11741  gc_thread.Start();
11743 
11744  LongRunningApply();
11745  {
11746  v8::Unlocker unlock;
11747  gc_thread.Join();
11748  }
11750  CHECK(apply_success_);
11751  CHECK(gc_success_);
11752  }
11753 
11754  private:
11755  // Number of garbage collections required.
11756  static const int kRequiredGCs = 2;
11757 
11758  class GCThread : public i::Thread {
11759  public:
11760  explicit GCThread(ApplyInterruptTest* test)
11761  : Thread("GCThread"), test_(test) {}
11762  virtual void Run() {
11763  test_->CollectGarbage();
11764  }
11765  private:
11766  ApplyInterruptTest* test_;
11767  };
11768 
11769  void CollectGarbage() {
11770  block_->Wait();
11771  while (gc_during_apply_ < kRequiredGCs) {
11772  {
11773  v8::Locker lock;
11774  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11775  gc_count_++;
11776  }
11777  i::OS::Sleep(1);
11778  }
11779  gc_success_ = true;
11780  }
11781 
11782  void LongRunningApply() {
11783  block_->Signal();
11784  int rounds = 0;
11785  while (gc_during_apply_ < kRequiredGCs) {
11786  int gc_before = gc_count_;
11787  {
11788  const char* c_source =
11789  "function do_very_little(bar) {"
11790  " this.foo = bar;"
11791  "}"
11792  "for (var i = 0; i < 100000; i++) {"
11793  " do_very_little.apply(this, ['bar']);"
11794  "}";
11795  Local<String> source = String::New(c_source);
11796  Local<Script> script = Script::Compile(source);
11797  Local<Value> result = script->Run();
11798  // Check that no exception was thrown.
11799  CHECK(!result.IsEmpty());
11800  }
11801  int gc_after = gc_count_;
11802  gc_during_apply_ += gc_after - gc_before;
11803  rounds++;
11804  }
11805  apply_success_ = true;
11806  }
11807 
11808  i::Semaphore* block_;
11809  int gc_count_;
11810  int gc_during_apply_;
11811  bool apply_success_;
11812  bool gc_success_;
11813 };
11814 
11815 
11816 // Test that nothing bad happens if we get a preemption just when we were
11817 // about to do an apply().
11818 TEST(ApplyInterruption) {
11819  v8::Locker lock;
11821  v8::HandleScope scope;
11822  Local<Context> local_env;
11823  {
11824  LocalContext env;
11825  local_env = env.local();
11826  }
11827 
11828  // Local context should still be live.
11829  CHECK(!local_env.IsEmpty());
11830  local_env->Enter();
11831 
11832  // Should complete without problems.
11834 
11835  local_env->Exit();
11836 }
11837 
11838 
11839 // Verify that we can clone an object
11840 TEST(ObjectClone) {
11841  v8::HandleScope scope;
11842  LocalContext env;
11843 
11844  const char* sample =
11845  "var rv = {};" \
11846  "rv.alpha = 'hello';" \
11847  "rv.beta = 123;" \
11848  "rv;";
11849 
11850  // Create an object, verify basics.
11851  Local<Value> val = CompileRun(sample);
11852  CHECK(val->IsObject());
11853  Local<v8::Object> obj = val.As<v8::Object>();
11854  obj->Set(v8_str("gamma"), v8_str("cloneme"));
11855 
11856  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11857  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11858  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11859 
11860  // Clone it.
11861  Local<v8::Object> clone = obj->Clone();
11862  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11863  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11864  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11865 
11866  // Set a property on the clone, verify each object.
11867  clone->Set(v8_str("beta"), v8::Integer::New(456));
11868  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11869  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11870 }
11871 
11872 
11874  public:
11876  : data_(vector) {}
11878  virtual size_t length() const { return data_.length(); }
11879  virtual const char* data() const { return data_.start(); }
11880  private:
11881  i::Vector<const char> data_;
11882 };
11883 
11884 
11886  public:
11888  : data_(vector) {}
11889  virtual ~UC16VectorResource() {}
11890  virtual size_t length() const { return data_.length(); }
11891  virtual const i::uc16* data() const { return data_.start(); }
11892  private:
11894 };
11895 
11896 
11897 static void MorphAString(i::String* string,
11898  AsciiVectorResource* ascii_resource,
11899  UC16VectorResource* uc16_resource) {
11900  CHECK(i::StringShape(string).IsExternal());
11901  if (string->IsAsciiRepresentation()) {
11902  // Check old map is not symbol or long.
11903  CHECK(string->map() == HEAP->external_ascii_string_map());
11904  // Morph external string to be TwoByte string.
11905  string->set_map(HEAP->external_string_map());
11906  i::ExternalTwoByteString* morphed =
11908  morphed->set_resource(uc16_resource);
11909  } else {
11910  // Check old map is not symbol or long.
11911  CHECK(string->map() == HEAP->external_string_map());
11912  // Morph external string to be ASCII string.
11913  string->set_map(HEAP->external_ascii_string_map());
11914  i::ExternalAsciiString* morphed =
11916  morphed->set_resource(ascii_resource);
11917  }
11918 }
11919 
11920 
11921 // Test that we can still flatten a string if the components it is built up
11922 // from have been turned into 16 bit strings in the mean time.
11923 THREADED_TEST(MorphCompositeStringTest) {
11924  char utf_buffer[129];
11925  const char* c_string = "Now is the time for all good men"
11926  " to come to the aid of the party";
11927  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11928  {
11929  v8::HandleScope scope;
11930  LocalContext env;
11931  AsciiVectorResource ascii_resource(
11932  i::Vector<const char>(c_string, i::StrLength(c_string)));
11933  UC16VectorResource uc16_resource(
11934  i::Vector<const uint16_t>(two_byte_string,
11935  i::StrLength(c_string)));
11936 
11937  Local<String> lhs(v8::Utils::ToLocal(
11938  FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11939  Local<String> rhs(v8::Utils::ToLocal(
11940  FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11941 
11942  env->Global()->Set(v8_str("lhs"), lhs);
11943  env->Global()->Set(v8_str("rhs"), rhs);
11944 
11945  CompileRun(
11946  "var cons = lhs + rhs;"
11947  "var slice = lhs.substring(1, lhs.length - 1);"
11948  "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11949 
11950  CHECK(!lhs->MayContainNonAscii());
11951  CHECK(!rhs->MayContainNonAscii());
11952 
11953  MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11954  MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11955 
11956  // This should UTF-8 without flattening, since everything is ASCII.
11957  Handle<String> cons = v8_compile("cons")->Run().As<String>();
11958  CHECK_EQ(128, cons->Utf8Length());
11959  int nchars = -1;
11960  CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11961  CHECK_EQ(128, nchars);
11962  CHECK_EQ(0, strcmp(
11963  utf_buffer,
11964  "Now is the time for all good men to come to the aid of the party"
11965  "Now is the time for all good men to come to the aid of the party"));
11966 
11967  // Now do some stuff to make sure the strings are flattened, etc.
11968  CompileRun(
11969  "/[^a-z]/.test(cons);"
11970  "/[^a-z]/.test(slice);"
11971  "/[^a-z]/.test(slice_on_cons);");
11972  const char* expected_cons =
11973  "Now is the time for all good men to come to the aid of the party"
11974  "Now is the time for all good men to come to the aid of the party";
11975  const char* expected_slice =
11976  "ow is the time for all good men to come to the aid of the part";
11977  const char* expected_slice_on_cons =
11978  "ow is the time for all good men to come to the aid of the party"
11979  "Now is the time for all good men to come to the aid of the part";
11980  CHECK_EQ(String::New(expected_cons),
11981  env->Global()->Get(v8_str("cons")));
11982  CHECK_EQ(String::New(expected_slice),
11983  env->Global()->Get(v8_str("slice")));
11984  CHECK_EQ(String::New(expected_slice_on_cons),
11985  env->Global()->Get(v8_str("slice_on_cons")));
11986  }
11987  i::DeleteArray(two_byte_string);
11988 }
11989 
11990 
11991 TEST(CompileExternalTwoByteSource) {
11992  v8::HandleScope scope;
11993  LocalContext context;
11994 
11995  // This is a very short list of sources, which currently is to check for a
11996  // regression caused by r2703.
11997  const char* ascii_sources[] = {
11998  "0.5",
11999  "-0.5", // This mainly testes PushBack in the Scanner.
12000  "--0.5", // This mainly testes PushBack in the Scanner.
12001  NULL
12002  };
12003 
12004  // Compile the sources as external two byte strings.
12005  for (int i = 0; ascii_sources[i] != NULL; i++) {
12006  uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12007  UC16VectorResource uc16_resource(
12008  i::Vector<const uint16_t>(two_byte_string,
12009  i::StrLength(ascii_sources[i])));
12010  v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12011  v8::Script::Compile(source);
12012  i::DeleteArray(two_byte_string);
12013  }
12014 }
12015 
12016 
12018  public:
12020  : block_(i::OS::CreateSemaphore(0)),
12021  morphs_(0),
12022  morphs_during_regexp_(0),
12023  ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12024  uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12025  ~RegExpStringModificationTest() { delete block_; }
12026  void RunTest() {
12027  regexp_success_ = false;
12028  morph_success_ = false;
12029 
12030  // Initialize the contents of two_byte_content_ to be a uc16 representation
12031  // of "aaaaaaaaaaaaaab".
12032  for (int i = 0; i < 14; i++) {
12033  two_byte_content_[i] = 'a';
12034  }
12035  two_byte_content_[14] = 'b';
12036 
12037  // Create the input string for the regexp - the one we are going to change
12038  // properties of.
12039  input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
12040 
12041  // Inject the input as a global variable.
12042  i::Handle<i::String> input_name =
12043  FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
12044  i::Isolate::Current()->global_context()->global()->SetProperty(
12045  *input_name,
12046  *input_,
12047  NONE,
12048  i::kNonStrictMode)->ToObjectChecked();
12049 
12050  MorphThread morph_thread(this);
12051  morph_thread.Start();
12053  LongRunningRegExp();
12054  {
12055  v8::Unlocker unlock;
12056  morph_thread.Join();
12057  }
12059  CHECK(regexp_success_);
12060  CHECK(morph_success_);
12061  }
12062 
12063  private:
12064  // Number of string modifications required.
12065  static const int kRequiredModifications = 5;
12066  static const int kMaxModifications = 100;
12067 
12068  class MorphThread : public i::Thread {
12069  public:
12070  explicit MorphThread(RegExpStringModificationTest* test)
12071  : Thread("MorphThread"), test_(test) {}
12072  virtual void Run() {
12073  test_->MorphString();
12074  }
12075  private:
12077  };
12078 
12079  void MorphString() {
12080  block_->Wait();
12081  while (morphs_during_regexp_ < kRequiredModifications &&
12082  morphs_ < kMaxModifications) {
12083  {
12084  v8::Locker lock;
12085  // Swap string between ascii and two-byte representation.
12086  i::String* string = *input_;
12087  MorphAString(string, &ascii_resource_, &uc16_resource_);
12088  morphs_++;
12089  }
12090  i::OS::Sleep(1);
12091  }
12092  morph_success_ = true;
12093  }
12094 
12095  void LongRunningRegExp() {
12096  block_->Signal(); // Enable morphing thread on next preemption.
12097  while (morphs_during_regexp_ < kRequiredModifications &&
12098  morphs_ < kMaxModifications) {
12099  int morphs_before = morphs_;
12100  {
12101  v8::HandleScope scope;
12102  // Match 15-30 "a"'s against 14 and a "b".
12103  const char* c_source =
12104  "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12105  ".exec(input) === null";
12106  Local<String> source = String::New(c_source);
12107  Local<Script> script = Script::Compile(source);
12108  Local<Value> result = script->Run();
12109  CHECK(result->IsTrue());
12110  }
12111  int morphs_after = morphs_;
12112  morphs_during_regexp_ += morphs_after - morphs_before;
12113  }
12114  regexp_success_ = true;
12115  }
12116 
12117  i::uc16 two_byte_content_[15];
12118  i::Semaphore* block_;
12119  int morphs_;
12120  int morphs_during_regexp_;
12121  bool regexp_success_;
12122  bool morph_success_;
12123  i::Handle<i::String> input_;
12124  AsciiVectorResource ascii_resource_;
12125  UC16VectorResource uc16_resource_;
12126 };
12127 
12128 
12129 // Test that a regular expression execution can be interrupted and
12130 // the string changed without failing.
12131 TEST(RegExpStringModification) {
12132  v8::Locker lock;
12134  v8::HandleScope scope;
12135  Local<Context> local_env;
12136  {
12137  LocalContext env;
12138  local_env = env.local();
12139  }
12140 
12141  // Local context should still be live.
12142  CHECK(!local_env.IsEmpty());
12143  local_env->Enter();
12144 
12145  // Should complete without problems.
12147 
12148  local_env->Exit();
12149 }
12150 
12151 
12152 // Test that we cannot set a property on the global object if there
12153 // is a read-only property in the prototype chain.
12154 TEST(ReadOnlyPropertyInGlobalProto) {
12155  i::FLAG_es5_readonly = true;
12156  v8::HandleScope scope;
12158  LocalContext context(0, templ);
12159  v8::Handle<v8::Object> global = context->Global();
12160  v8::Handle<v8::Object> global_proto =
12161  v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12162  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12163  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12164  // Check without 'eval' or 'with'.
12165  v8::Handle<v8::Value> res =
12166  CompileRun("function f() { x = 42; return x; }; f()");
12167  CHECK_EQ(v8::Integer::New(0), res);
12168  // Check with 'eval'.
12169  res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12170  CHECK_EQ(v8::Integer::New(0), res);
12171  // Check with 'with'.
12172  res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12173  CHECK_EQ(v8::Integer::New(0), res);
12174 }
12175 
12176 static int force_set_set_count = 0;
12177 static int force_set_get_count = 0;
12178 bool pass_on_get = false;
12179 
12180 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12181  const v8::AccessorInfo& info) {
12182  force_set_get_count++;
12183  if (pass_on_get) {
12184  return v8::Handle<v8::Value>();
12185  } else {
12186  return v8::Int32::New(3);
12187  }
12188 }
12189 
12190 static void ForceSetSetter(v8::Local<v8::String> name,
12191  v8::Local<v8::Value> value,
12192  const v8::AccessorInfo& info) {
12193  force_set_set_count++;
12194 }
12195 
12196 static v8::Handle<v8::Value> ForceSetInterceptSetter(
12197  v8::Local<v8::String> name,
12198  v8::Local<v8::Value> value,
12199  const v8::AccessorInfo& info) {
12200  force_set_set_count++;
12201  return v8::Undefined();
12202 }
12203 
12204 TEST(ForceSet) {
12205  force_set_get_count = 0;
12206  force_set_set_count = 0;
12207  pass_on_get = false;
12208 
12209  v8::HandleScope scope;
12211  v8::Handle<v8::String> access_property = v8::String::New("a");
12212  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12213  LocalContext context(NULL, templ);
12214  v8::Handle<v8::Object> global = context->Global();
12215 
12216  // Ordinary properties
12217  v8::Handle<v8::String> simple_property = v8::String::New("p");
12218  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12219  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12220  // This should fail because the property is read-only
12221  global->Set(simple_property, v8::Int32::New(5));
12222  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12223  // This should succeed even though the property is read-only
12224  global->ForceSet(simple_property, v8::Int32::New(6));
12225  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12226 
12227  // Accessors
12228  CHECK_EQ(0, force_set_set_count);
12229  CHECK_EQ(0, force_set_get_count);
12230  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12231  // CHECK_EQ the property shouldn't override it, just call the setter
12232  // which in this case does nothing.
12233  global->Set(access_property, v8::Int32::New(7));
12234  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12235  CHECK_EQ(1, force_set_set_count);
12236  CHECK_EQ(2, force_set_get_count);
12237  // Forcing the property to be set should override the accessor without
12238  // calling it
12239  global->ForceSet(access_property, v8::Int32::New(8));
12240  CHECK_EQ(8, global->Get(access_property)->Int32Value());
12241  CHECK_EQ(1, force_set_set_count);
12242  CHECK_EQ(2, force_set_get_count);
12243 }
12244 
12245 TEST(ForceSetWithInterceptor) {
12246  force_set_get_count = 0;
12247  force_set_set_count = 0;
12248  pass_on_get = false;
12249 
12250  v8::HandleScope scope;
12252  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12253  LocalContext context(NULL, templ);
12254  v8::Handle<v8::Object> global = context->Global();
12255 
12256  v8::Handle<v8::String> some_property = v8::String::New("a");
12257  CHECK_EQ(0, force_set_set_count);
12258  CHECK_EQ(0, force_set_get_count);
12259  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12260  // Setting the property shouldn't override it, just call the setter
12261  // which in this case does nothing.
12262  global->Set(some_property, v8::Int32::New(7));
12263  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12264  CHECK_EQ(1, force_set_set_count);
12265  CHECK_EQ(2, force_set_get_count);
12266  // Getting the property when the interceptor returns an empty handle
12267  // should yield undefined, since the property isn't present on the
12268  // object itself yet.
12269  pass_on_get = true;
12270  CHECK(global->Get(some_property)->IsUndefined());
12271  CHECK_EQ(1, force_set_set_count);
12272  CHECK_EQ(3, force_set_get_count);
12273  // Forcing the property to be set should cause the value to be
12274  // set locally without calling the interceptor.
12275  global->ForceSet(some_property, v8::Int32::New(8));
12276  CHECK_EQ(8, global->Get(some_property)->Int32Value());
12277  CHECK_EQ(1, force_set_set_count);
12278  CHECK_EQ(4, force_set_get_count);
12279  // Reenabling the interceptor should cause it to take precedence over
12280  // the property
12281  pass_on_get = false;
12282  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12283  CHECK_EQ(1, force_set_set_count);
12284  CHECK_EQ(5, force_set_get_count);
12285  // The interceptor should also work for other properties
12286  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12287  CHECK_EQ(1, force_set_set_count);
12288  CHECK_EQ(6, force_set_get_count);
12289 }
12290 
12291 
12292 THREADED_TEST(ForceDelete) {
12293  v8::HandleScope scope;
12295  LocalContext context(NULL, templ);
12296  v8::Handle<v8::Object> global = context->Global();
12297 
12298  // Ordinary properties
12299  v8::Handle<v8::String> simple_property = v8::String::New("p");
12300  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12301  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12302  // This should fail because the property is dont-delete.
12303  CHECK(!global->Delete(simple_property));
12304  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12305  // This should succeed even though the property is dont-delete.
12306  CHECK(global->ForceDelete(simple_property));
12307  CHECK(global->Get(simple_property)->IsUndefined());
12308 }
12309 
12310 
12311 static int force_delete_interceptor_count = 0;
12312 static bool pass_on_delete = false;
12313 
12314 
12315 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12316  v8::Local<v8::String> name,
12317  const v8::AccessorInfo& info) {
12318  force_delete_interceptor_count++;
12319  if (pass_on_delete) {
12320  return v8::Handle<v8::Boolean>();
12321  } else {
12322  return v8::True();
12323  }
12324 }
12325 
12326 
12327 THREADED_TEST(ForceDeleteWithInterceptor) {
12328  force_delete_interceptor_count = 0;
12329  pass_on_delete = false;
12330 
12331  v8::HandleScope scope;
12333  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12334  LocalContext context(NULL, templ);
12335  v8::Handle<v8::Object> global = context->Global();
12336 
12337  v8::Handle<v8::String> some_property = v8::String::New("a");
12338  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12339 
12340  // Deleting a property should get intercepted and nothing should
12341  // happen.
12342  CHECK_EQ(0, force_delete_interceptor_count);
12343  CHECK(global->Delete(some_property));
12344  CHECK_EQ(1, force_delete_interceptor_count);
12345  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12346  // Deleting the property when the interceptor returns an empty
12347  // handle should not delete the property since it is DontDelete.
12348  pass_on_delete = true;
12349  CHECK(!global->Delete(some_property));
12350  CHECK_EQ(2, force_delete_interceptor_count);
12351  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12352  // Forcing the property to be deleted should delete the value
12353  // without calling the interceptor.
12354  CHECK(global->ForceDelete(some_property));
12355  CHECK(global->Get(some_property)->IsUndefined());
12356  CHECK_EQ(2, force_delete_interceptor_count);
12357 }
12358 
12359 
12360 // Make sure that forcing a delete invalidates any IC stubs, so we
12361 // don't read the hole value.
12362 THREADED_TEST(ForceDeleteIC) {
12363  v8::HandleScope scope;
12364  LocalContext context;
12365  // Create a DontDelete variable on the global object.
12366  CompileRun("this.__proto__ = { foo: 'horse' };"
12367  "var foo = 'fish';"
12368  "function f() { return foo.length; }");
12369  // Initialize the IC for foo in f.
12370  CompileRun("for (var i = 0; i < 4; i++) f();");
12371  // Make sure the value of foo is correct before the deletion.
12372  CHECK_EQ(4, CompileRun("f()")->Int32Value());
12373  // Force the deletion of foo.
12374  CHECK(context->Global()->ForceDelete(v8_str("foo")));
12375  // Make sure the value for foo is read from the prototype, and that
12376  // we don't get in trouble with reading the deleted cell value
12377  // sentinel.
12378  CHECK_EQ(5, CompileRun("f()")->Int32Value());
12379 }
12380 
12381 
12382 TEST(InlinedFunctionAcrossContexts) {
12383  i::FLAG_allow_natives_syntax = true;
12384  v8::HandleScope outer_scope;
12387  ctx1->Enter();
12388 
12389  {
12390  v8::HandleScope inner_scope;
12391  CompileRun("var G = 42; function foo() { return G; }");
12392  v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
12393  ctx2->Enter();
12394  ctx2->Global()->Set(v8_str("o"), foo);
12395  v8::Local<v8::Value> res = CompileRun(
12396  "function f() { return o(); }"
12397  "for (var i = 0; i < 10; ++i) f();"
12398  "%OptimizeFunctionOnNextCall(f);"
12399  "f();");
12400  CHECK_EQ(42, res->Int32Value());
12401  ctx2->Exit();
12402  v8::Handle<v8::String> G_property = v8::String::New("G");
12403  CHECK(ctx1->Global()->ForceDelete(G_property));
12404  ctx2->Enter();
12405  ExpectString(
12406  "(function() {"
12407  " try {"
12408  " return f();"
12409  " } catch(e) {"
12410  " return e.toString();"
12411  " }"
12412  " })()",
12413  "ReferenceError: G is not defined");
12414  ctx2->Exit();
12415  ctx1->Exit();
12416  ctx1.Dispose();
12417  }
12418  ctx2.Dispose();
12419 }
12420 
12421 
12425 
12426 
12427 // Check that the call to the callback is initiated in
12428 // calling_context2, the directly calling context is calling_context1
12429 // and the callback itself is in calling_context0.
12430 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12432  CHECK(Context::GetCurrent() == calling_context0);
12433  CHECK(Context::GetCalling() == calling_context1);
12434  CHECK(Context::GetEntered() == calling_context2);
12435  return v8::Integer::New(42);
12436 }
12437 
12438 
12439 THREADED_TEST(GetCallingContext) {
12440  v8::HandleScope scope;
12441 
12442  calling_context0 = Context::New();
12443  calling_context1 = Context::New();
12444  calling_context2 = Context::New();
12445 
12446  // Allow cross-domain access.
12447  Local<String> token = v8_str("<security token>");
12448  calling_context0->SetSecurityToken(token);
12449  calling_context1->SetSecurityToken(token);
12450  calling_context2->SetSecurityToken(token);
12451 
12452  // Create an object with a C++ callback in context0.
12453  calling_context0->Enter();
12454  Local<v8::FunctionTemplate> callback_templ =
12455  v8::FunctionTemplate::New(GetCallingContextCallback);
12456  calling_context0->Global()->Set(v8_str("callback"),
12457  callback_templ->GetFunction());
12458  calling_context0->Exit();
12459 
12460  // Expose context0 in context1 and set up a function that calls the
12461  // callback function.
12462  calling_context1->Enter();
12463  calling_context1->Global()->Set(v8_str("context0"),
12464  calling_context0->Global());
12465  CompileRun("function f() { context0.callback() }");
12466  calling_context1->Exit();
12467 
12468  // Expose context1 in context2 and call the callback function in
12469  // context0 indirectly through f in context1.
12470  calling_context2->Enter();
12471  calling_context2->Global()->Set(v8_str("context1"),
12472  calling_context1->Global());
12473  CompileRun("context1.f()");
12474  calling_context2->Exit();
12475 
12476  // Dispose the contexts to allow them to be garbage collected.
12477  calling_context0.Dispose();
12478  calling_context1.Dispose();
12479  calling_context2.Dispose();
12480  calling_context0.Clear();
12481  calling_context1.Clear();
12482  calling_context2.Clear();
12483 }
12484 
12485 
12486 // Check that a variable declaration with no explicit initialization
12487 // value does shadow an existing property in the prototype chain.
12488 THREADED_TEST(InitGlobalVarInProtoChain) {
12489  i::FLAG_es52_globals = true;
12490  v8::HandleScope scope;
12491  LocalContext context;
12492  // Introduce a variable in the prototype chain.
12493  CompileRun("__proto__.x = 42");
12494  v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
12495  CHECK(!result->IsUndefined());
12496  CHECK_EQ(43, result->Int32Value());
12497 }
12498 
12499 
12500 // Regression test for issue 398.
12501 // If a function is added to an object, creating a constant function
12502 // field, and the result is cloned, replacing the constant function on the
12503 // original should not affect the clone.
12504 // See http://code.google.com/p/v8/issues/detail?id=398
12505 THREADED_TEST(ReplaceConstantFunction) {
12506  v8::HandleScope scope;
12507  LocalContext context;
12510  v8::Handle<v8::String> foo_string = v8::String::New("foo");
12511  obj->Set(foo_string, func_templ->GetFunction());
12512  v8::Handle<v8::Object> obj_clone = obj->Clone();
12513  obj_clone->Set(foo_string, v8::String::New("Hello"));
12514  CHECK(!obj->Get(foo_string)->IsUndefined());
12515 }
12516 
12517 
12518 // Regression test for http://crbug.com/16276.
12519 THREADED_TEST(Regress16276) {
12520  v8::HandleScope scope;
12521  LocalContext context;
12522  // Force the IC in f to be a dictionary load IC.
12523  CompileRun("function f(obj) { return obj.x; }\n"
12524  "var obj = { x: { foo: 42 }, y: 87 };\n"
12525  "var x = obj.x;\n"
12526  "delete obj.y;\n"
12527  "for (var i = 0; i < 5; i++) f(obj);");
12528  // Detach the global object to make 'this' refer directly to the
12529  // global object (not the proxy), and make sure that the dictionary
12530  // load IC doesn't mess up loading directly from the global object.
12531  context->DetachGlobal();
12532  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12533 }
12534 
12535 
12536 THREADED_TEST(PixelArray) {
12537  v8::HandleScope scope;
12538  LocalContext context;
12539  const int kElementCount = 260;
12540  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12543  FACTORY->NewExternalArray(kElementCount,
12545  pixel_data));
12546  // Force GC to trigger verification.
12547  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12548  for (int i = 0; i < kElementCount; i++) {
12549  pixels->set(i, i % 256);
12550  }
12551  // Force GC to trigger verification.
12552  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12553  for (int i = 0; i < kElementCount; i++) {
12554  CHECK_EQ(i % 256, pixels->get_scalar(i));
12555  CHECK_EQ(i % 256, pixel_data[i]);
12556  }
12557 
12560  // Set the elements to be the pixels.
12561  // jsobj->set_elements(*pixels);
12562  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12563  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12564  obj->Set(v8_str("field"), v8::Int32::New(1503));
12565  context->Global()->Set(v8_str("pixels"), obj);
12566  v8::Handle<v8::Value> result = CompileRun("pixels.field");
12567  CHECK_EQ(1503, result->Int32Value());
12568  result = CompileRun("pixels[1]");
12569  CHECK_EQ(1, result->Int32Value());
12570 
12571  result = CompileRun("var sum = 0;"
12572  "for (var i = 0; i < 8; i++) {"
12573  " sum += pixels[i] = pixels[i] = -i;"
12574  "}"
12575  "sum;");
12576  CHECK_EQ(-28, result->Int32Value());
12577 
12578  result = CompileRun("var sum = 0;"
12579  "for (var i = 0; i < 8; i++) {"
12580  " sum += pixels[i] = pixels[i] = 0;"
12581  "}"
12582  "sum;");
12583  CHECK_EQ(0, result->Int32Value());
12584 
12585  result = CompileRun("var sum = 0;"
12586  "for (var i = 0; i < 8; i++) {"
12587  " sum += pixels[i] = pixels[i] = 255;"
12588  "}"
12589  "sum;");
12590  CHECK_EQ(8 * 255, result->Int32Value());
12591 
12592  result = CompileRun("var sum = 0;"
12593  "for (var i = 0; i < 8; i++) {"
12594  " sum += pixels[i] = pixels[i] = 256 + i;"
12595  "}"
12596  "sum;");
12597  CHECK_EQ(2076, result->Int32Value());
12598 
12599  result = CompileRun("var sum = 0;"
12600  "for (var i = 0; i < 8; i++) {"
12601  " sum += pixels[i] = pixels[i] = i;"
12602  "}"
12603  "sum;");
12604  CHECK_EQ(28, result->Int32Value());
12605 
12606  result = CompileRun("var sum = 0;"
12607  "for (var i = 0; i < 8; i++) {"
12608  " sum += pixels[i];"
12609  "}"
12610  "sum;");
12611  CHECK_EQ(28, result->Int32Value());
12612 
12614  i::Handle<i::Object> no_failure;
12615  no_failure =
12616  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12617  ASSERT(!no_failure.is_null());
12618  i::USE(no_failure);
12619  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12620  *value.location() = i::Smi::FromInt(256);
12621  no_failure =
12622  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12623  ASSERT(!no_failure.is_null());
12624  i::USE(no_failure);
12625  CHECK_EQ(255,
12626  i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12627  *value.location() = i::Smi::FromInt(-1);
12628  no_failure =
12629  i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12630  ASSERT(!no_failure.is_null());
12631  i::USE(no_failure);
12632  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12633 
12634  result = CompileRun("for (var i = 0; i < 8; i++) {"
12635  " pixels[i] = (i * 65) - 109;"
12636  "}"
12637  "pixels[1] + pixels[6];");
12638  CHECK_EQ(255, result->Int32Value());
12639  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12640  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12641  CHECK_EQ(21,
12642  i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12643  CHECK_EQ(86,
12644  i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12645  CHECK_EQ(151,
12646  i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12647  CHECK_EQ(216,
12648  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12649  CHECK_EQ(255,
12650  i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12651  CHECK_EQ(255,
12652  i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12653  result = CompileRun("var sum = 0;"
12654  "for (var i = 0; i < 8; i++) {"
12655  " sum += pixels[i];"
12656  "}"
12657  "sum;");
12658  CHECK_EQ(984, result->Int32Value());
12659 
12660  result = CompileRun("for (var i = 0; i < 8; i++) {"
12661  " pixels[i] = (i * 1.1);"
12662  "}"
12663  "pixels[1] + pixels[6];");
12664  CHECK_EQ(8, result->Int32Value());
12665  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12666  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12667  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12668  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12669  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12670  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12671  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12672  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12673 
12674  result = CompileRun("for (var i = 0; i < 8; i++) {"
12675  " pixels[7] = undefined;"
12676  "}"
12677  "pixels[7];");
12678  CHECK_EQ(0, result->Int32Value());
12679  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12680 
12681  result = CompileRun("for (var i = 0; i < 8; i++) {"
12682  " pixels[6] = '2.3';"
12683  "}"
12684  "pixels[6];");
12685  CHECK_EQ(2, result->Int32Value());
12686  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12687 
12688  result = CompileRun("for (var i = 0; i < 8; i++) {"
12689  " pixels[5] = NaN;"
12690  "}"
12691  "pixels[5];");
12692  CHECK_EQ(0, result->Int32Value());
12693  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12694 
12695  result = CompileRun("for (var i = 0; i < 8; i++) {"
12696  " pixels[8] = Infinity;"
12697  "}"
12698  "pixels[8];");
12699  CHECK_EQ(255, result->Int32Value());
12700  CHECK_EQ(255,
12701  i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
12702 
12703  result = CompileRun("for (var i = 0; i < 8; i++) {"
12704  " pixels[9] = -Infinity;"
12705  "}"
12706  "pixels[9];");
12707  CHECK_EQ(0, result->Int32Value());
12708  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
12709 
12710  result = CompileRun("pixels[3] = 33;"
12711  "delete pixels[3];"
12712  "pixels[3];");
12713  CHECK_EQ(33, result->Int32Value());
12714 
12715  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12716  "pixels[2] = 12; pixels[3] = 13;"
12717  "pixels.__defineGetter__('2',"
12718  "function() { return 120; });"
12719  "pixels[2];");
12720  CHECK_EQ(12, result->Int32Value());
12721 
12722  result = CompileRun("var js_array = new Array(40);"
12723  "js_array[0] = 77;"
12724  "js_array;");
12725  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12726 
12727  result = CompileRun("pixels[1] = 23;"
12728  "pixels.__proto__ = [];"
12729  "js_array.__proto__ = pixels;"
12730  "js_array.concat(pixels);");
12731  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12732  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12733 
12734  result = CompileRun("pixels[1] = 23;");
12735  CHECK_EQ(23, result->Int32Value());
12736 
12737  // Test for index greater than 255. Regression test for:
12738  // http://code.google.com/p/chromium/issues/detail?id=26337.
12739  result = CompileRun("pixels[256] = 255;");
12740  CHECK_EQ(255, result->Int32Value());
12741  result = CompileRun("var i = 0;"
12742  "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12743  "i");
12744  CHECK_EQ(255, result->Int32Value());
12745 
12746  // Make sure that pixel array ICs recognize when a non-pixel array
12747  // is passed to it.
12748  result = CompileRun("function pa_load(p) {"
12749  " var sum = 0;"
12750  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12751  " return sum;"
12752  "}"
12753  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12754  "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12755  "just_ints = new Object();"
12756  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12757  "for (var i = 0; i < 10; ++i) {"
12758  " result = pa_load(just_ints);"
12759  "}"
12760  "result");
12761  CHECK_EQ(32640, result->Int32Value());
12762 
12763  // Make sure that pixel array ICs recognize out-of-bound accesses.
12764  result = CompileRun("function pa_load(p, start) {"
12765  " var sum = 0;"
12766  " for (var j = start; j < 256; j++) { sum += p[j]; }"
12767  " return sum;"
12768  "}"
12769  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12770  "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12771  "for (var i = 0; i < 10; ++i) {"
12772  " result = pa_load(pixels,-10);"
12773  "}"
12774  "result");
12775  CHECK_EQ(0, result->Int32Value());
12776 
12777  // Make sure that generic ICs properly handles a pixel array.
12778  result = CompileRun("function pa_load(p) {"
12779  " var sum = 0;"
12780  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12781  " return sum;"
12782  "}"
12783  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12784  "just_ints = new Object();"
12785  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12786  "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12787  "for (var i = 0; i < 10; ++i) {"
12788  " result = pa_load(pixels);"
12789  "}"
12790  "result");
12791  CHECK_EQ(32640, result->Int32Value());
12792 
12793  // Make sure that generic load ICs recognize out-of-bound accesses in
12794  // pixel arrays.
12795  result = CompileRun("function pa_load(p, start) {"
12796  " var sum = 0;"
12797  " for (var j = start; j < 256; j++) { sum += p[j]; }"
12798  " return sum;"
12799  "}"
12800  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12801  "just_ints = new Object();"
12802  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12803  "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12804  "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12805  "for (var i = 0; i < 10; ++i) {"
12806  " result = pa_load(pixels,-10);"
12807  "}"
12808  "result");
12809  CHECK_EQ(0, result->Int32Value());
12810 
12811  // Make sure that generic ICs properly handles other types than pixel
12812  // arrays (that the inlined fast pixel array test leaves the right information
12813  // in the right registers).
12814  result = CompileRun("function pa_load(p) {"
12815  " var sum = 0;"
12816  " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12817  " return sum;"
12818  "}"
12819  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12820  "just_ints = new Object();"
12821  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12822  "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12823  "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12824  "sparse_array = new Object();"
12825  "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12826  "sparse_array[1000000] = 3;"
12827  "for (var i = 0; i < 10; ++i) {"
12828  " result = pa_load(sparse_array);"
12829  "}"
12830  "result");
12831  CHECK_EQ(32640, result->Int32Value());
12832 
12833  // Make sure that pixel array store ICs clamp values correctly.
12834  result = CompileRun("function pa_store(p) {"
12835  " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12836  "}"
12837  "pa_store(pixels);"
12838  "var sum = 0;"
12839  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12840  "sum");
12841  CHECK_EQ(48896, result->Int32Value());
12842 
12843  // Make sure that pixel array stores correctly handle accesses outside
12844  // of the pixel array..
12845  result = CompileRun("function pa_store(p,start) {"
12846  " for (var j = 0; j < 256; j++) {"
12847  " p[j+start] = j * 2;"
12848  " }"
12849  "}"
12850  "pa_store(pixels,0);"
12851  "pa_store(pixels,-128);"
12852  "var sum = 0;"
12853  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12854  "sum");
12855  CHECK_EQ(65280, result->Int32Value());
12856 
12857  // Make sure that the generic store stub correctly handle accesses outside
12858  // of the pixel array..
12859  result = CompileRun("function pa_store(p,start) {"
12860  " for (var j = 0; j < 256; j++) {"
12861  " p[j+start] = j * 2;"
12862  " }"
12863  "}"
12864  "pa_store(pixels,0);"
12865  "just_ints = new Object();"
12866  "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12867  "pa_store(just_ints, 0);"
12868  "pa_store(pixels,-128);"
12869  "var sum = 0;"
12870  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12871  "sum");
12872  CHECK_EQ(65280, result->Int32Value());
12873 
12874  // Make sure that the generic keyed store stub clamps pixel array values
12875  // correctly.
12876  result = CompileRun("function pa_store(p) {"
12877  " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12878  "}"
12879  "pa_store(pixels);"
12880  "just_ints = new Object();"
12881  "pa_store(just_ints);"
12882  "pa_store(pixels);"
12883  "var sum = 0;"
12884  "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12885  "sum");
12886  CHECK_EQ(48896, result->Int32Value());
12887 
12888  // Make sure that pixel array loads are optimized by crankshaft.
12889  result = CompileRun("function pa_load(p) {"
12890  " var sum = 0;"
12891  " for (var i=0; i<256; ++i) {"
12892  " sum += p[i];"
12893  " }"
12894  " return sum; "
12895  "}"
12896  "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12897  "for (var i = 0; i < 5000; ++i) {"
12898  " result = pa_load(pixels);"
12899  "}"
12900  "result");
12901  CHECK_EQ(32640, result->Int32Value());
12902 
12903  // Make sure that pixel array stores are optimized by crankshaft.
12904  result = CompileRun("function pa_init(p) {"
12905  "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12906  "}"
12907  "function pa_load(p) {"
12908  " var sum = 0;"
12909  " for (var i=0; i<256; ++i) {"
12910  " sum += p[i];"
12911  " }"
12912  " return sum; "
12913  "}"
12914  "for (var i = 0; i < 5000; ++i) {"
12915  " pa_init(pixels);"
12916  "}"
12917  "result = pa_load(pixels);"
12918  "result");
12919  CHECK_EQ(32640, result->Int32Value());
12920 
12921  free(pixel_data);
12922 }
12923 
12924 
12925 THREADED_TEST(PixelArrayInfo) {
12926  v8::HandleScope scope;
12927  LocalContext context;
12928  for (int size = 0; size < 100; size += 10) {
12929  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12931  obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12933  CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12935  free(pixel_data);
12936  }
12937 }
12938 
12939 
12940 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12941  uint32_t index,
12942  const AccessorInfo& info) {
12944  return v8::Handle<Value>();
12945 }
12946 
12947 
12948 static v8::Handle<Value> NotHandledIndexedPropertySetter(
12949  uint32_t index,
12950  Local<Value> value,
12951  const AccessorInfo& info) {
12953  return v8::Handle<Value>();
12954 }
12955 
12956 
12957 THREADED_TEST(PixelArrayWithInterceptor) {
12958  v8::HandleScope scope;
12959  LocalContext context;
12960  const int kElementCount = 260;
12961  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12964  FACTORY->NewExternalArray(kElementCount,
12966  pixel_data));
12967  for (int i = 0; i < kElementCount; i++) {
12968  pixels->set(i, i % 256);
12969  }
12971  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12972  NotHandledIndexedPropertySetter);
12973  v8::Handle<v8::Object> obj = templ->NewInstance();
12974  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12975  context->Global()->Set(v8_str("pixels"), obj);
12976  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12977  CHECK_EQ(1, result->Int32Value());
12978  result = CompileRun("var sum = 0;"
12979  "for (var i = 0; i < 8; i++) {"
12980  " sum += pixels[i] = pixels[i] = -i;"
12981  "}"
12982  "sum;");
12983  CHECK_EQ(-28, result->Int32Value());
12984  result = CompileRun("pixels.hasOwnProperty('1')");
12985  CHECK(result->BooleanValue());
12986  free(pixel_data);
12987 }
12988 
12989 
12990 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12991  switch (array_type) {
12995  return 1;
12996  break;
12999  return 2;
13000  break;
13001  case v8::kExternalIntArray:
13004  return 4;
13005  break;
13007  return 8;
13008  break;
13009  default:
13010  UNREACHABLE();
13011  return -1;
13012  }
13013  UNREACHABLE();
13014  return -1;
13015 }
13016 
13017 
13018 template <class ExternalArrayClass, class ElementType>
13019 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13020  int64_t low,
13021  int64_t high) {
13022  v8::HandleScope scope;
13023  LocalContext context;
13024  const int kElementCount = 40;
13025  int element_size = ExternalArrayElementSize(array_type);
13026  ElementType* array_data =
13027  static_cast<ElementType*>(malloc(kElementCount * element_size));
13030  FACTORY->NewExternalArray(kElementCount, array_type, array_data));
13031  // Force GC to trigger verification.
13032  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13033  for (int i = 0; i < kElementCount; i++) {
13034  array->set(i, static_cast<ElementType>(i));
13035  }
13036  // Force GC to trigger verification.
13037  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13038  for (int i = 0; i < kElementCount; i++) {
13039  CHECK_EQ(static_cast<int64_t>(i),
13040  static_cast<int64_t>(array->get_scalar(i)));
13041  CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13042  }
13043 
13046  // Set the elements to be the external array.
13048  array_type,
13049  kElementCount);
13050  CHECK_EQ(
13051  1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
13052  obj->Set(v8_str("field"), v8::Int32::New(1503));
13053  context->Global()->Set(v8_str("ext_array"), obj);
13054  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13055  CHECK_EQ(1503, result->Int32Value());
13056  result = CompileRun("ext_array[1]");
13057  CHECK_EQ(1, result->Int32Value());
13058 
13059  // Check pass through of assigned smis
13060  result = CompileRun("var sum = 0;"
13061  "for (var i = 0; i < 8; i++) {"
13062  " sum += ext_array[i] = ext_array[i] = -i;"
13063  "}"
13064  "sum;");
13065  CHECK_EQ(-28, result->Int32Value());
13066 
13067  // Check assigned smis
13068  result = CompileRun("for (var i = 0; i < 8; i++) {"
13069  " ext_array[i] = i;"
13070  "}"
13071  "var sum = 0;"
13072  "for (var i = 0; i < 8; i++) {"
13073  " sum += ext_array[i];"
13074  "}"
13075  "sum;");
13076  CHECK_EQ(28, result->Int32Value());
13077 
13078  // Check assigned smis in reverse order
13079  result = CompileRun("for (var i = 8; --i >= 0; ) {"
13080  " ext_array[i] = i;"
13081  "}"
13082  "var sum = 0;"
13083  "for (var i = 0; i < 8; i++) {"
13084  " sum += ext_array[i];"
13085  "}"
13086  "sum;");
13087  CHECK_EQ(28, result->Int32Value());
13088 
13089  // Check pass through of assigned HeapNumbers
13090  result = CompileRun("var sum = 0;"
13091  "for (var i = 0; i < 16; i+=2) {"
13092  " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13093  "}"
13094  "sum;");
13095  CHECK_EQ(-28, result->Int32Value());
13096 
13097  // Check assigned HeapNumbers
13098  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13099  " ext_array[i] = (i * 0.5);"
13100  "}"
13101  "var sum = 0;"
13102  "for (var i = 0; i < 16; i+=2) {"
13103  " sum += ext_array[i];"
13104  "}"
13105  "sum;");
13106  CHECK_EQ(28, result->Int32Value());
13107 
13108  // Check assigned HeapNumbers in reverse order
13109  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13110  " ext_array[i] = (i * 0.5);"
13111  "}"
13112  "var sum = 0;"
13113  "for (var i = 0; i < 16; i+=2) {"
13114  " sum += ext_array[i];"
13115  "}"
13116  "sum;");
13117  CHECK_EQ(28, result->Int32Value());
13118 
13119  i::ScopedVector<char> test_buf(1024);
13120 
13121  // Check legal boundary conditions.
13122  // The repeated loads and stores ensure the ICs are exercised.
13123  const char* boundary_program =
13124  "var res = 0;"
13125  "for (var i = 0; i < 16; i++) {"
13126  " ext_array[i] = %lld;"
13127  " if (i > 8) {"
13128  " res = ext_array[i];"
13129  " }"
13130  "}"
13131  "res;";
13132  i::OS::SNPrintF(test_buf,
13133  boundary_program,
13134  low);
13135  result = CompileRun(test_buf.start());
13136  CHECK_EQ(low, result->IntegerValue());
13137 
13138  i::OS::SNPrintF(test_buf,
13139  boundary_program,
13140  high);
13141  result = CompileRun(test_buf.start());
13142  CHECK_EQ(high, result->IntegerValue());
13143 
13144  // Check misprediction of type in IC.
13145  result = CompileRun("var tmp_array = ext_array;"
13146  "var sum = 0;"
13147  "for (var i = 0; i < 8; i++) {"
13148  " tmp_array[i] = i;"
13149  " sum += tmp_array[i];"
13150  " if (i == 4) {"
13151  " tmp_array = {};"
13152  " }"
13153  "}"
13154  "sum;");
13155  // Force GC to trigger verification.
13156  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13157  CHECK_EQ(28, result->Int32Value());
13158 
13159  // Make sure out-of-range loads do not throw.
13160  i::OS::SNPrintF(test_buf,
13161  "var caught_exception = false;"
13162  "try {"
13163  " ext_array[%d];"
13164  "} catch (e) {"
13165  " caught_exception = true;"
13166  "}"
13167  "caught_exception;",
13168  kElementCount);
13169  result = CompileRun(test_buf.start());
13170  CHECK_EQ(false, result->BooleanValue());
13171 
13172  // Make sure out-of-range stores do not throw.
13173  i::OS::SNPrintF(test_buf,
13174  "var caught_exception = false;"
13175  "try {"
13176  " ext_array[%d] = 1;"
13177  "} catch (e) {"
13178  " caught_exception = true;"
13179  "}"
13180  "caught_exception;",
13181  kElementCount);
13182  result = CompileRun(test_buf.start());
13183  CHECK_EQ(false, result->BooleanValue());
13184 
13185  // Check other boundary conditions, values and operations.
13186  result = CompileRun("for (var i = 0; i < 8; i++) {"
13187  " ext_array[7] = undefined;"
13188  "}"
13189  "ext_array[7];");
13190  CHECK_EQ(0, result->Int32Value());
13191  if (array_type == v8::kExternalDoubleArray ||
13192  array_type == v8::kExternalFloatArray) {
13193  CHECK_EQ(
13194  static_cast<int>(i::OS::nan_value()),
13195  static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13196  } else {
13197  CHECK_EQ(0, static_cast<int>(
13198  jsobj->GetElement(7)->ToObjectChecked()->Number()));
13199  }
13200 
13201  result = CompileRun("for (var i = 0; i < 8; i++) {"
13202  " ext_array[6] = '2.3';"
13203  "}"
13204  "ext_array[6];");
13205  CHECK_EQ(2, result->Int32Value());
13206  CHECK_EQ(
13207  2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
13208 
13209  if (array_type != v8::kExternalFloatArray &&
13210  array_type != v8::kExternalDoubleArray) {
13211  // Though the specification doesn't state it, be explicit about
13212  // converting NaNs and +/-Infinity to zero.
13213  result = CompileRun("for (var i = 0; i < 8; i++) {"
13214  " ext_array[i] = 5;"
13215  "}"
13216  "for (var i = 0; i < 8; i++) {"
13217  " ext_array[i] = NaN;"
13218  "}"
13219  "ext_array[5];");
13220  CHECK_EQ(0, result->Int32Value());
13221  CHECK_EQ(0,
13222  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13223 
13224  result = CompileRun("for (var i = 0; i < 8; i++) {"
13225  " ext_array[i] = 5;"
13226  "}"
13227  "for (var i = 0; i < 8; i++) {"
13228  " ext_array[i] = Infinity;"
13229  "}"
13230  "ext_array[5];");
13231  int expected_value =
13232  (array_type == v8::kExternalPixelArray) ? 255 : 0;
13233  CHECK_EQ(expected_value, result->Int32Value());
13234  CHECK_EQ(expected_value,
13235  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13236 
13237  result = CompileRun("for (var i = 0; i < 8; i++) {"
13238  " ext_array[i] = 5;"
13239  "}"
13240  "for (var i = 0; i < 8; i++) {"
13241  " ext_array[i] = -Infinity;"
13242  "}"
13243  "ext_array[5];");
13244  CHECK_EQ(0, result->Int32Value());
13245  CHECK_EQ(0,
13246  i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13247 
13248  // Check truncation behavior of integral arrays.
13249  const char* unsigned_data =
13250  "var source_data = [0.6, 10.6];"
13251  "var expected_results = [0, 10];";
13252  const char* signed_data =
13253  "var source_data = [0.6, 10.6, -0.6, -10.6];"
13254  "var expected_results = [0, 10, 0, -10];";
13255  const char* pixel_data =
13256  "var source_data = [0.6, 10.6];"
13257  "var expected_results = [1, 11];";
13258  bool is_unsigned =
13259  (array_type == v8::kExternalUnsignedByteArray ||
13260  array_type == v8::kExternalUnsignedShortArray ||
13261  array_type == v8::kExternalUnsignedIntArray);
13262  bool is_pixel_data = array_type == v8::kExternalPixelArray;
13263 
13264  i::OS::SNPrintF(test_buf,
13265  "%s"
13266  "var all_passed = true;"
13267  "for (var i = 0; i < source_data.length; i++) {"
13268  " for (var j = 0; j < 8; j++) {"
13269  " ext_array[j] = source_data[i];"
13270  " }"
13271  " all_passed = all_passed &&"
13272  " (ext_array[5] == expected_results[i]);"
13273  "}"
13274  "all_passed;",
13275  (is_unsigned ?
13276  unsigned_data :
13277  (is_pixel_data ? pixel_data : signed_data)));
13278  result = CompileRun(test_buf.start());
13279  CHECK_EQ(true, result->BooleanValue());
13280  }
13281 
13282  for (int i = 0; i < kElementCount; i++) {
13283  array->set(i, static_cast<ElementType>(i));
13284  }
13285  // Test complex assignments
13286  result = CompileRun("function ee_op_test_complex_func(sum) {"
13287  " for (var i = 0; i < 40; ++i) {"
13288  " sum += (ext_array[i] += 1);"
13289  " sum += (ext_array[i] -= 1);"
13290  " } "
13291  " return sum;"
13292  "}"
13293  "sum=0;"
13294  "for (var i=0;i<10000;++i) {"
13295  " sum=ee_op_test_complex_func(sum);"
13296  "}"
13297  "sum;");
13298  CHECK_EQ(16000000, result->Int32Value());
13299 
13300  // Test count operations
13301  result = CompileRun("function ee_op_test_count_func(sum) {"
13302  " for (var i = 0; i < 40; ++i) {"
13303  " sum += (++ext_array[i]);"
13304  " sum += (--ext_array[i]);"
13305  " } "
13306  " return sum;"
13307  "}"
13308  "sum=0;"
13309  "for (var i=0;i<10000;++i) {"
13310  " sum=ee_op_test_count_func(sum);"
13311  "}"
13312  "sum;");
13313  CHECK_EQ(16000000, result->Int32Value());
13314 
13315  result = CompileRun("ext_array[3] = 33;"
13316  "delete ext_array[3];"
13317  "ext_array[3];");
13318  CHECK_EQ(33, result->Int32Value());
13319 
13320  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13321  "ext_array[2] = 12; ext_array[3] = 13;"
13322  "ext_array.__defineGetter__('2',"
13323  "function() { return 120; });"
13324  "ext_array[2];");
13325  CHECK_EQ(12, result->Int32Value());
13326 
13327  result = CompileRun("var js_array = new Array(40);"
13328  "js_array[0] = 77;"
13329  "js_array;");
13330  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13331 
13332  result = CompileRun("ext_array[1] = 23;"
13333  "ext_array.__proto__ = [];"
13334  "js_array.__proto__ = ext_array;"
13335  "js_array.concat(ext_array);");
13336  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13337  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13338 
13339  result = CompileRun("ext_array[1] = 23;");
13340  CHECK_EQ(23, result->Int32Value());
13341 
13342  // Test more complex manipulations which cause eax to contain values
13343  // that won't be completely overwritten by loads from the arrays.
13344  // This catches bugs in the instructions used for the KeyedLoadIC
13345  // for byte and word types.
13346  {
13347  const int kXSize = 300;
13348  const int kYSize = 300;
13349  const int kLargeElementCount = kXSize * kYSize * 4;
13350  ElementType* large_array_data =
13351  static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
13353  // Set the elements to be the external array.
13354  large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13355  array_type,
13356  kLargeElementCount);
13357  context->Global()->Set(v8_str("large_array"), large_obj);
13358  // Initialize contents of a few rows.
13359  for (int x = 0; x < 300; x++) {
13360  int row = 0;
13361  int offset = row * 300 * 4;
13362  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13363  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13364  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13365  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13366  row = 150;
13367  offset = row * 300 * 4;
13368  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13369  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13370  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13371  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13372  row = 298;
13373  offset = row * 300 * 4;
13374  large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13375  large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13376  large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13377  large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13378  }
13379  // The goal of the code below is to make "offset" large enough
13380  // that the computation of the index (which goes into eax) has
13381  // high bits set which will not be overwritten by a byte or short
13382  // load.
13383  result = CompileRun("var failed = false;"
13384  "var offset = 0;"
13385  "for (var i = 0; i < 300; i++) {"
13386  " if (large_array[4 * i] != 127 ||"
13387  " large_array[4 * i + 1] != 0 ||"
13388  " large_array[4 * i + 2] != 0 ||"
13389  " large_array[4 * i + 3] != 127) {"
13390  " failed = true;"
13391  " }"
13392  "}"
13393  "offset = 150 * 300 * 4;"
13394  "for (var i = 0; i < 300; i++) {"
13395  " if (large_array[offset + 4 * i] != 127 ||"
13396  " large_array[offset + 4 * i + 1] != 0 ||"
13397  " large_array[offset + 4 * i + 2] != 0 ||"
13398  " large_array[offset + 4 * i + 3] != 127) {"
13399  " failed = true;"
13400  " }"
13401  "}"
13402  "offset = 298 * 300 * 4;"
13403  "for (var i = 0; i < 300; i++) {"
13404  " if (large_array[offset + 4 * i] != 127 ||"
13405  " large_array[offset + 4 * i + 1] != 0 ||"
13406  " large_array[offset + 4 * i + 2] != 0 ||"
13407  " large_array[offset + 4 * i + 3] != 127) {"
13408  " failed = true;"
13409  " }"
13410  "}"
13411  "!failed;");
13412  CHECK_EQ(true, result->BooleanValue());
13413  free(large_array_data);
13414  }
13415 
13416  // The "" property descriptor is overloaded to store information about
13417  // the external array. Ensure that setting and accessing the "" property
13418  // works (it should overwrite the information cached about the external
13419  // array in the DescriptorArray) in various situations.
13420  result = CompileRun("ext_array[''] = 23; ext_array['']");
13421  CHECK_EQ(23, result->Int32Value());
13422 
13423  // Property "" set after the external array is associated with the object.
13424  {
13426  obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13427  obj2->Set(v8_str(""), v8::Int32::New(1503));
13428  // Set the elements to be the external array.
13429  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13430  array_type,
13431  kElementCount);
13432  context->Global()->Set(v8_str("ext_array"), obj2);
13433  result = CompileRun("ext_array['']");
13434  CHECK_EQ(1503, result->Int32Value());
13435  }
13436 
13437  // Property "" set after the external array is associated with the object.
13438  {
13440  obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13441  // Set the elements to be the external array.
13442  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13443  array_type,
13444  kElementCount);
13445  obj2->Set(v8_str(""), v8::Int32::New(1503));
13446  context->Global()->Set(v8_str("ext_array"), obj2);
13447  result = CompileRun("ext_array['']");
13448  CHECK_EQ(1503, result->Int32Value());
13449  }
13450 
13451  // Should reuse the map from previous test.
13452  {
13454  obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13455  // Set the elements to be the external array. Should re-use the map
13456  // from previous test.
13457  obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13458  array_type,
13459  kElementCount);
13460  context->Global()->Set(v8_str("ext_array"), obj2);
13461  result = CompileRun("ext_array['']");
13462  }
13463 
13464  // Property "" is a constant function that shouldn't not be interfered with
13465  // when an external array is set.
13466  {
13468  // Start
13469  obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13470 
13471  // Add a constant function to an object.
13472  context->Global()->Set(v8_str("ext_array"), obj2);
13473  result = CompileRun("ext_array[''] = function() {return 1503;};"
13474  "ext_array['']();");
13475 
13476  // Add an external array transition to the same map that
13477  // has the constant transition.
13479  obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13480  obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13481  array_type,
13482  kElementCount);
13483  context->Global()->Set(v8_str("ext_array"), obj3);
13484  }
13485 
13486  // If a external array transition is in the map, it should get clobbered
13487  // by a constant function.
13488  {
13489  // Add an external array transition.
13491  obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13492  obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13493  array_type,
13494  kElementCount);
13495 
13496  // Add a constant function to the same map that just got an external array
13497  // transition.
13499  obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13500  context->Global()->Set(v8_str("ext_array"), obj2);
13501  result = CompileRun("ext_array[''] = function() {return 1503;};"
13502  "ext_array['']();");
13503  }
13504 
13505  free(array_data);
13506 }
13507 
13508 
13509 THREADED_TEST(ExternalByteArray) {
13510  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
13512  -128,
13513  127);
13514 }
13515 
13516 
13517 THREADED_TEST(ExternalUnsignedByteArray) {
13518  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
13520  0,
13521  255);
13522 }
13523 
13524 
13525 THREADED_TEST(ExternalPixelArray) {
13526  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13528  0,
13529  255);
13530 }
13531 
13532 
13533 THREADED_TEST(ExternalShortArray) {
13534  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
13536  -32768,
13537  32767);
13538 }
13539 
13540 
13541 THREADED_TEST(ExternalUnsignedShortArray) {
13542  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
13544  0,
13545  65535);
13546 }
13547 
13548 
13549 THREADED_TEST(ExternalIntArray) {
13550  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
13552  INT_MIN, // -2147483648
13553  INT_MAX); // 2147483647
13554 }
13555 
13556 
13557 THREADED_TEST(ExternalUnsignedIntArray) {
13558  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
13560  0,
13561  UINT_MAX); // 4294967295
13562 }
13563 
13564 
13565 THREADED_TEST(ExternalFloatArray) {
13566  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
13568  -500,
13569  500);
13570 }
13571 
13572 
13573 THREADED_TEST(ExternalDoubleArray) {
13574  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13576  -500,
13577  500);
13578 }
13579 
13580 
13581 THREADED_TEST(ExternalArrays) {
13582  TestExternalByteArray();
13583  TestExternalUnsignedByteArray();
13584  TestExternalShortArray();
13585  TestExternalUnsignedShortArray();
13586  TestExternalIntArray();
13587  TestExternalUnsignedIntArray();
13588  TestExternalFloatArray();
13589 }
13590 
13591 
13593  v8::HandleScope scope;
13594  LocalContext context;
13595  for (int size = 0; size < 100; size += 10) {
13596  int element_size = ExternalArrayElementSize(array_type);
13597  void* external_data = malloc(size * element_size);
13600  external_data, array_type, size);
13602  CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13605  free(external_data);
13606  }
13607 }
13608 
13609 
13610 THREADED_TEST(ExternalArrayInfo) {
13620 }
13621 
13622 
13623 THREADED_TEST(ScriptContextDependence) {
13624  v8::HandleScope scope;
13625  LocalContext c1;
13626  const char *source = "foo";
13629  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13630  CHECK_EQ(dep->Run()->Int32Value(), 100);
13631  CHECK_EQ(indep->Run()->Int32Value(), 100);
13632  LocalContext c2;
13633  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13634  CHECK_EQ(dep->Run()->Int32Value(), 100);
13635  CHECK_EQ(indep->Run()->Int32Value(), 101);
13636 }
13637 
13638 
13639 THREADED_TEST(StackTrace) {
13640  v8::HandleScope scope;
13641  LocalContext context;
13642  v8::TryCatch try_catch;
13643  const char *source = "function foo() { FAIL.FAIL; }; foo();";
13645  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13646  v8::Script::New(src, origin)->Run();
13647  CHECK(try_catch.HasCaught());
13648  v8::String::Utf8Value stack(try_catch.StackTrace());
13649  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13650 }
13651 
13652 
13653 // Checks that a StackFrame has certain expected values.
13654 void checkStackFrame(const char* expected_script_name,
13655  const char* expected_func_name, int expected_line_number,
13656  int expected_column, bool is_eval, bool is_constructor,
13658  v8::HandleScope scope;
13659  v8::String::Utf8Value func_name(frame->GetFunctionName());
13660  v8::String::Utf8Value script_name(frame->GetScriptName());
13661  if (*script_name == NULL) {
13662  // The situation where there is no associated script, like for evals.
13663  CHECK(expected_script_name == NULL);
13664  } else {
13665  CHECK(strstr(*script_name, expected_script_name) != NULL);
13666  }
13667  CHECK(strstr(*func_name, expected_func_name) != NULL);
13668  CHECK_EQ(expected_line_number, frame->GetLineNumber());
13669  CHECK_EQ(expected_column, frame->GetColumn());
13670  CHECK_EQ(is_eval, frame->IsEval());
13671  CHECK_EQ(is_constructor, frame->IsConstructor());
13672 }
13673 
13674 
13676  v8::HandleScope scope;
13677  const char* origin = "capture-stack-trace-test";
13678  const int kOverviewTest = 1;
13679  const int kDetailedTest = 2;
13680 
13681  ASSERT(args.Length() == 1);
13682 
13683  int testGroup = args[0]->Int32Value();
13684  if (testGroup == kOverviewTest) {
13685  v8::Handle<v8::StackTrace> stackTrace =
13687  CHECK_EQ(4, stackTrace->GetFrameCount());
13688  checkStackFrame(origin, "bar", 2, 10, false, false,
13689  stackTrace->GetFrame(0));
13690  checkStackFrame(origin, "foo", 6, 3, false, false,
13691  stackTrace->GetFrame(1));
13692  // This is the source string inside the eval which has the call to foo.
13693  checkStackFrame(NULL, "", 1, 5, false, false,
13694  stackTrace->GetFrame(2));
13695  // The last frame is an anonymous function which has the initial eval call.
13696  checkStackFrame(origin, "", 8, 7, false, false,
13697  stackTrace->GetFrame(3));
13698 
13699  CHECK(stackTrace->AsArray()->IsArray());
13700  } else if (testGroup == kDetailedTest) {
13701  v8::Handle<v8::StackTrace> stackTrace =
13703  CHECK_EQ(4, stackTrace->GetFrameCount());
13704  checkStackFrame(origin, "bat", 4, 22, false, false,
13705  stackTrace->GetFrame(0));
13706  checkStackFrame(origin, "baz", 8, 3, false, true,
13707  stackTrace->GetFrame(1));
13708 #ifdef ENABLE_DEBUGGER_SUPPORT
13709  bool is_eval = true;
13710 #else // ENABLE_DEBUGGER_SUPPORT
13711  bool is_eval = false;
13712 #endif // ENABLE_DEBUGGER_SUPPORT
13713 
13714  // This is the source string inside the eval which has the call to baz.
13715  checkStackFrame(NULL, "", 1, 5, is_eval, false,
13716  stackTrace->GetFrame(2));
13717  // The last frame is an anonymous function which has the initial eval call.
13718  checkStackFrame(origin, "", 10, 1, false, false,
13719  stackTrace->GetFrame(3));
13720 
13721  CHECK(stackTrace->AsArray()->IsArray());
13722  }
13723  return v8::Undefined();
13724 }
13725 
13726 
13727 // Tests the C++ StackTrace API.
13728 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13729 // THREADED_TEST(CaptureStackTrace) {
13730 TEST(CaptureStackTrace) {
13731  v8::HandleScope scope;
13732  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13733  Local<ObjectTemplate> templ = ObjectTemplate::New();
13734  templ->Set(v8_str("AnalyzeStackInNativeCode"),
13736  LocalContext context(0, templ);
13737 
13738  // Test getting OVERVIEW information. Should ignore information that is not
13739  // script name, function name, line number, and column offset.
13740  const char *overview_source =
13741  "function bar() {\n"
13742  " var y; AnalyzeStackInNativeCode(1);\n"
13743  "}\n"
13744  "function foo() {\n"
13745  "\n"
13746  " bar();\n"
13747  "}\n"
13748  "var x;eval('new foo();');";
13749  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
13750  v8::Handle<Value> overview_result(
13751  v8::Script::New(overview_src, origin)->Run());
13752  CHECK(!overview_result.IsEmpty());
13753  CHECK(overview_result->IsObject());
13754 
13755  // Test getting DETAILED information.
13756  const char *detailed_source =
13757  "function bat() {AnalyzeStackInNativeCode(2);\n"
13758  "}\n"
13759  "\n"
13760  "function baz() {\n"
13761  " bat();\n"
13762  "}\n"
13763  "eval('new baz();');";
13764  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13765  // Make the script using a non-zero line and column offset.
13766  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13767  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13768  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13769  v8::Handle<v8::Script> detailed_script(
13770  v8::Script::New(detailed_src, &detailed_origin));
13771  v8::Handle<Value> detailed_result(detailed_script->Run());
13772  CHECK(!detailed_result.IsEmpty());
13773  CHECK(detailed_result->IsObject());
13774 }
13775 
13776 
13777 static void StackTraceForUncaughtExceptionListener(
13778  v8::Handle<v8::Message> message,
13780  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13781  CHECK_EQ(2, stack_trace->GetFrameCount());
13782  checkStackFrame("origin", "foo", 2, 3, false, false,
13783  stack_trace->GetFrame(0));
13784  checkStackFrame("origin", "bar", 5, 3, false, false,
13785  stack_trace->GetFrame(1));
13786 }
13787 
13788 TEST(CaptureStackTraceForUncaughtException) {
13789  report_count = 0;
13790  v8::HandleScope scope;
13791  LocalContext env;
13792  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13794 
13795  Script::Compile(v8_str("function foo() {\n"
13796  " throw 1;\n"
13797  "};\n"
13798  "function bar() {\n"
13799  " foo();\n"
13800  "};"),
13801  v8_str("origin"))->Run();
13802  v8::Local<v8::Object> global = env->Global();
13803  Local<Value> trouble = global->Get(v8_str("bar"));
13804  CHECK(trouble->IsFunction());
13805  Function::Cast(*trouble)->Call(global, 0, NULL);
13807  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13808 }
13809 
13810 
13811 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13812  v8::HandleScope scope;
13813  LocalContext env;
13815  1024,
13817 
13818  CompileRun(
13819  "var setters = ['column', 'lineNumber', 'scriptName',\n"
13820  " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13821  " 'isConstructor'];\n"
13822  "for (var i = 0; i < setters.length; i++) {\n"
13823  " var prop = setters[i];\n"
13824  " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13825  "}\n");
13826  CompileRun("throw 'exception';");
13828 }
13829 
13830 
13831 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
13832  v8::Handle<v8::Value> data) {
13833  // Use the frame where JavaScript is called from.
13834  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13835  CHECK(!stack_trace.IsEmpty());
13836  int frame_count = stack_trace->GetFrameCount();
13837  CHECK_EQ(3, frame_count);
13838  int line_number[] = {1, 2, 5};
13839  for (int i = 0; i < frame_count; i++) {
13840  CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13841  }
13842 }
13843 
13844 
13845 // Test that we only return the stack trace at the site where the exception
13846 // is first thrown (not where it is rethrown).
13847 TEST(RethrowStackTrace) {
13848  v8::HandleScope scope;
13849  LocalContext env;
13850  // We make sure that
13851  // - the stack trace of the ReferenceError in g() is reported.
13852  // - the stack trace is not overwritten when e1 is rethrown by t().
13853  // - the stack trace of e2 does not overwrite that of e1.
13854  const char* source =
13855  "function g() { error; } \n"
13856  "function f() { g(); } \n"
13857  "function t(e) { throw e; } \n"
13858  "try { \n"
13859  " f(); \n"
13860  "} catch (e1) { \n"
13861  " try { \n"
13862  " error; \n"
13863  " } catch (e2) { \n"
13864  " t(e1); \n"
13865  " } \n"
13866  "} \n";
13867  v8::V8::AddMessageListener(RethrowStackTraceHandler);
13869  CompileRun(source);
13871  v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
13872 }
13873 
13874 
13875 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
13876  v8::Handle<v8::Value> data) {
13877  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13878  CHECK(!stack_trace.IsEmpty());
13879  int frame_count = stack_trace->GetFrameCount();
13880  CHECK_EQ(2, frame_count);
13881  int line_number[] = {3, 7};
13882  for (int i = 0; i < frame_count; i++) {
13883  CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13884  }
13885 }
13886 
13887 
13888 // Test that we do not recognize identity for primitive exceptions.
13889 TEST(RethrowPrimitiveStackTrace) {
13890  v8::HandleScope scope;
13891  LocalContext env;
13892  // We do not capture stack trace for non Error objects on creation time.
13893  // Instead, we capture the stack trace on last throw.
13894  const char* source =
13895  "function g() { throw 404; } \n"
13896  "function f() { g(); } \n"
13897  "function t(e) { throw e; } \n"
13898  "try { \n"
13899  " f(); \n"
13900  "} catch (e1) { \n"
13901  " t(e1) \n"
13902  "} \n";
13903  v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
13905  CompileRun(source);
13907  v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
13908 }
13909 
13910 
13911 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
13912  v8::Handle<v8::Value> data) {
13913  // Use the frame where JavaScript is called from.
13914  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13915  CHECK(!stack_trace.IsEmpty());
13916  CHECK_EQ(1, stack_trace->GetFrameCount());
13917  CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
13918 }
13919 
13920 
13921 // Test that the stack trace is captured when the error object is created and
13922 // not where it is thrown.
13923 TEST(RethrowExistingStackTrace) {
13924  v8::HandleScope scope;
13925  LocalContext env;
13926  const char* source =
13927  "var e = new Error(); \n"
13928  "throw e; \n";
13929  v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
13931  CompileRun(source);
13933  v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
13934 }
13935 
13936 
13937 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
13938  v8::Handle<v8::Value> data) {
13939  // Use the frame where JavaScript is called from.
13940  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13941  CHECK(!stack_trace.IsEmpty());
13942  CHECK_EQ(1, stack_trace->GetFrameCount());
13943  CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
13944 }
13945 
13946 
13947 // Test that the stack trace is captured where the bogus Error object is thrown.
13948 TEST(RethrowBogusErrorStackTrace) {
13949  v8::HandleScope scope;
13950  LocalContext env;
13951  const char* source =
13952  "var e = {__proto__: new Error()} \n"
13953  "throw e; \n";
13954  v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
13956  CompileRun(source);
13958  v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
13959 }
13960 
13961 
13963  v8::HandleScope scope;
13964  v8::Handle<v8::StackTrace> stackTrace =
13966  CHECK_EQ(5, stackTrace->GetFrameCount());
13967  v8::Handle<v8::String> url = v8_str("eval_url");
13968  for (int i = 0; i < 3; i++) {
13969  v8::Handle<v8::String> name =
13970  stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13971  CHECK(!name.IsEmpty());
13972  CHECK_EQ(url, name);
13973  }
13974  return v8::Undefined();
13975 }
13976 
13977 
13978 TEST(SourceURLInStackTrace) {
13979  v8::HandleScope scope;
13980  Local<ObjectTemplate> templ = ObjectTemplate::New();
13981  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13983  LocalContext context(0, templ);
13984 
13985  const char *source =
13986  "function outer() {\n"
13987  "function bar() {\n"
13988  " AnalyzeStackOfEvalWithSourceURL();\n"
13989  "}\n"
13990  "function foo() {\n"
13991  "\n"
13992  " bar();\n"
13993  "}\n"
13994  "foo();\n"
13995  "}\n"
13996  "eval('(' + outer +')()//@ sourceURL=eval_url');";
13997  CHECK(CompileRun(source)->IsUndefined());
13998 }
13999 
14000 
14001 static void CreateGarbageInOldSpace() {
14002  v8::HandleScope scope;
14003  i::AlwaysAllocateScope always_allocate;
14004  for (int i = 0; i < 1000; i++) {
14005  FACTORY->NewFixedArray(1000, i::TENURED);
14006  }
14007 }
14008 
14009 // Test that idle notification can be handled and eventually returns true.
14010 TEST(IdleNotification) {
14011  const intptr_t MB = 1024 * 1024;
14012  v8::HandleScope scope;
14013  LocalContext env;
14014  intptr_t initial_size = HEAP->SizeOfObjects();
14015  CreateGarbageInOldSpace();
14016  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14017  CHECK_GT(size_with_garbage, initial_size + MB);
14018  bool finished = false;
14019  for (int i = 0; i < 200 && !finished; i++) {
14020  finished = v8::V8::IdleNotification();
14021  }
14022  intptr_t final_size = HEAP->SizeOfObjects();
14023  CHECK(finished);
14024  CHECK_LT(final_size, initial_size + 1);
14025 }
14026 
14027 
14028 // Test that idle notification can be handled and eventually collects garbage.
14029 TEST(IdleNotificationWithSmallHint) {
14030  const intptr_t MB = 1024 * 1024;
14031  const int IdlePauseInMs = 900;
14032  v8::HandleScope scope;
14033  LocalContext env;
14034  intptr_t initial_size = HEAP->SizeOfObjects();
14035  CreateGarbageInOldSpace();
14036  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14037  CHECK_GT(size_with_garbage, initial_size + MB);
14038  bool finished = false;
14039  for (int i = 0; i < 200 && !finished; i++) {
14040  finished = v8::V8::IdleNotification(IdlePauseInMs);
14041  }
14042  intptr_t final_size = HEAP->SizeOfObjects();
14043  CHECK(finished);
14044  CHECK_LT(final_size, initial_size + 1);
14045 }
14046 
14047 
14048 // Test that idle notification can be handled and eventually collects garbage.
14049 TEST(IdleNotificationWithLargeHint) {
14050  const intptr_t MB = 1024 * 1024;
14051  const int IdlePauseInMs = 900;
14052  v8::HandleScope scope;
14053  LocalContext env;
14054  intptr_t initial_size = HEAP->SizeOfObjects();
14055  CreateGarbageInOldSpace();
14056  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14057  CHECK_GT(size_with_garbage, initial_size + MB);
14058  bool finished = false;
14059  for (int i = 0; i < 200 && !finished; i++) {
14060  finished = v8::V8::IdleNotification(IdlePauseInMs);
14061  }
14062  intptr_t final_size = HEAP->SizeOfObjects();
14063  CHECK(finished);
14064  CHECK_LT(final_size, initial_size + 1);
14065 }
14066 
14067 
14068 TEST(Regress2107) {
14069  const intptr_t MB = 1024 * 1024;
14070  const int kShortIdlePauseInMs = 100;
14071  const int kLongIdlePauseInMs = 1000;
14072  v8::HandleScope scope;
14073  LocalContext env;
14074  intptr_t initial_size = HEAP->SizeOfObjects();
14075  // Send idle notification to start a round of incremental GCs.
14076  v8::V8::IdleNotification(kShortIdlePauseInMs);
14077  // Emulate 7 page reloads.
14078  for (int i = 0; i < 7; i++) {
14080  ctx->Enter();
14081  CreateGarbageInOldSpace();
14082  ctx->Exit();
14083  ctx.Dispose();
14085  v8::V8::IdleNotification(kLongIdlePauseInMs);
14086  }
14087  // Create garbage and check that idle notification still collects it.
14088  CreateGarbageInOldSpace();
14089  intptr_t size_with_garbage = HEAP->SizeOfObjects();
14090  CHECK_GT(size_with_garbage, initial_size + MB);
14091  bool finished = false;
14092  for (int i = 0; i < 200 && !finished; i++) {
14093  finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14094  }
14095  intptr_t final_size = HEAP->SizeOfObjects();
14096  CHECK_LT(final_size, initial_size + 1);
14097 }
14098 
14099 static uint32_t* stack_limit;
14100 
14101 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
14102  stack_limit = reinterpret_cast<uint32_t*>(
14103  i::Isolate::Current()->stack_guard()->real_climit());
14104  return v8::Undefined();
14105 }
14106 
14107 
14108 // Uses the address of a local variable to determine the stack top now.
14109 // Given a size, returns an address that is that far from the current
14110 // top of stack.
14111 static uint32_t* ComputeStackLimit(uint32_t size) {
14112  uint32_t* answer = &size - (size / sizeof(size));
14113  // If the size is very large and the stack is very near the bottom of
14114  // memory then the calculation above may wrap around and give an address
14115  // that is above the (downwards-growing) stack. In that case we return
14116  // a very low address.
14117  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14118  return answer;
14119 }
14120 
14121 
14123  static const int K = 1024;
14124  uint32_t* set_limit = ComputeStackLimit(128 * K);
14125 
14126  // Set stack limit.
14127  v8::ResourceConstraints constraints;
14128  constraints.set_stack_limit(set_limit);
14129  CHECK(v8::SetResourceConstraints(&constraints));
14130 
14131  // Execute a script.
14132  v8::HandleScope scope;
14133  LocalContext env;
14134  Local<v8::FunctionTemplate> fun_templ =
14135  v8::FunctionTemplate::New(GetStackLimitCallback);
14136  Local<Function> fun = fun_templ->GetFunction();
14137  env->Global()->Set(v8_str("get_stack_limit"), fun);
14138  CompileRun("get_stack_limit();");
14139 
14140  CHECK(stack_limit == set_limit);
14141 }
14142 
14143 
14144 TEST(SetResourceConstraintsInThread) {
14145  uint32_t* set_limit;
14146  {
14147  v8::Locker locker;
14148  static const int K = 1024;
14149  set_limit = ComputeStackLimit(128 * K);
14150 
14151  // Set stack limit.
14152  v8::ResourceConstraints constraints;
14153  constraints.set_stack_limit(set_limit);
14154  CHECK(v8::SetResourceConstraints(&constraints));
14155 
14156  // Execute a script.
14157  v8::HandleScope scope;
14158  LocalContext env;
14159  Local<v8::FunctionTemplate> fun_templ =
14160  v8::FunctionTemplate::New(GetStackLimitCallback);
14161  Local<Function> fun = fun_templ->GetFunction();
14162  env->Global()->Set(v8_str("get_stack_limit"), fun);
14163  CompileRun("get_stack_limit();");
14164 
14165  CHECK(stack_limit == set_limit);
14166  }
14167  {
14168  v8::Locker locker;
14169  CHECK(stack_limit == set_limit);
14170  }
14171 }
14172 
14173 
14174 THREADED_TEST(GetHeapStatistics) {
14175  v8::HandleScope scope;
14176  LocalContext c1;
14177  v8::HeapStatistics heap_statistics;
14178  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14179  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
14180  v8::V8::GetHeapStatistics(&heap_statistics);
14181  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14182  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
14183 }
14184 
14185 
14187  public:
14189  : resource1_(r1),
14190  resource2_(r2),
14191  found_resource1_(false),
14192  found_resource2_(false) {}
14193  virtual ~VisitorImpl() {}
14195  if (!string->IsExternal()) {
14196  CHECK(string->IsExternalAscii());
14197  return;
14198  }
14200  string->GetExternalStringResource();
14201  CHECK(resource);
14202  if (resource1_ == resource) {
14203  CHECK(!found_resource1_);
14204  found_resource1_ = true;
14205  }
14206  if (resource2_ == resource) {
14207  CHECK(!found_resource2_);
14208  found_resource2_ = true;
14209  }
14210  }
14212  CHECK(found_resource1_);
14213  CHECK(found_resource2_);
14214  }
14215 
14216  private:
14219  bool found_resource1_;
14220  bool found_resource2_;
14221 };
14222 
14223 TEST(VisitExternalStrings) {
14224  v8::HandleScope scope;
14225  LocalContext env;
14226  const char* string = "Some string";
14227  uint16_t* two_byte_string = AsciiToTwoByteString(string);
14228  TestResource* resource1 = new TestResource(two_byte_string);
14229  v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
14230  TestResource* resource2 = new TestResource(two_byte_string);
14231  v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
14232 
14233  // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
14234  CHECK(string1->IsExternal());
14235  CHECK(string2->IsExternal());
14236 
14237  VisitorImpl visitor(resource1, resource2);
14239  visitor.CheckVisitedResources();
14240 }
14241 
14242 
14243 static double DoubleFromBits(uint64_t value) {
14244  double target;
14245  memcpy(&target, &value, sizeof(target));
14246  return target;
14247 }
14248 
14249 
14250 static uint64_t DoubleToBits(double value) {
14251  uint64_t target;
14252  memcpy(&target, &value, sizeof(target));
14253  return target;
14254 }
14255 
14256 
14257 static double DoubleToDateTime(double input) {
14258  double date_limit = 864e13;
14259  if (IsNaN(input) || input < -date_limit || input > date_limit) {
14260  return i::OS::nan_value();
14261  }
14262  return (input < 0) ? -(floor(-input)) : floor(input);
14263 }
14264 
14265 // We don't have a consistent way to write 64-bit constants syntactically, so we
14266 // split them into two 32-bit constants and combine them programmatically.
14267 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
14268  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
14269 }
14270 
14271 
14272 THREADED_TEST(QuietSignalingNaNs) {
14273  v8::HandleScope scope;
14274  LocalContext context;
14275  v8::TryCatch try_catch;
14276 
14277  // Special double values.
14278  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
14279  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
14280  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
14281  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
14282  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
14283  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
14284  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
14285 
14286  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
14287  // on either side of the epoch.
14288  double date_limit = 864e13;
14289 
14290  double test_values[] = {
14291  snan,
14292  qnan,
14293  infinity,
14294  max_normal,
14295  date_limit + 1,
14296  date_limit,
14297  min_normal,
14298  max_denormal,
14299  min_denormal,
14300  0,
14301  -0,
14302  -min_denormal,
14303  -max_denormal,
14304  -min_normal,
14305  -date_limit,
14306  -date_limit - 1,
14307  -max_normal,
14308  -infinity,
14309  -qnan,
14310  -snan
14311  };
14312  int num_test_values = 20;
14313 
14314  for (int i = 0; i < num_test_values; i++) {
14315  double test_value = test_values[i];
14316 
14317  // Check that Number::New preserves non-NaNs and quiets SNaNs.
14318  v8::Handle<v8::Value> number = v8::Number::New(test_value);
14319  double stored_number = number->NumberValue();
14320  if (!IsNaN(test_value)) {
14321  CHECK_EQ(test_value, stored_number);
14322  } else {
14323  uint64_t stored_bits = DoubleToBits(stored_number);
14324  // Check if quiet nan (bits 51..62 all set).
14325 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14326  // Most significant fraction bit for quiet nan is set to 0
14327  // on MIPS architecture. Allowed by IEEE-754.
14328  CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14329 #else
14330  CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14331 #endif
14332  }
14333 
14334  // Check that Date::New preserves non-NaNs in the date range and
14335  // quiets SNaNs.
14336  v8::Handle<v8::Value> date = v8::Date::New(test_value);
14337  double expected_stored_date = DoubleToDateTime(test_value);
14338  double stored_date = date->NumberValue();
14339  if (!IsNaN(expected_stored_date)) {
14340  CHECK_EQ(expected_stored_date, stored_date);
14341  } else {
14342  uint64_t stored_bits = DoubleToBits(stored_date);
14343  // Check if quiet nan (bits 51..62 all set).
14344 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14345  // Most significant fraction bit for quiet nan is set to 0
14346  // on MIPS architecture. Allowed by IEEE-754.
14347  CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14348 #else
14349  CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14350 #endif
14351  }
14352  }
14353 }
14354 
14355 
14356 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14357  v8::HandleScope scope;
14358  v8::TryCatch tc;
14359  v8::Handle<v8::String> str(args[0]->ToString());
14360  USE(str);
14361  if (tc.HasCaught())
14362  return tc.ReThrow();
14363  return v8::Undefined();
14364 }
14365 
14366 
14367 // Test that an exception can be propagated down through a spaghetti
14368 // stack using ReThrow.
14369 THREADED_TEST(SpaghettiStackReThrow) {
14370  v8::HandleScope scope;
14371  LocalContext context;
14372  context->Global()->Set(
14373  v8::String::New("s"),
14374  v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
14375  v8::TryCatch try_catch;
14376  CompileRun(
14377  "var i = 0;"
14378  "var o = {"
14379  " toString: function () {"
14380  " if (i == 10) {"
14381  " throw 'Hey!';"
14382  " } else {"
14383  " i++;"
14384  " return s(o);"
14385  " }"
14386  " }"
14387  "};"
14388  "s(o);");
14389  CHECK(try_catch.HasCaught());
14390  v8::String::Utf8Value value(try_catch.Exception());
14391  CHECK_EQ(0, strcmp(*value, "Hey!"));
14392 }
14393 
14394 
14395 TEST(Regress528) {
14397 
14398  v8::HandleScope scope;
14399  v8::Persistent<Context> context;
14400  v8::Persistent<Context> other_context;
14401  int gc_count;
14402 
14403  // Create a context used to keep the code from aging in the compilation
14404  // cache.
14405  other_context = Context::New();
14406 
14407  // Context-dependent context data creates reference from the compilation
14408  // cache to the global object.
14409  const char* source_simple = "1";
14410  context = Context::New();
14411  {
14412  v8::HandleScope scope;
14413 
14414  context->Enter();
14415  Local<v8::String> obj = v8::String::New("");
14416  context->SetData(obj);
14417  CompileRun(source_simple);
14418  context->Exit();
14419  }
14420  context.Dispose();
14421  for (gc_count = 1; gc_count < 10; gc_count++) {
14422  other_context->Enter();
14423  CompileRun(source_simple);
14424  other_context->Exit();
14425  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14426  if (GetGlobalObjectsCount() == 1) break;
14427  }
14428  CHECK_GE(2, gc_count);
14429  CHECK_EQ(1, GetGlobalObjectsCount());
14430 
14431  // Eval in a function creates reference from the compilation cache to the
14432  // global object.
14433  const char* source_eval = "function f(){eval('1')}; f()";
14434  context = Context::New();
14435  {
14436  v8::HandleScope scope;
14437 
14438  context->Enter();
14439  CompileRun(source_eval);
14440  context->Exit();
14441  }
14442  context.Dispose();
14443  for (gc_count = 1; gc_count < 10; gc_count++) {
14444  other_context->Enter();
14445  CompileRun(source_eval);
14446  other_context->Exit();
14447  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14448  if (GetGlobalObjectsCount() == 1) break;
14449  }
14450  CHECK_GE(2, gc_count);
14451  CHECK_EQ(1, GetGlobalObjectsCount());
14452 
14453  // Looking up the line number for an exception creates reference from the
14454  // compilation cache to the global object.
14455  const char* source_exception = "function f(){throw 1;} f()";
14456  context = Context::New();
14457  {
14458  v8::HandleScope scope;
14459 
14460  context->Enter();
14461  v8::TryCatch try_catch;
14462  CompileRun(source_exception);
14463  CHECK(try_catch.HasCaught());
14464  v8::Handle<v8::Message> message = try_catch.Message();
14465  CHECK(!message.IsEmpty());
14466  CHECK_EQ(1, message->GetLineNumber());
14467  context->Exit();
14468  }
14469  context.Dispose();
14470  for (gc_count = 1; gc_count < 10; gc_count++) {
14471  other_context->Enter();
14472  CompileRun(source_exception);
14473  other_context->Exit();
14474  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14475  if (GetGlobalObjectsCount() == 1) break;
14476  }
14477  CHECK_GE(2, gc_count);
14478  CHECK_EQ(1, GetGlobalObjectsCount());
14479 
14480  other_context.Dispose();
14481 }
14482 
14483 
14484 THREADED_TEST(ScriptOrigin) {
14485  v8::HandleScope scope;
14486  LocalContext env;
14489  "function f() {}\n\nfunction g() {}");
14490  v8::Script::Compile(script, &origin)->Run();
14492  env->Global()->Get(v8::String::New("f")));
14494  env->Global()->Get(v8::String::New("g")));
14495 
14496  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
14497  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
14498  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
14499 
14500  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
14501  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
14502  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
14503 }
14504 
14505 THREADED_TEST(FunctionGetInferredName) {
14506  v8::HandleScope scope;
14507  LocalContext env;
14510  "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
14511  v8::Script::Compile(script, &origin)->Run();
14513  env->Global()->Get(v8::String::New("f")));
14514  CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
14515 }
14516 
14517 THREADED_TEST(ScriptLineNumber) {
14518  v8::HandleScope scope;
14519  LocalContext env;
14522  "function f() {}\n\nfunction g() {}");
14523  v8::Script::Compile(script, &origin)->Run();
14525  env->Global()->Get(v8::String::New("f")));
14527  env->Global()->Get(v8::String::New("g")));
14528  CHECK_EQ(0, f->GetScriptLineNumber());
14529  CHECK_EQ(2, g->GetScriptLineNumber());
14530 }
14531 
14532 
14533 THREADED_TEST(ScriptColumnNumber) {
14534  v8::HandleScope scope;
14535  LocalContext env;
14539  "function foo() {}\n\n function bar() {}");
14540  v8::Script::Compile(script, &origin)->Run();
14542  env->Global()->Get(v8::String::New("foo")));
14544  env->Global()->Get(v8::String::New("bar")));
14545  CHECK_EQ(14, foo->GetScriptColumnNumber());
14546  CHECK_EQ(17, bar->GetScriptColumnNumber());
14547 }
14548 
14549 
14550 THREADED_TEST(FunctionGetScriptId) {
14551  v8::HandleScope scope;
14552  LocalContext env;
14555  v8::Handle<v8::String> scriptSource = v8::String::New(
14556  "function foo() {}\n\n function bar() {}");
14557  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
14558  script->Run();
14560  env->Global()->Get(v8::String::New("foo")));
14562  env->Global()->Get(v8::String::New("bar")));
14563  CHECK_EQ(script->Id(), foo->GetScriptId());
14564  CHECK_EQ(script->Id(), bar->GetScriptId());
14565 }
14566 
14567 
14568 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
14569  const AccessorInfo& info) {
14570  return v8_num(42);
14571 }
14572 
14573 
14574 static void SetterWhichSetsYOnThisTo23(Local<String> name,
14575  Local<Value> value,
14576  const AccessorInfo& info) {
14577  info.This()->Set(v8_str("y"), v8_num(23));
14578 }
14579 
14580 
14581 TEST(SetterOnConstructorPrototype) {
14582  v8::HandleScope scope;
14583  Local<ObjectTemplate> templ = ObjectTemplate::New();
14584  templ->SetAccessor(v8_str("x"),
14585  GetterWhichReturns42,
14586  SetterWhichSetsYOnThisTo23);
14587  LocalContext context;
14588  context->Global()->Set(v8_str("P"), templ->NewInstance());
14589  CompileRun("function C1() {"
14590  " this.x = 23;"
14591  "};"
14592  "C1.prototype = P;"
14593  "function C2() {"
14594  " this.x = 23"
14595  "};"
14596  "C2.prototype = { };"
14597  "C2.prototype.__proto__ = P;");
14598 
14599  v8::Local<v8::Script> script;
14600  script = v8::Script::Compile(v8_str("new C1();"));
14601  for (int i = 0; i < 10; i++) {
14603  CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14604  CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14605  }
14606 
14607  script = v8::Script::Compile(v8_str("new C2();"));
14608  for (int i = 0; i < 10; i++) {
14610  CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
14611  CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
14612  }
14613 }
14614 
14615 
14616 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
14617  Local<String> name, const AccessorInfo& info) {
14618  return v8_num(42);
14619 }
14620 
14621 
14622 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
14623  Local<String> name, Local<Value> value, const AccessorInfo& info) {
14624  if (name->Equals(v8_str("x"))) {
14625  info.This()->Set(v8_str("y"), v8_num(23));
14626  }
14627  return v8::Handle<Value>();
14628 }
14629 
14630 
14631 THREADED_TEST(InterceptorOnConstructorPrototype) {
14632  v8::HandleScope scope;
14633  Local<ObjectTemplate> templ = ObjectTemplate::New();
14634  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
14635  NamedPropertySetterWhichSetsYOnThisTo23);
14636  LocalContext context;
14637  context->Global()->Set(v8_str("P"), templ->NewInstance());
14638  CompileRun("function C1() {"
14639  " this.x = 23;"
14640  "};"
14641  "C1.prototype = P;"
14642  "function C2() {"
14643  " this.x = 23"
14644  "};"
14645  "C2.prototype = { };"
14646  "C2.prototype.__proto__ = P;");
14647 
14648  v8::Local<v8::Script> script;
14649  script = v8::Script::Compile(v8_str("new C1();"));
14650  for (int i = 0; i < 10; i++) {
14652  CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14653  CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14654  }
14655 
14656  script = v8::Script::Compile(v8_str("new C2();"));
14657  for (int i = 0; i < 10; i++) {
14659  CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
14660  CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
14661  }
14662 }
14663 
14664 
14665 TEST(Bug618) {
14666  const char* source = "function C1() {"
14667  " this.x = 23;"
14668  "};"
14669  "C1.prototype = P;";
14670 
14671  v8::HandleScope scope;
14672  LocalContext context;
14673  v8::Local<v8::Script> script;
14674 
14675  // Use a simple object as prototype.
14676  v8::Local<v8::Object> prototype = v8::Object::New();
14677  prototype->Set(v8_str("y"), v8_num(42));
14678  context->Global()->Set(v8_str("P"), prototype);
14679 
14680  // This compile will add the code to the compilation cache.
14681  CompileRun(source);
14682 
14683  script = v8::Script::Compile(v8_str("new C1();"));
14684  // Allow enough iterations for the inobject slack tracking logic
14685  // to finalize instance size and install the fast construct stub.
14686  for (int i = 0; i < 256; i++) {
14688  CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14689  CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14690  }
14691 
14692  // Use an API object with accessors as prototype.
14693  Local<ObjectTemplate> templ = ObjectTemplate::New();
14694  templ->SetAccessor(v8_str("x"),
14695  GetterWhichReturns42,
14696  SetterWhichSetsYOnThisTo23);
14697  context->Global()->Set(v8_str("P"), templ->NewInstance());
14698 
14699  // This compile will get the code from the compilation cache.
14700  CompileRun(source);
14701 
14702  script = v8::Script::Compile(v8_str("new C1();"));
14703  for (int i = 0; i < 10; i++) {
14705  CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14706  CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14707  }
14708 }
14709 
14714 
14717 }
14718 
14721 }
14722 
14725 }
14726 
14729 }
14730 
14731 TEST(GCCallbacks) {
14732  LocalContext context;
14733 
14736  CHECK_EQ(0, prologue_call_count);
14737  CHECK_EQ(0, epilogue_call_count);
14738  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14739  CHECK_EQ(1, prologue_call_count);
14740  CHECK_EQ(1, epilogue_call_count);
14743  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14744  CHECK_EQ(2, prologue_call_count);
14745  CHECK_EQ(2, epilogue_call_count);
14746  CHECK_EQ(1, prologue_call_count_second);
14747  CHECK_EQ(1, epilogue_call_count_second);
14750  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14751  CHECK_EQ(2, prologue_call_count);
14752  CHECK_EQ(2, epilogue_call_count);
14753  CHECK_EQ(2, prologue_call_count_second);
14754  CHECK_EQ(2, epilogue_call_count_second);
14757  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14758  CHECK_EQ(2, prologue_call_count);
14759  CHECK_EQ(2, epilogue_call_count);
14760  CHECK_EQ(2, prologue_call_count_second);
14761  CHECK_EQ(2, epilogue_call_count_second);
14762 }
14763 
14764 
14765 THREADED_TEST(AddToJSFunctionResultCache) {
14766  i::FLAG_allow_natives_syntax = true;
14767  v8::HandleScope scope;
14768 
14769  LocalContext context;
14770 
14771  const char* code =
14772  "(function() {"
14773  " var key0 = 'a';"
14774  " var key1 = 'b';"
14775  " var r0 = %_GetFromCache(0, key0);"
14776  " var r1 = %_GetFromCache(0, key1);"
14777  " var r0_ = %_GetFromCache(0, key0);"
14778  " if (r0 !== r0_)"
14779  " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14780  " var r1_ = %_GetFromCache(0, key1);"
14781  " if (r1 !== r1_)"
14782  " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14783  " return 'PASSED';"
14784  "})()";
14785  HEAP->ClearJSFunctionResultCaches();
14786  ExpectString(code, "PASSED");
14787 }
14788 
14789 
14790 static const int k0CacheSize = 16;
14791 
14792 THREADED_TEST(FillJSFunctionResultCache) {
14793  i::FLAG_allow_natives_syntax = true;
14794  v8::HandleScope scope;
14795 
14796  LocalContext context;
14797 
14798  const char* code =
14799  "(function() {"
14800  " var k = 'a';"
14801  " var r = %_GetFromCache(0, k);"
14802  " for (var i = 0; i < 16; i++) {"
14803  " %_GetFromCache(0, 'a' + i);"
14804  " };"
14805  " if (r === %_GetFromCache(0, k))"
14806  " return 'FAILED: k0CacheSize is too small';"
14807  " return 'PASSED';"
14808  "})()";
14809  HEAP->ClearJSFunctionResultCaches();
14810  ExpectString(code, "PASSED");
14811 }
14812 
14813 
14814 THREADED_TEST(RoundRobinGetFromCache) {
14815  i::FLAG_allow_natives_syntax = true;
14816  v8::HandleScope scope;
14817 
14818  LocalContext context;
14819 
14820  const char* code =
14821  "(function() {"
14822  " var keys = [];"
14823  " for (var i = 0; i < 16; i++) keys.push(i);"
14824  " var values = [];"
14825  " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14826  " for (var i = 0; i < 16; i++) {"
14827  " var v = %_GetFromCache(0, keys[i]);"
14828  " if (v.toString() !== values[i].toString())"
14829  " return 'Wrong value for ' + "
14830  " keys[i] + ': ' + v + ' vs. ' + values[i];"
14831  " };"
14832  " return 'PASSED';"
14833  "})()";
14834  HEAP->ClearJSFunctionResultCaches();
14835  ExpectString(code, "PASSED");
14836 }
14837 
14838 
14839 THREADED_TEST(ReverseGetFromCache) {
14840  i::FLAG_allow_natives_syntax = true;
14841  v8::HandleScope scope;
14842 
14843  LocalContext context;
14844 
14845  const char* code =
14846  "(function() {"
14847  " var keys = [];"
14848  " for (var i = 0; i < 16; i++) keys.push(i);"
14849  " var values = [];"
14850  " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14851  " for (var i = 15; i >= 16; i--) {"
14852  " var v = %_GetFromCache(0, keys[i]);"
14853  " if (v !== values[i])"
14854  " return 'Wrong value for ' + "
14855  " keys[i] + ': ' + v + ' vs. ' + values[i];"
14856  " };"
14857  " return 'PASSED';"
14858  "})()";
14859  HEAP->ClearJSFunctionResultCaches();
14860  ExpectString(code, "PASSED");
14861 }
14862 
14863 
14864 THREADED_TEST(TestEviction) {
14865  i::FLAG_allow_natives_syntax = true;
14866  v8::HandleScope scope;
14867 
14868  LocalContext context;
14869 
14870  const char* code =
14871  "(function() {"
14872  " for (var i = 0; i < 2*16; i++) {"
14873  " %_GetFromCache(0, 'a' + i);"
14874  " };"
14875  " return 'PASSED';"
14876  "})()";
14877  HEAP->ClearJSFunctionResultCaches();
14878  ExpectString(code, "PASSED");
14879 }
14880 
14881 
14882 THREADED_TEST(TwoByteStringInAsciiCons) {
14883  // See Chromium issue 47824.
14884  v8::HandleScope scope;
14885 
14886  LocalContext context;
14887  const char* init_code =
14888  "var str1 = 'abelspendabel';"
14889  "var str2 = str1 + str1 + str1;"
14890  "str2;";
14891  Local<Value> result = CompileRun(init_code);
14892 
14893  Local<Value> indexof = CompileRun("str2.indexOf('els')");
14894  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14895 
14896  CHECK(result->IsString());
14897  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14898  int length = string->length();
14899  CHECK(string->IsAsciiRepresentation());
14900 
14901  FlattenString(string);
14902  i::Handle<i::String> flat_string = FlattenGetString(string);
14903 
14904  CHECK(string->IsAsciiRepresentation());
14905  CHECK(flat_string->IsAsciiRepresentation());
14906 
14907  // Create external resource.
14908  uint16_t* uc16_buffer = new uint16_t[length + 1];
14909 
14910  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14911  uc16_buffer[length] = 0;
14912 
14913  TestResource resource(uc16_buffer);
14914 
14915  flat_string->MakeExternal(&resource);
14916 
14917  CHECK(flat_string->IsTwoByteRepresentation());
14918 
14919  // At this point, we should have a Cons string which is flat and ASCII,
14920  // with a first half that is a two-byte string (although it only contains
14921  // ASCII characters). This is a valid sequence of steps, and it can happen
14922  // in real pages.
14923 
14924  CHECK(string->IsAsciiRepresentation());
14925  i::ConsString* cons = i::ConsString::cast(*string);
14926  CHECK_EQ(0, cons->second()->length());
14927  CHECK(cons->first()->IsTwoByteRepresentation());
14928 
14929  // Check that some string operations work.
14930 
14931  // Atom RegExp.
14932  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14933  CHECK_EQ(6, reresult->Int32Value());
14934 
14935  // Nonatom RegExp.
14936  reresult = CompileRun("str2.match(/abe./g).length;");
14937  CHECK_EQ(6, reresult->Int32Value());
14938 
14939  reresult = CompileRun("str2.search(/bel/g);");
14940  CHECK_EQ(1, reresult->Int32Value());
14941 
14942  reresult = CompileRun("str2.search(/be./g);");
14943  CHECK_EQ(1, reresult->Int32Value());
14944 
14945  ExpectTrue("/bel/g.test(str2);");
14946 
14947  ExpectTrue("/be./g.test(str2);");
14948 
14949  reresult = CompileRun("/bel/g.exec(str2);");
14950  CHECK(!reresult->IsNull());
14951 
14952  reresult = CompileRun("/be./g.exec(str2);");
14953  CHECK(!reresult->IsNull());
14954 
14955  ExpectString("str2.substring(2, 10);", "elspenda");
14956 
14957  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14958 
14959  ExpectString("str2.charAt(2);", "e");
14960 
14961  ExpectObject("str2.indexOf('els');", indexof);
14962 
14963  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14964 
14965  reresult = CompileRun("str2.charCodeAt(2);");
14966  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14967 }
14968 
14969 
14970 // Failed access check callback that performs a GC on each invocation.
14971 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14972  v8::AccessType type,
14973  Local<v8::Value> data) {
14974  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14975 }
14976 
14977 
14978 TEST(GCInFailedAccessCheckCallback) {
14979  // Install a failed access check callback that performs a GC on each
14980  // invocation. Then force the callback to be called from va
14981 
14984 
14985  v8::HandleScope scope;
14986 
14987  // Create an ObjectTemplate for global objects and install access
14988  // check callbacks that will block access.
14990  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14991  IndexedGetAccessBlocker,
14993  false);
14994 
14995  // Create a context and set an x property on it's global object.
14996  LocalContext context0(NULL, global_template);
14997  context0->Global()->Set(v8_str("x"), v8_num(42));
14998  v8::Handle<v8::Object> global0 = context0->Global();
14999 
15000  // Create a context with a different security token so that the
15001  // failed access check callback will be called on each access.
15002  LocalContext context1(NULL, global_template);
15003  context1->Global()->Set(v8_str("other"), global0);
15004 
15005  // Get property with failed access check.
15006  ExpectUndefined("other.x");
15007 
15008  // Get element with failed access check.
15009  ExpectUndefined("other[0]");
15010 
15011  // Set property with failed access check.
15012  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15013  CHECK(result->IsObject());
15014 
15015  // Set element with failed access check.
15016  result = CompileRun("other[0] = new Object()");
15017  CHECK(result->IsObject());
15018 
15019  // Get property attribute with failed access check.
15020  ExpectFalse("\'x\' in other");
15021 
15022  // Get property attribute for element with failed access check.
15023  ExpectFalse("0 in other");
15024 
15025  // Delete property.
15026  ExpectFalse("delete other.x");
15027 
15028  // Delete element.
15029  CHECK_EQ(false, global0->Delete(0));
15030 
15031  // DefineAccessor.
15032  CHECK_EQ(false,
15033  global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15034 
15035  // Define JavaScript accessor.
15036  ExpectUndefined("Object.prototype.__defineGetter__.call("
15037  " other, \'x\', function() { return 42; })");
15038 
15039  // LookupAccessor.
15040  ExpectUndefined("Object.prototype.__lookupGetter__.call("
15041  " other, \'x\')");
15042 
15043  // HasLocalElement.
15044  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15045 
15046  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15047  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15048  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15049 
15050  // Reset the failed access check callback so it does not influence
15051  // the other tests.
15053 }
15054 
15055 TEST(DefaultIsolateGetCurrent) {
15057  v8::Isolate* isolate = v8::Isolate::GetCurrent();
15058  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15059  printf("*** %s\n", "DefaultIsolateGetCurrent success");
15060 }
15061 
15062 TEST(IsolateNewDispose) {
15063  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15064  v8::Isolate* isolate = v8::Isolate::New();
15065  CHECK(isolate != NULL);
15066  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15067  CHECK(current_isolate != isolate);
15068  CHECK(current_isolate == v8::Isolate::GetCurrent());
15069 
15071  last_location = last_message = NULL;
15072  isolate->Dispose();
15073  CHECK_EQ(last_location, NULL);
15074  CHECK_EQ(last_message, NULL);
15075 }
15076 
15077 TEST(IsolateEnterExitDefault) {
15078  v8::HandleScope scope;
15079  LocalContext context;
15080  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15081  CHECK(current_isolate != NULL); // Default isolate.
15082  ExpectString("'hello'", "hello");
15083  current_isolate->Enter();
15084  ExpectString("'still working'", "still working");
15085  current_isolate->Exit();
15086  ExpectString("'still working 2'", "still working 2");
15087  current_isolate->Exit();
15088  // Default isolate is always, well, 'default current'.
15089  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15090  // Still working since default isolate is auto-entering any thread
15091  // that has no isolate and attempts to execute V8 APIs.
15092  ExpectString("'still working 3'", "still working 3");
15093 }
15094 
15095 TEST(DisposeDefaultIsolate) {
15097 
15098  // Run some V8 code to trigger default isolate to become 'current'.
15099  v8::HandleScope scope;
15100  LocalContext context;
15101  ExpectString("'run some V8'", "run some V8");
15102 
15103  v8::Isolate* isolate = v8::Isolate::GetCurrent();
15104  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15105  last_location = last_message = NULL;
15106  isolate->Dispose();
15107  // It is not possible to dispose default isolate via Isolate API.
15108  CHECK_NE(last_location, NULL);
15109  CHECK_NE(last_message, NULL);
15110 }
15111 
15112 TEST(RunDefaultAndAnotherIsolate) {
15113  v8::HandleScope scope;
15114  LocalContext context;
15115 
15116  // Enter new isolate.
15117  v8::Isolate* isolate = v8::Isolate::New();
15118  CHECK(isolate);
15119  isolate->Enter();
15120  { // Need this block because subsequent Exit() will deallocate Heap,
15121  // so we need all scope objects to be deconstructed when it happens.
15122  v8::HandleScope scope_new;
15123  LocalContext context_new;
15124 
15125  // Run something in new isolate.
15126  CompileRun("var foo = 153;");
15127  ExpectTrue("function f() { return foo == 153; }; f()");
15128  }
15129  isolate->Exit();
15130 
15131  // This runs automatically in default isolate.
15132  // Variables in another isolate should be not available.
15133  ExpectTrue("function f() {"
15134  " try {"
15135  " foo;"
15136  " return false;"
15137  " } catch(e) {"
15138  " return true;"
15139  " }"
15140  "};"
15141  "var bar = 371;"
15142  "f()");
15143 
15145  last_location = last_message = NULL;
15146  isolate->Dispose();
15147  CHECK_EQ(last_location, NULL);
15148  CHECK_EQ(last_message, NULL);
15149 
15150  // Check that default isolate still runs.
15151  ExpectTrue("function f() { return bar == 371; }; f()");
15152 }
15153 
15154 TEST(DisposeIsolateWhenInUse) {
15155  v8::Isolate* isolate = v8::Isolate::New();
15156  CHECK(isolate);
15157  isolate->Enter();
15158  v8::HandleScope scope;
15159  LocalContext context;
15160  // Run something in this isolate.
15161  ExpectTrue("true");
15163  last_location = last_message = NULL;
15164  // Still entered, should fail.
15165  isolate->Dispose();
15166  CHECK_NE(last_location, NULL);
15167  CHECK_NE(last_message, NULL);
15168 }
15169 
15170 TEST(RunTwoIsolatesOnSingleThread) {
15171  // Run isolate 1.
15172  v8::Isolate* isolate1 = v8::Isolate::New();
15173  isolate1->Enter();
15175 
15176  {
15177  v8::Context::Scope cscope(context1);
15178  v8::HandleScope scope;
15179  // Run something in new isolate.
15180  CompileRun("var foo = 'isolate 1';");
15181  ExpectString("function f() { return foo; }; f()", "isolate 1");
15182  }
15183 
15184  // Run isolate 2.
15185  v8::Isolate* isolate2 = v8::Isolate::New();
15186  v8::Persistent<v8::Context> context2;
15187 
15188  {
15189  v8::Isolate::Scope iscope(isolate2);
15190  context2 = v8::Context::New();
15191  v8::Context::Scope cscope(context2);
15192  v8::HandleScope scope;
15193 
15194  // Run something in new isolate.
15195  CompileRun("var foo = 'isolate 2';");
15196  ExpectString("function f() { return foo; }; f()", "isolate 2");
15197  }
15198 
15199  {
15200  v8::Context::Scope cscope(context1);
15201  v8::HandleScope scope;
15202  // Now again in isolate 1
15203  ExpectString("function f() { return foo; }; f()", "isolate 1");
15204  }
15205 
15206  isolate1->Exit();
15207 
15208  // Run some stuff in default isolate.
15209  v8::Persistent<v8::Context> context_default = v8::Context::New();
15210 
15211  {
15212  v8::Context::Scope cscope(context_default);
15213  v8::HandleScope scope;
15214  // Variables in other isolates should be not available, verify there
15215  // is an exception.
15216  ExpectTrue("function f() {"
15217  " try {"
15218  " foo;"
15219  " return false;"
15220  " } catch(e) {"
15221  " return true;"
15222  " }"
15223  "};"
15224  "var isDefaultIsolate = true;"
15225  "f()");
15226  }
15227 
15228  isolate1->Enter();
15229 
15230  {
15231  v8::Isolate::Scope iscope(isolate2);
15232  v8::Context::Scope cscope(context2);
15233  v8::HandleScope scope;
15234  ExpectString("function f() { return foo; }; f()", "isolate 2");
15235  }
15236 
15237  {
15238  v8::Context::Scope cscope(context1);
15239  v8::HandleScope scope;
15240  ExpectString("function f() { return foo; }; f()", "isolate 1");
15241  }
15242 
15243  {
15244  v8::Isolate::Scope iscope(isolate2);
15245  context2.Dispose();
15246  }
15247 
15248  context1.Dispose();
15249  isolate1->Exit();
15250 
15252  last_location = last_message = NULL;
15253 
15254  isolate1->Dispose();
15255  CHECK_EQ(last_location, NULL);
15256  CHECK_EQ(last_message, NULL);
15257 
15258  isolate2->Dispose();
15259  CHECK_EQ(last_location, NULL);
15260  CHECK_EQ(last_message, NULL);
15261 
15262  // Check that default isolate still runs.
15263  {
15264  v8::Context::Scope cscope(context_default);
15265  v8::HandleScope scope;
15266  ExpectTrue("function f() { return isDefaultIsolate; }; f()");
15267  }
15268 }
15269 
15270 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
15271  v8::Isolate::Scope isolate_scope(isolate);
15272  v8::HandleScope scope;
15273  LocalContext context;
15274  i::ScopedVector<char> code(1024);
15275  i::OS::SNPrintF(code, "function fib(n) {"
15276  " if (n <= 2) return 1;"
15277  " return fib(n-1) + fib(n-2);"
15278  "}"
15279  "fib(%d)", limit);
15280  Local<Value> value = CompileRun(code.start());
15281  CHECK(value->IsNumber());
15282  return static_cast<int>(value->NumberValue());
15283 }
15284 
15286  public:
15287  IsolateThread(v8::Isolate* isolate, int fib_limit)
15288  : Thread("IsolateThread"),
15289  isolate_(isolate),
15290  fib_limit_(fib_limit),
15291  result_(0) { }
15292 
15293  void Run() {
15294  result_ = CalcFibonacci(isolate_, fib_limit_);
15295  }
15296 
15297  int result() { return result_; }
15298 
15299  private:
15300  v8::Isolate* isolate_;
15301  int fib_limit_;
15302  int result_;
15303 };
15304 
15305 TEST(MultipleIsolatesOnIndividualThreads) {
15306  v8::Isolate* isolate1 = v8::Isolate::New();
15307  v8::Isolate* isolate2 = v8::Isolate::New();
15308 
15309  IsolateThread thread1(isolate1, 21);
15310  IsolateThread thread2(isolate2, 12);
15311 
15312  // Compute some fibonacci numbers on 3 threads in 3 isolates.
15313  thread1.Start();
15314  thread2.Start();
15315 
15316  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15317  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
15318 
15319  thread1.Join();
15320  thread2.Join();
15321 
15322  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
15323  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
15324  CHECK_EQ(result1, 10946);
15325  CHECK_EQ(result2, 144);
15326  CHECK_EQ(result1, thread1.result());
15327  CHECK_EQ(result2, thread2.result());
15328 
15329  isolate1->Dispose();
15330  isolate2->Dispose();
15331 }
15332 
15333 TEST(IsolateDifferentContexts) {
15334  v8::Isolate* isolate = v8::Isolate::New();
15335  Persistent<v8::Context> context;
15336  {
15337  v8::Isolate::Scope isolate_scope(isolate);
15338  v8::HandleScope handle_scope;
15339  context = v8::Context::New();
15340  v8::Context::Scope context_scope(context);
15341  Local<Value> v = CompileRun("2");
15342  CHECK(v->IsNumber());
15343  CHECK_EQ(2, static_cast<int>(v->NumberValue()));
15344  }
15345  {
15346  v8::Isolate::Scope isolate_scope(isolate);
15347  v8::HandleScope handle_scope;
15348  context = v8::Context::New();
15349  v8::Context::Scope context_scope(context);
15350  Local<Value> v = CompileRun("22");
15351  CHECK(v->IsNumber());
15352  CHECK_EQ(22, static_cast<int>(v->NumberValue()));
15353  }
15354 }
15355 
15357  public:
15358  enum TestCase {
15365  };
15366 
15368  : Thread("InitDefaultIsolateThread"),
15369  testCase_(testCase),
15370  result_(false) { }
15371 
15372  void Run() {
15373  switch (testCase_) {
15374  case IgnoreOOM:
15376  break;
15377 
15378  case SetResourceConstraints: {
15379  static const int K = 1024;
15380  v8::ResourceConstraints constraints;
15381  constraints.set_max_young_space_size(256 * K);
15382  constraints.set_max_old_space_size(4 * K * K);
15383  v8::SetResourceConstraints(&constraints);
15384  break;
15385  }
15386 
15387  case SetFatalHandler:
15389  break;
15390 
15391  case SetCounterFunction:
15393  break;
15394 
15397  break;
15398 
15401  break;
15402  }
15403  result_ = true;
15404  }
15405 
15406  bool result() { return result_; }
15407 
15408  private:
15409  TestCase testCase_;
15410  bool result_;
15411 };
15412 
15413 
15414 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
15415  InitDefaultIsolateThread thread(testCase);
15416  thread.Start();
15417  thread.Join();
15418  CHECK_EQ(thread.result(), true);
15419 }
15420 
15421 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
15422  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
15423 }
15424 
15425 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
15427 }
15428 
15429 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
15430  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
15431 }
15432 
15433 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
15434  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
15435 }
15436 
15437 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
15439 }
15440 
15441 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
15443 }
15444 
15445 
15446 TEST(StringCheckMultipleContexts) {
15447  const char* code =
15448  "(function() { return \"a\".charAt(0); })()";
15449 
15450  {
15451  // Run the code twice in the first context to initialize the call IC.
15452  v8::HandleScope scope;
15453  LocalContext context1;
15454  ExpectString(code, "a");
15455  ExpectString(code, "a");
15456  }
15457 
15458  {
15459  // Change the String.prototype in the second context and check
15460  // that the right function gets called.
15461  v8::HandleScope scope;
15462  LocalContext context2;
15463  CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
15464  ExpectString(code, "not a");
15465  }
15466 }
15467 
15468 
15469 TEST(NumberCheckMultipleContexts) {
15470  const char* code =
15471  "(function() { return (42).toString(); })()";
15472 
15473  {
15474  // Run the code twice in the first context to initialize the call IC.
15475  v8::HandleScope scope;
15476  LocalContext context1;
15477  ExpectString(code, "42");
15478  ExpectString(code, "42");
15479  }
15480 
15481  {
15482  // Change the Number.prototype in the second context and check
15483  // that the right function gets called.
15484  v8::HandleScope scope;
15485  LocalContext context2;
15486  CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
15487  ExpectString(code, "not 42");
15488  }
15489 }
15490 
15491 
15492 TEST(BooleanCheckMultipleContexts) {
15493  const char* code =
15494  "(function() { return true.toString(); })()";
15495 
15496  {
15497  // Run the code twice in the first context to initialize the call IC.
15498  v8::HandleScope scope;
15499  LocalContext context1;
15500  ExpectString(code, "true");
15501  ExpectString(code, "true");
15502  }
15503 
15504  {
15505  // Change the Boolean.prototype in the second context and check
15506  // that the right function gets called.
15507  v8::HandleScope scope;
15508  LocalContext context2;
15509  CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
15510  ExpectString(code, "");
15511  }
15512 }
15513 
15514 
15515 TEST(DontDeleteCellLoadIC) {
15516  const char* function_code =
15517  "function readCell() { while (true) { return cell; } }";
15518 
15519  {
15520  // Run the code twice in the first context to initialize the load
15521  // IC for a don't delete cell.
15522  v8::HandleScope scope;
15523  LocalContext context1;
15524  CompileRun("var cell = \"first\";");
15525  ExpectBoolean("delete cell", false);
15526  CompileRun(function_code);
15527  ExpectString("readCell()", "first");
15528  ExpectString("readCell()", "first");
15529  }
15530 
15531  {
15532  // Use a deletable cell in the second context.
15533  v8::HandleScope scope;
15534  LocalContext context2;
15535  CompileRun("cell = \"second\";");
15536  CompileRun(function_code);
15537  ExpectString("readCell()", "second");
15538  ExpectBoolean("delete cell", true);
15539  ExpectString("(function() {"
15540  " try {"
15541  " return readCell();"
15542  " } catch(e) {"
15543  " return e.toString();"
15544  " }"
15545  "})()",
15546  "ReferenceError: cell is not defined");
15547  CompileRun("cell = \"new_second\";");
15548  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15549  ExpectString("readCell()", "new_second");
15550  ExpectString("readCell()", "new_second");
15551  }
15552 }
15553 
15554 
15555 TEST(DontDeleteCellLoadICForceDelete) {
15556  const char* function_code =
15557  "function readCell() { while (true) { return cell; } }";
15558 
15559  // Run the code twice to initialize the load IC for a don't delete
15560  // cell.
15561  v8::HandleScope scope;
15562  LocalContext context;
15563  CompileRun("var cell = \"value\";");
15564  ExpectBoolean("delete cell", false);
15565  CompileRun(function_code);
15566  ExpectString("readCell()", "value");
15567  ExpectString("readCell()", "value");
15568 
15569  // Delete the cell using the API and check the inlined code works
15570  // correctly.
15571  CHECK(context->Global()->ForceDelete(v8_str("cell")));
15572  ExpectString("(function() {"
15573  " try {"
15574  " return readCell();"
15575  " } catch(e) {"
15576  " return e.toString();"
15577  " }"
15578  "})()",
15579  "ReferenceError: cell is not defined");
15580 }
15581 
15582 
15583 TEST(DontDeleteCellLoadICAPI) {
15584  const char* function_code =
15585  "function readCell() { while (true) { return cell; } }";
15586 
15587  // Run the code twice to initialize the load IC for a don't delete
15588  // cell created using the API.
15589  v8::HandleScope scope;
15590  LocalContext context;
15591  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
15592  ExpectBoolean("delete cell", false);
15593  CompileRun(function_code);
15594  ExpectString("readCell()", "value");
15595  ExpectString("readCell()", "value");
15596 
15597  // Delete the cell using the API and check the inlined code works
15598  // correctly.
15599  CHECK(context->Global()->ForceDelete(v8_str("cell")));
15600  ExpectString("(function() {"
15601  " try {"
15602  " return readCell();"
15603  " } catch(e) {"
15604  " return e.toString();"
15605  " }"
15606  "})()",
15607  "ReferenceError: cell is not defined");
15608 }
15609 
15610 
15611 TEST(RegExp) {
15612  v8::HandleScope scope;
15613  LocalContext context;
15614 
15616  CHECK(re->IsRegExp());
15617  CHECK(re->GetSource()->Equals(v8_str("foo")));
15619 
15620  re = v8::RegExp::New(v8_str("bar"),
15621  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15623  CHECK(re->IsRegExp());
15624  CHECK(re->GetSource()->Equals(v8_str("bar")));
15626  static_cast<int>(re->GetFlags()));
15627 
15628  re = v8::RegExp::New(v8_str("baz"),
15629  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15631  CHECK(re->IsRegExp());
15632  CHECK(re->GetSource()->Equals(v8_str("baz")));
15634  static_cast<int>(re->GetFlags()));
15635 
15636  re = CompileRun("/quux/").As<v8::RegExp>();
15637  CHECK(re->IsRegExp());
15638  CHECK(re->GetSource()->Equals(v8_str("quux")));
15639  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
15640 
15641  re = CompileRun("/quux/gm").As<v8::RegExp>();
15642  CHECK(re->IsRegExp());
15643  CHECK(re->GetSource()->Equals(v8_str("quux")));
15645  static_cast<int>(re->GetFlags()));
15646 
15647  // Override the RegExp constructor and check the API constructor
15648  // still works.
15649  CompileRun("RegExp = function() {}");
15650 
15651  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
15652  CHECK(re->IsRegExp());
15653  CHECK(re->GetSource()->Equals(v8_str("foobar")));
15654  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
15655 
15656  re = v8::RegExp::New(v8_str("foobarbaz"),
15657  static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15659  CHECK(re->IsRegExp());
15660  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
15662  static_cast<int>(re->GetFlags()));
15663 
15664  context->Global()->Set(v8_str("re"), re);
15665  ExpectTrue("re.test('FoobarbaZ')");
15666 
15667  // RegExps are objects on which you can set properties.
15668  re->Set(v8_str("property"), v8::Integer::New(32));
15669  v8::Handle<v8::Value> value(CompileRun("re.property"));
15670  CHECK_EQ(32, value->Int32Value());
15671 
15672  v8::TryCatch try_catch;
15673  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15674  CHECK(re.IsEmpty());
15675  CHECK(try_catch.HasCaught());
15676  context->Global()->Set(v8_str("ex"), try_catch.Exception());
15677  ExpectTrue("ex instanceof SyntaxError");
15678 }
15679 
15680 
15681 THREADED_TEST(Equals) {
15682  v8::HandleScope handleScope;
15683  LocalContext localContext;
15684 
15685  v8::Handle<v8::Object> globalProxy = localContext->Global();
15686  v8::Handle<Value> global = globalProxy->GetPrototype();
15687 
15688  CHECK(global->StrictEquals(global));
15689  CHECK(!global->StrictEquals(globalProxy));
15690  CHECK(!globalProxy->StrictEquals(global));
15691  CHECK(globalProxy->StrictEquals(globalProxy));
15692 
15693  CHECK(global->Equals(global));
15694  CHECK(!global->Equals(globalProxy));
15695  CHECK(!globalProxy->Equals(global));
15696  CHECK(globalProxy->Equals(globalProxy));
15697 }
15698 
15699 
15700 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15701  const v8::AccessorInfo& info ) {
15702  return v8_str("42!");
15703 }
15704 
15705 
15706 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15708  result->Set(0, v8_str("universalAnswer"));
15709  return result;
15710 }
15711 
15712 
15713 TEST(NamedEnumeratorAndForIn) {
15714  v8::HandleScope handle_scope;
15715  LocalContext context;
15716  v8::Context::Scope context_scope(context.local());
15717 
15719  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15720  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15722  "var result = []; for (var k in o) result.push(k); result"));
15723  CHECK_EQ(1, result->Length());
15724  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15725 }
15726 
15727 
15728 TEST(DefinePropertyPostDetach) {
15729  v8::HandleScope scope;
15730  LocalContext context;
15731  v8::Handle<v8::Object> proxy = context->Global();
15732  v8::Handle<v8::Function> define_property =
15733  CompileRun("(function() {"
15734  " Object.defineProperty("
15735  " this,"
15736  " 1,"
15737  " { configurable: true, enumerable: true, value: 3 });"
15738  "})").As<Function>();
15739  context->DetachGlobal();
15740  define_property->Call(proxy, 0, NULL);
15741 }
15742 
15743 
15744 static void InstallContextId(v8::Handle<Context> context, int id) {
15745  Context::Scope scope(context);
15746  CompileRun("Object.prototype").As<Object>()->
15747  Set(v8_str("context_id"), v8::Integer::New(id));
15748 }
15749 
15750 
15751 static void CheckContextId(v8::Handle<Object> object, int expected) {
15752  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15753 }
15754 
15755 
15756 THREADED_TEST(CreationContext) {
15757  HandleScope handle_scope;
15758  Persistent<Context> context1 = Context::New();
15759  InstallContextId(context1, 1);
15760  Persistent<Context> context2 = Context::New();
15761  InstallContextId(context2, 2);
15762  Persistent<Context> context3 = Context::New();
15763  InstallContextId(context3, 3);
15764 
15765  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15766 
15767  Local<Object> object1;
15768  Local<Function> func1;
15769  {
15770  Context::Scope scope(context1);
15771  object1 = Object::New();
15772  func1 = tmpl->GetFunction();
15773  }
15774 
15775  Local<Object> object2;
15776  Local<Function> func2;
15777  {
15778  Context::Scope scope(context2);
15779  object2 = Object::New();
15780  func2 = tmpl->GetFunction();
15781  }
15782 
15783  Local<Object> instance1;
15784  Local<Object> instance2;
15785 
15786  {
15787  Context::Scope scope(context3);
15788  instance1 = func1->NewInstance();
15789  instance2 = func2->NewInstance();
15790  }
15791 
15792  CHECK(object1->CreationContext() == context1);
15793  CheckContextId(object1, 1);
15794  CHECK(func1->CreationContext() == context1);
15795  CheckContextId(func1, 1);
15796  CHECK(instance1->CreationContext() == context1);
15797  CheckContextId(instance1, 1);
15798  CHECK(object2->CreationContext() == context2);
15799  CheckContextId(object2, 2);
15800  CHECK(func2->CreationContext() == context2);
15801  CheckContextId(func2, 2);
15802  CHECK(instance2->CreationContext() == context2);
15803  CheckContextId(instance2, 2);
15804 
15805  {
15806  Context::Scope scope(context1);
15807  CHECK(object1->CreationContext() == context1);
15808  CheckContextId(object1, 1);
15809  CHECK(func1->CreationContext() == context1);
15810  CheckContextId(func1, 1);
15811  CHECK(instance1->CreationContext() == context1);
15812  CheckContextId(instance1, 1);
15813  CHECK(object2->CreationContext() == context2);
15814  CheckContextId(object2, 2);
15815  CHECK(func2->CreationContext() == context2);
15816  CheckContextId(func2, 2);
15817  CHECK(instance2->CreationContext() == context2);
15818  CheckContextId(instance2, 2);
15819  }
15820 
15821  {
15822  Context::Scope scope(context2);
15823  CHECK(object1->CreationContext() == context1);
15824  CheckContextId(object1, 1);
15825  CHECK(func1->CreationContext() == context1);
15826  CheckContextId(func1, 1);
15827  CHECK(instance1->CreationContext() == context1);
15828  CheckContextId(instance1, 1);
15829  CHECK(object2->CreationContext() == context2);
15830  CheckContextId(object2, 2);
15831  CHECK(func2->CreationContext() == context2);
15832  CheckContextId(func2, 2);
15833  CHECK(instance2->CreationContext() == context2);
15834  CheckContextId(instance2, 2);
15835  }
15836 
15837  context1.Dispose();
15838  context2.Dispose();
15839  context3.Dispose();
15840 }
15841 
15842 
15843 THREADED_TEST(CreationContextOfJsFunction) {
15844  HandleScope handle_scope;
15845  Persistent<Context> context = Context::New();
15846  InstallContextId(context, 1);
15847 
15848  Local<Object> function;
15849  {
15850  Context::Scope scope(context);
15851  function = CompileRun("function foo() {}; foo").As<Object>();
15852  }
15853 
15854  CHECK(function->CreationContext() == context);
15855  CheckContextId(function, 1);
15856 
15857  context.Dispose();
15858 }
15859 
15860 
15861 Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15862  const AccessorInfo& info) {
15863  if (index == 42) return v8_str("yes");
15864  return Handle<v8::Integer>();
15865 }
15866 
15867 
15868 Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15869  const AccessorInfo& info) {
15870  if (property->Equals(v8_str("foo"))) return v8_str("yes");
15871  return Handle<Value>();
15872 }
15873 
15874 
15876  uint32_t index, const AccessorInfo& info) {
15877  if (index == 42) return v8_num(1).As<v8::Integer>();
15878  return Handle<v8::Integer>();
15879 }
15880 
15881 
15883  Local<String> property, const AccessorInfo& info) {
15884  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15885  return Handle<v8::Integer>();
15886 }
15887 
15888 
15890  Local<String> property, const AccessorInfo& info) {
15891  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15892  return Handle<v8::Integer>();
15893 }
15894 
15895 
15896 Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15897  const AccessorInfo& info) {
15898  return v8_str("yes");
15899 }
15900 
15901 
15902 TEST(HasOwnProperty) {
15903  v8::HandleScope scope;
15904  LocalContext env;
15905  { // Check normal properties and defined getters.
15906  Handle<Value> value = CompileRun(
15907  "function Foo() {"
15908  " this.foo = 11;"
15909  " this.__defineGetter__('baz', function() { return 1; });"
15910  "};"
15911  "function Bar() { "
15912  " this.bar = 13;"
15913  " this.__defineGetter__('bla', function() { return 2; });"
15914  "};"
15915  "Bar.prototype = new Foo();"
15916  "new Bar();");
15917  CHECK(value->IsObject());
15918  Handle<Object> object = value->ToObject();
15919  CHECK(object->Has(v8_str("foo")));
15920  CHECK(!object->HasOwnProperty(v8_str("foo")));
15921  CHECK(object->HasOwnProperty(v8_str("bar")));
15922  CHECK(object->Has(v8_str("baz")));
15923  CHECK(!object->HasOwnProperty(v8_str("baz")));
15924  CHECK(object->HasOwnProperty(v8_str("bla")));
15925  }
15926  { // Check named getter interceptors.
15927  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15928  templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15929  Handle<Object> instance = templ->NewInstance();
15930  CHECK(!instance->HasOwnProperty(v8_str("42")));
15931  CHECK(instance->HasOwnProperty(v8_str("foo")));
15932  CHECK(!instance->HasOwnProperty(v8_str("bar")));
15933  }
15934  { // Check indexed getter interceptors.
15935  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15936  templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15937  Handle<Object> instance = templ->NewInstance();
15938  CHECK(instance->HasOwnProperty(v8_str("42")));
15939  CHECK(!instance->HasOwnProperty(v8_str("43")));
15940  CHECK(!instance->HasOwnProperty(v8_str("foo")));
15941  }
15942  { // Check named query interceptors.
15943  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15944  templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15945  Handle<Object> instance = templ->NewInstance();
15946  CHECK(instance->HasOwnProperty(v8_str("foo")));
15947  CHECK(!instance->HasOwnProperty(v8_str("bar")));
15948  }
15949  { // Check indexed query interceptors.
15950  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15951  templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15952  Handle<Object> instance = templ->NewInstance();
15953  CHECK(instance->HasOwnProperty(v8_str("42")));
15954  CHECK(!instance->HasOwnProperty(v8_str("41")));
15955  }
15956  { // Check callbacks.
15957  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15958  templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15959  Handle<Object> instance = templ->NewInstance();
15960  CHECK(instance->HasOwnProperty(v8_str("foo")));
15961  CHECK(!instance->HasOwnProperty(v8_str("bar")));
15962  }
15963  { // Check that query wins on disagreement.
15964  Handle<ObjectTemplate> templ = ObjectTemplate::New();
15965  templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15966  0,
15968  Handle<Object> instance = templ->NewInstance();
15969  CHECK(!instance->HasOwnProperty(v8_str("foo")));
15970  CHECK(instance->HasOwnProperty(v8_str("bar")));
15971  }
15972 }
15973 
15974 
15976  Handle<Value> result = CompileRun("eval('42')");
15977  CHECK_EQ(42, result->Int32Value());
15978  result = CompileRun("(function(e) { return e('42'); })(eval)");
15979  CHECK_EQ(42, result->Int32Value());
15980  result = CompileRun("var f = new Function('return 42'); f()");
15981  CHECK_EQ(42, result->Int32Value());
15982 }
15983 
15984 
15986  TryCatch try_catch;
15987 
15988  Handle<Value> result = CompileRun("eval('42')");
15989  CHECK(result.IsEmpty());
15990  CHECK(try_catch.HasCaught());
15991  try_catch.Reset();
15992 
15993  result = CompileRun("(function(e) { return e('42'); })(eval)");
15994  CHECK(result.IsEmpty());
15995  CHECK(try_catch.HasCaught());
15996  try_catch.Reset();
15997 
15998  result = CompileRun("var f = new Function('return 42'); f()");
15999  CHECK(result.IsEmpty());
16000  CHECK(try_catch.HasCaught());
16001 }
16002 
16003 
16004 bool CodeGenerationAllowed(Local<Context> context) {
16006  return true;
16007 }
16008 
16009 
16010 bool CodeGenerationDisallowed(Local<Context> context) {
16012  return false;
16013 }
16014 
16015 
16016 THREADED_TEST(AllowCodeGenFromStrings) {
16017  v8::HandleScope scope;
16018  LocalContext context;
16019 
16020  // eval and the Function constructor allowed by default.
16023 
16024  // Disallow eval and the Function constructor.
16025  context->AllowCodeGenerationFromStrings(false);
16028 
16029  // Allow again.
16030  context->AllowCodeGenerationFromStrings(true);
16032 
16033  // Disallow but setting a global callback that will allow the calls.
16034  context->AllowCodeGenerationFromStrings(false);
16035  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
16038 
16039  // Set a callback that disallows the code generation.
16040  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16043 }
16044 
16045 
16046 static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16047  return v8::Undefined();
16048 }
16049 
16050 
16051 THREADED_TEST(CallAPIFunctionOnNonObject) {
16052  v8::HandleScope scope;
16053  LocalContext context;
16054  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
16055  Handle<Function> function = templ->GetFunction();
16056  context->Global()->Set(v8_str("f"), function);
16057  TryCatch try_catch;
16058  CompileRun("f.call(2)");
16059 }
16060 
16061 
16062 // Regression test for issue 1470.
16063 THREADED_TEST(ReadOnlyIndexedProperties) {
16064  v8::HandleScope scope;
16065  Local<ObjectTemplate> templ = ObjectTemplate::New();
16066 
16067  LocalContext context;
16068  Local<v8::Object> obj = templ->NewInstance();
16069  context->Global()->Set(v8_str("obj"), obj);
16070  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16071  obj->Set(v8_str("1"), v8_str("foobar"));
16072  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
16073  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
16074  obj->Set(v8_num(2), v8_str("foobar"));
16075  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
16076 
16077  // Test non-smi case.
16078  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16079  obj->Set(v8_str("2000000000"), v8_str("foobar"));
16080  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16081 }
16082 
16083 
16084 THREADED_TEST(Regress1516) {
16085  v8::HandleScope scope;
16086 
16087  LocalContext context;
16088  { v8::HandleScope temp_scope;
16089  CompileRun("({'a': 0})");
16090  }
16091 
16092  int elements;
16093  { i::MapCache* map_cache =
16094  i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16095  elements = map_cache->NumberOfElements();
16096  CHECK_LE(1, elements);
16097  }
16098 
16099  i::Isolate::Current()->heap()->CollectAllGarbage(true);
16100  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16101  if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16102  i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16103  CHECK_GT(elements, map_cache->NumberOfElements());
16104  }
16105  }
16106 }
16107 
16108 
16109 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16110  Local<Value> name,
16111  v8::AccessType type,
16112  Local<Value> data) {
16113  // Only block read access to __proto__.
16114  if (type == v8::ACCESS_GET &&
16115  name->IsString() &&
16116  name->ToString()->Length() == 9 &&
16117  name->ToString()->Utf8Length() == 9) {
16118  char buffer[10];
16119  CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16120  return strncmp(buffer, "__proto__", 9) != 0;
16121  }
16122 
16123  return true;
16124 }
16125 
16126 
16127 THREADED_TEST(Regress93759) {
16128  HandleScope scope;
16129 
16130  // Template for object with security check.
16131  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16132  // We don't do indexing, so any callback can be used for that.
16133  no_proto_template->SetAccessCheckCallbacks(
16134  BlockProtoNamedSecurityTestCallback,
16135  IndexedSecurityTestCallback);
16136 
16137  // Templates for objects with hidden prototypes and possibly security check.
16138  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16139  hidden_proto_template->SetHiddenPrototype(true);
16140 
16141  Local<FunctionTemplate> protected_hidden_proto_template =
16143  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16144  BlockProtoNamedSecurityTestCallback,
16145  IndexedSecurityTestCallback);
16146  protected_hidden_proto_template->SetHiddenPrototype(true);
16147 
16148  // Context for "foreign" objects used in test.
16149  Persistent<Context> context = v8::Context::New();
16150  context->Enter();
16151 
16152  // Plain object, no security check.
16153  Local<Object> simple_object = Object::New();
16154 
16155  // Object with explicit security check.
16156  Local<Object> protected_object =
16157  no_proto_template->NewInstance();
16158 
16159  // JSGlobalProxy object, always have security check.
16160  Local<Object> proxy_object =
16161  context->Global();
16162 
16163  // Global object, the prototype of proxy_object. No security checks.
16164  Local<Object> global_object =
16165  proxy_object->GetPrototype()->ToObject();
16166 
16167  // Hidden prototype without security check.
16168  Local<Object> hidden_prototype =
16169  hidden_proto_template->GetFunction()->NewInstance();
16170  Local<Object> object_with_hidden =
16171  Object::New();
16172  object_with_hidden->SetPrototype(hidden_prototype);
16173 
16174  // Hidden prototype with security check on the hidden prototype.
16175  Local<Object> protected_hidden_prototype =
16176  protected_hidden_proto_template->GetFunction()->NewInstance();
16177  Local<Object> object_with_protected_hidden =
16178  Object::New();
16179  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16180 
16181  context->Exit();
16182 
16183  // Template for object for second context. Values to test are put on it as
16184  // properties.
16185  Local<ObjectTemplate> global_template = ObjectTemplate::New();
16186  global_template->Set(v8_str("simple"), simple_object);
16187  global_template->Set(v8_str("protected"), protected_object);
16188  global_template->Set(v8_str("global"), global_object);
16189  global_template->Set(v8_str("proxy"), proxy_object);
16190  global_template->Set(v8_str("hidden"), object_with_hidden);
16191  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
16192 
16193  LocalContext context2(NULL, global_template);
16194 
16195  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16196  CHECK(result1->Equals(simple_object->GetPrototype()));
16197 
16198  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16199  CHECK(result2->Equals(Undefined()));
16200 
16201  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16202  CHECK(result3->Equals(global_object->GetPrototype()));
16203 
16204  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16205  CHECK(result4->Equals(Undefined()));
16206 
16207  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16208  CHECK(result5->Equals(
16209  object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16210 
16211  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16212  CHECK(result6->Equals(Undefined()));
16213 
16214  context.Dispose();
16215 }
16216 
16217 
16218 THREADED_TEST(Regress125988) {
16219  v8::HandleScope scope;
16220  Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16222  LocalContext env;
16223  env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
16224  CompileRun("var a = new Object();"
16225  "var b = new Intercept();"
16226  "var c = new Object();"
16227  "c.__proto__ = b;"
16228  "b.__proto__ = a;"
16229  "a.x = 23;"
16230  "for (var i = 0; i < 3; i++) c.x;");
16231  ExpectBoolean("c.hasOwnProperty('x')", false);
16232  ExpectInt32("c.x", 23);
16233  CompileRun("a.y = 42;"
16234  "for (var i = 0; i < 3; i++) c.x;");
16235  ExpectBoolean("c.hasOwnProperty('x')", false);
16236  ExpectInt32("c.x", 23);
16237  ExpectBoolean("c.hasOwnProperty('y')", false);
16238  ExpectInt32("c.y", 42);
16239 }
16240 
16241 
16242 static void TestReceiver(Local<Value> expected_result,
16243  Local<Value> expected_receiver,
16244  const char* code) {
16245  Local<Value> result = CompileRun(code);
16246  CHECK(result->IsObject());
16247  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
16248  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
16249 }
16250 
16251 
16252 THREADED_TEST(ForeignFunctionReceiver) {
16253  HandleScope scope;
16254 
16255  // Create two contexts with different "id" properties ('i' and 'o').
16256  // Call a function both from its own context and from a the foreign
16257  // context, and see what "this" is bound to (returning both "this"
16258  // and "this.id" for comparison).
16259 
16260  Persistent<Context> foreign_context = v8::Context::New();
16261  foreign_context->Enter();
16262  Local<Value> foreign_function =
16263  CompileRun("function func() { return { 0: this.id, "
16264  " 1: this, "
16265  " toString: function() { "
16266  " return this[0];"
16267  " }"
16268  " };"
16269  "}"
16270  "var id = 'i';"
16271  "func;");
16272  CHECK(foreign_function->IsFunction());
16273  foreign_context->Exit();
16274 
16275  LocalContext context;
16276 
16277  Local<String> password = v8_str("Password");
16278  // Don't get hit by security checks when accessing foreign_context's
16279  // global receiver (aka. global proxy).
16280  context->SetSecurityToken(password);
16281  foreign_context->SetSecurityToken(password);
16282 
16283  Local<String> i = v8_str("i");
16284  Local<String> o = v8_str("o");
16285  Local<String> id = v8_str("id");
16286 
16287  CompileRun("function ownfunc() { return { 0: this.id, "
16288  " 1: this, "
16289  " toString: function() { "
16290  " return this[0];"
16291  " }"
16292  " };"
16293  "}"
16294  "var id = 'o';"
16295  "ownfunc");
16296  context->Global()->Set(v8_str("func"), foreign_function);
16297 
16298  // Sanity check the contexts.
16299  CHECK(i->Equals(foreign_context->Global()->Get(id)));
16300  CHECK(o->Equals(context->Global()->Get(id)));
16301 
16302  // Checking local function's receiver.
16303  // Calling function using its call/apply methods.
16304  TestReceiver(o, context->Global(), "ownfunc.call()");
16305  TestReceiver(o, context->Global(), "ownfunc.apply()");
16306  // Making calls through built-in functions.
16307  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
16308  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
16309  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
16310  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
16311  // Calling with environment record as base.
16312  TestReceiver(o, context->Global(), "ownfunc()");
16313  // Calling with no base.
16314  TestReceiver(o, context->Global(), "(1,ownfunc)()");
16315 
16316  // Checking foreign function return value.
16317  // Calling function using its call/apply methods.
16318  TestReceiver(i, foreign_context->Global(), "func.call()");
16319  TestReceiver(i, foreign_context->Global(), "func.apply()");
16320  // Calling function using another context's call/apply methods.
16321  TestReceiver(i, foreign_context->Global(),
16322  "Function.prototype.call.call(func)");
16323  TestReceiver(i, foreign_context->Global(),
16324  "Function.prototype.call.apply(func)");
16325  TestReceiver(i, foreign_context->Global(),
16326  "Function.prototype.apply.call(func)");
16327  TestReceiver(i, foreign_context->Global(),
16328  "Function.prototype.apply.apply(func)");
16329  // Making calls through built-in functions.
16330  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
16331  // ToString(func()) is func()[0], i.e., the returned this.id.
16332  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
16333  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
16334  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
16335 
16336  // TODO(1547): Make the following also return "i".
16337  // Calling with environment record as base.
16338  TestReceiver(o, context->Global(), "func()");
16339  // Calling with no base.
16340  TestReceiver(o, context->Global(), "(1,func)()");
16341 
16342  foreign_context.Dispose();
16343 }
16344 
16345 
16346 uint8_t callback_fired = 0;
16347 
16348 
16350  i::OS::Print("Firing callback 1.\n");
16351  callback_fired ^= 1; // Toggle first bit.
16352 }
16353 
16354 
16356  i::OS::Print("Firing callback 2.\n");
16357  callback_fired ^= 2; // Toggle second bit.
16358 }
16359 
16360 
16361 Handle<Value> RecursiveCall(const Arguments& args) {
16362  int32_t level = args[0]->Int32Value();
16363  if (level < 3) {
16364  level++;
16365  i::OS::Print("Entering recursion level %d.\n", level);
16366  char script[64];
16367  i::Vector<char> script_vector(script, sizeof(script));
16368  i::OS::SNPrintF(script_vector, "recursion(%d)", level);
16369  CompileRun(script_vector.start());
16370  i::OS::Print("Leaving recursion level %d.\n", level);
16371  CHECK_EQ(0, callback_fired);
16372  } else {
16373  i::OS::Print("Recursion ends.\n");
16374  CHECK_EQ(0, callback_fired);
16375  }
16376  return Undefined();
16377 }
16378 
16379 
16381  v8::HandleScope scope;
16382  LocalContext env;
16383  v8::Handle<v8::FunctionTemplate> recursive_runtime =
16385  env->Global()->Set(v8_str("recursion"),
16386  recursive_runtime->GetFunction());
16387  // Adding the same callback a second time has no effect.
16391  i::OS::Print("--- Script (1) ---\n");
16392  Local<Script> script =
16393  v8::Script::Compile(v8::String::New("recursion(0)"));
16394  script->Run();
16395  CHECK_EQ(3, callback_fired);
16396 
16397  i::OS::Print("\n--- Script (2) ---\n");
16398  callback_fired = 0;
16400  script->Run();
16401  CHECK_EQ(2, callback_fired);
16402 
16403  i::OS::Print("\n--- Function ---\n");
16404  callback_fired = 0;
16405  Local<Function> recursive_function =
16406  Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
16407  v8::Handle<Value> args[] = { v8_num(0) };
16408  recursive_function->Call(env->Global(), 1, args);
16409  CHECK_EQ(2, callback_fired);
16410 }
16411 
16412 
16414  v8::HandleScope scope;
16415  CompileRun("1+1;");
16416 }
16417 
16418 
16420  v8::HandleScope scope;
16421  CompileRun("throw 'second exception';");
16422 }
16423 
16424 
16425 TEST(CallCompletedCallbackOneException) {
16426  v8::HandleScope scope;
16427  LocalContext env;
16429  CompileRun("throw 'exception';");
16430 }
16431 
16432 
16433 TEST(CallCompletedCallbackTwoExceptions) {
16434  v8::HandleScope scope;
16435  LocalContext env;
16437  CompileRun("throw 'first exception';");
16438 }
16439 
16440 
16441 static int probes_counter = 0;
16442 static int misses_counter = 0;
16443 static int updates_counter = 0;
16444 
16445 
16446 static int* LookupCounter(const char* name) {
16447  if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
16448  return &probes_counter;
16449  } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
16450  return &misses_counter;
16451  } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
16452  return &updates_counter;
16453  }
16454  return NULL;
16455 }
16456 
16457 
16458 static const char* kMegamorphicTestProgram =
16459  "function ClassA() { };"
16460  "function ClassB() { };"
16461  "ClassA.prototype.foo = function() { };"
16462  "ClassB.prototype.foo = function() { };"
16463  "function fooify(obj) { obj.foo(); };"
16464  "var a = new ClassA();"
16465  "var b = new ClassB();"
16466  "for (var i = 0; i < 10000; i++) {"
16467  " fooify(a);"
16468  " fooify(b);"
16469  "}";
16470 
16471 
16472 static void StubCacheHelper(bool primary) {
16473  V8::SetCounterFunction(LookupCounter);
16474  USE(kMegamorphicTestProgram);
16475 #ifdef DEBUG
16476  i::FLAG_native_code_counters = true;
16477  if (primary) {
16478  i::FLAG_test_primary_stub_cache = true;
16479  } else {
16480  i::FLAG_test_secondary_stub_cache = true;
16481  }
16482  i::FLAG_crankshaft = false;
16483  v8::HandleScope scope;
16484  LocalContext env;
16485  int initial_probes = probes_counter;
16486  int initial_misses = misses_counter;
16487  int initial_updates = updates_counter;
16488  CompileRun(kMegamorphicTestProgram);
16489  int probes = probes_counter - initial_probes;
16490  int misses = misses_counter - initial_misses;
16491  int updates = updates_counter - initial_updates;
16492  CHECK_LT(updates, 10);
16493  CHECK_LT(misses, 10);
16494  CHECK_GE(probes, 10000);
16495 #endif
16496 }
16497 
16498 
16499 TEST(SecondaryStubCache) {
16500  StubCacheHelper(true);
16501 }
16502 
16503 
16504 TEST(PrimaryStubCache) {
16505  StubCacheHelper(false);
16506 }
16507 
16508 
16509 static int fatal_error_callback_counter = 0;
16510 static void CountingErrorCallback(const char* location, const char* message) {
16511  printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
16512  fatal_error_callback_counter++;
16513 }
16514 
16515 
16516 TEST(StaticGetters) {
16517  v8::HandleScope scope;
16518  LocalContext context;
16519  v8::Isolate* isolate = v8::Isolate::GetCurrent();
16520  i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
16521  CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
16522  CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
16523  i::Handle<i::Object> null_value = FACTORY->null_value();
16524  CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
16525  CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
16526  i::Handle<i::Object> true_value = FACTORY->true_value();
16527  CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
16528  CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
16529  i::Handle<i::Object> false_value = FACTORY->false_value();
16530  CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
16531  CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
16532 
16533  // Test after-death behavior.
16535  CHECK_EQ(0, fatal_error_callback_counter);
16536  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
16537  v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
16538  i::Isolate::Current()->TearDown();
16540  CHECK_EQ(1, fatal_error_callback_counter);
16541  CHECK(v8::Undefined().IsEmpty());
16542  CHECK_EQ(2, fatal_error_callback_counter);
16543  CHECK(v8::Undefined(isolate).IsEmpty());
16544  CHECK_EQ(3, fatal_error_callback_counter);
16545  CHECK(v8::Null().IsEmpty());
16546  CHECK_EQ(4, fatal_error_callback_counter);
16547  CHECK(v8::Null(isolate).IsEmpty());
16548  CHECK_EQ(5, fatal_error_callback_counter);
16549  CHECK(v8::True().IsEmpty());
16550  CHECK_EQ(6, fatal_error_callback_counter);
16551  CHECK(v8::True(isolate).IsEmpty());
16552  CHECK_EQ(7, fatal_error_callback_counter);
16553  CHECK(v8::False().IsEmpty());
16554  CHECK_EQ(8, fatal_error_callback_counter);
16555  CHECK(v8::False(isolate).IsEmpty());
16556  CHECK_EQ(9, fatal_error_callback_counter);
16557 }
16558 
16559 
16560 TEST(IsolateEmbedderData) {
16561  v8::Isolate* isolate = v8::Isolate::GetCurrent();
16562  CHECK_EQ(NULL, isolate->GetData());
16563  CHECK_EQ(NULL, ISOLATE->GetData());
16564  static void* data1 = reinterpret_cast<void*>(0xacce55ed);
16565  isolate->SetData(data1);
16566  CHECK_EQ(data1, isolate->GetData());
16567  CHECK_EQ(data1, ISOLATE->GetData());
16568  static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
16569  ISOLATE->SetData(data2);
16570  CHECK_EQ(data2, isolate->GetData());
16571  CHECK_EQ(data2, ISOLATE->GetData());
16572  ISOLATE->TearDown();
16573  CHECK_EQ(data2, isolate->GetData());
16574  CHECK_EQ(data2, ISOLATE->GetData());
16575 }
16576 
16577 
16578 TEST(StringEmpty) {
16579  v8::HandleScope scope;
16580  LocalContext context;
16581  v8::Isolate* isolate = v8::Isolate::GetCurrent();
16582  i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
16583  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
16584  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
16585 
16586  // Test after-death behavior.
16588  CHECK_EQ(0, fatal_error_callback_counter);
16589  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
16590  v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
16591  i::Isolate::Current()->TearDown();
16593  CHECK_EQ(1, fatal_error_callback_counter);
16594  CHECK(v8::String::Empty().IsEmpty());
16595  CHECK_EQ(2, fatal_error_callback_counter);
16596  CHECK(v8::String::Empty(isolate).IsEmpty());
16597  CHECK_EQ(3, fatal_error_callback_counter);
16598 }
16599 
16600 
16601 static int instance_checked_getter_count = 0;
16602 static Handle<Value> InstanceCheckedGetter(Local<String> name,
16603  const AccessorInfo& info) {
16604  CHECK_EQ(name, v8_str("foo"));
16605  instance_checked_getter_count++;
16606  return v8_num(11);
16607 }
16608 
16609 
16610 static int instance_checked_setter_count = 0;
16611 static void InstanceCheckedSetter(Local<String> name,
16612  Local<Value> value,
16613  const AccessorInfo& info) {
16614  CHECK_EQ(name, v8_str("foo"));
16615  CHECK_EQ(value, v8_num(23));
16616  instance_checked_setter_count++;
16617 }
16618 
16619 
16620 static void CheckInstanceCheckedResult(int getters,
16621  int setters,
16622  bool expects_callbacks,
16623  TryCatch* try_catch) {
16624  if (expects_callbacks) {
16625  CHECK(!try_catch->HasCaught());
16626  CHECK_EQ(getters, instance_checked_getter_count);
16627  CHECK_EQ(setters, instance_checked_setter_count);
16628  } else {
16629  CHECK(try_catch->HasCaught());
16630  CHECK_EQ(0, instance_checked_getter_count);
16631  CHECK_EQ(0, instance_checked_setter_count);
16632  }
16633  try_catch->Reset();
16634 }
16635 
16636 
16637 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
16638  instance_checked_getter_count = 0;
16639  instance_checked_setter_count = 0;
16640  TryCatch try_catch;
16641 
16642  // Test path through generic runtime code.
16643  CompileRun("obj.foo");
16644  CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
16645  CompileRun("obj.foo = 23");
16646  CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
16647 
16648  // Test path through generated LoadIC and StoredIC.
16649  CompileRun("function test_get(o) { o.foo; }"
16650  "test_get(obj);");
16651  CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
16652  CompileRun("test_get(obj);");
16653  CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
16654  CompileRun("test_get(obj);");
16655  CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
16656  CompileRun("function test_set(o) { o.foo = 23; }"
16657  "test_set(obj);");
16658  CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
16659  CompileRun("test_set(obj);");
16660  CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
16661  CompileRun("test_set(obj);");
16662  CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
16663 
16664  // Test path through optimized code.
16665  CompileRun("%OptimizeFunctionOnNextCall(test_get);"
16666  "test_get(obj);");
16667  CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
16668  CompileRun("%OptimizeFunctionOnNextCall(test_set);"
16669  "test_set(obj);");
16670  CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
16671 
16672  // Cleanup so that closures start out fresh in next check.
16673  CompileRun("%DeoptimizeFunction(test_get);"
16674  "%ClearFunctionTypeFeedback(test_get);"
16675  "%DeoptimizeFunction(test_set);"
16676  "%ClearFunctionTypeFeedback(test_set);");
16677 }
16678 
16679 
16680 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
16681  v8::internal::FLAG_allow_natives_syntax = true;
16682  v8::HandleScope scope;
16683  LocalContext context;
16684 
16685  Local<FunctionTemplate> templ = FunctionTemplate::New();
16686  Local<ObjectTemplate> inst = templ->InstanceTemplate();
16687  inst->SetAccessor(v8_str("foo"),
16688  InstanceCheckedGetter, InstanceCheckedSetter,
16689  Handle<Value>(),
16690  v8::DEFAULT,
16691  v8::None,
16693  context->Global()->Set(v8_str("f"), templ->GetFunction());
16694 
16695  printf("Testing positive ...\n");
16696  CompileRun("var obj = new f();");
16697  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16698  CheckInstanceCheckedAccessors(true);
16699 
16700  printf("Testing negative ...\n");
16701  CompileRun("var obj = {};"
16702  "obj.__proto__ = new f();");
16703  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16704  CheckInstanceCheckedAccessors(false);
16705 }
16706 
16707 
16708 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
16709  v8::internal::FLAG_allow_natives_syntax = true;
16710  v8::HandleScope scope;
16711  LocalContext context;
16712 
16713  Local<FunctionTemplate> templ = FunctionTemplate::New();
16714  Local<ObjectTemplate> inst = templ->InstanceTemplate();
16716  inst->SetAccessor(v8_str("foo"),
16717  InstanceCheckedGetter, InstanceCheckedSetter,
16718  Handle<Value>(),
16719  v8::DEFAULT,
16720  v8::None,
16722  context->Global()->Set(v8_str("f"), templ->GetFunction());
16723 
16724  printf("Testing positive ...\n");
16725  CompileRun("var obj = new f();");
16726  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16727  CheckInstanceCheckedAccessors(true);
16728 
16729  printf("Testing negative ...\n");
16730  CompileRun("var obj = {};"
16731  "obj.__proto__ = new f();");
16732  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16733  CheckInstanceCheckedAccessors(false);
16734 }
16735 
16736 
16737 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
16738  v8::internal::FLAG_allow_natives_syntax = true;
16739  v8::HandleScope scope;
16740  LocalContext context;
16741 
16742  Local<FunctionTemplate> templ = FunctionTemplate::New();
16743  Local<ObjectTemplate> proto = templ->PrototypeTemplate();
16744  proto->SetAccessor(v8_str("foo"),
16745  InstanceCheckedGetter, InstanceCheckedSetter,
16746  Handle<Value>(),
16747  v8::DEFAULT,
16748  v8::None,
16750  context->Global()->Set(v8_str("f"), templ->GetFunction());
16751 
16752  printf("Testing positive ...\n");
16753  CompileRun("var obj = new f();");
16754  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16755  CheckInstanceCheckedAccessors(true);
16756 
16757  printf("Testing negative ...\n");
16758  CompileRun("var obj = {};"
16759  "obj.__proto__ = new f();");
16760  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16761  CheckInstanceCheckedAccessors(false);
16762 
16763  printf("Testing positive with modified prototype chain ...\n");
16764  CompileRun("var obj = new f();"
16765  "var pro = {};"
16766  "pro.__proto__ = obj.__proto__;"
16767  "obj.__proto__ = pro;");
16768  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
16769  CheckInstanceCheckedAccessors(true);
16770 }
16771 
16772 
16773 TEST(TryFinallyMessage) {
16774  v8::HandleScope scope;
16775  LocalContext context;
16776  {
16777  // Test that the original error message is not lost if there is a
16778  // recursive call into Javascript is done in the finally block, e.g. to
16779  // initialize an IC. (crbug.com/129171)
16780  TryCatch try_catch;
16781  const char* trigger_ic =
16782  "try { \n"
16783  " throw new Error('test'); \n"
16784  "} finally { \n"
16785  " var x = 0; \n"
16786  " x++; \n" // Trigger an IC initialization here.
16787  "} \n";
16788  CompileRun(trigger_ic);
16789  CHECK(try_catch.HasCaught());
16790  Local<Message> message = try_catch.Message();
16791  CHECK(!message.IsEmpty());
16792  CHECK_EQ(2, message->GetLineNumber());
16793  }
16794 
16795  {
16796  // Test that the original exception message is indeed overwritten if
16797  // a new error is thrown in the finally block.
16798  TryCatch try_catch;
16799  const char* throw_again =
16800  "try { \n"
16801  " throw new Error('test'); \n"
16802  "} finally { \n"
16803  " var x = 0; \n"
16804  " x++; \n"
16805  " throw new Error('again'); \n" // This is the new uncaught error.
16806  "} \n";
16807  CompileRun(throw_again);
16808  CHECK(try_catch.HasCaught());
16809  Local<Message> message = try_catch.Message();
16810  CHECK(!message.IsEmpty());
16811  CHECK_EQ(6, message->GetLineNumber());
16812  }
16813 }
static void RunAllTests()
Definition: test-api.cc:10485
Handle< S > As()
Definition: v8.h:252
Handle< v8::Array > NonStrictArgsIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:3948
v8::Handle< Value > keyed_call_ic_function
Definition: test-api.cc:9799
static Isolate * GetCurrent()
Definition: api.cc:5380
void MakeWeak(void *parameters, WeakReferenceCallback callback)
Definition: v8.h:4075
void OOMCallback(const char *location, const char *message)
Definition: test-api.cc:4996
const SwVfpRegister s2
Local< S > As()
Definition: v8.h:290
Handle< Array >(* NamedPropertyEnumerator)(const AccessorInfo &info)
Definition: v8.h:2056
Handle< Value > GetScriptData() const
Definition: api.cc:1802
V8EXPORT int Length() const
Definition: api.cc:3718
v8::Persistent< Script > script_
Definition: test-api.cc:5060
v8::Persistent< v8::Object > some_object
Definition: test-api.cc:10750
V8EXPORT double NumberValue() const
Definition: api.cc:2547
static Object * Cast(Value *obj)
Definition: v8.h:4386
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1560
int GetLineNumber() const
Definition: api.cc:2013
void FlattenString(Handle< String > string)
Definition: handles.cc:211
bool IsEval() const
Definition: api.cc:2093
static void AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type_filter=kGCTypeAll)
Definition: api.cc:5273
V8EXPORT int WriteUtf8(char *buffer, int length=-1, int *nchars_ref=NULL, int options=NO_OPTIONS) const
Definition: api.cc:3829
v8::Persistent< Context > calling_context2
Definition: test-api.cc:12424
V8EXPORT bool HasRealIndexedProperty(uint32_t index)
Definition: api.cc:3125
TestAsciiResourceWithDisposeControl(const char *data, bool dispose)
Definition: test-api.cc:648
void set_max_young_space_size(int value)
Definition: v8.h:2608
virtual ~VisitorImpl()
Definition: test-api.cc:14193
v8::Handle< v8::Array > CheckThisIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:1696
#define CHECK_EQ(expected, value)
Definition: checks.h:219
V8EXPORT bool IsTrue() const
Definition: api.cc:2135
Local< Array > AsArray()
Definition: api.cc:1990
V8EXPORT uint8_t * GetIndexedPropertiesPixelData()
Definition: api.cc:3412
v8::Handle< Value > call_ic_function
Definition: test-api.cc:9040
void StoringErrorCallback(const char *location, const char *message)
Definition: test-api.cc:4963
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:943
v8::Handle< Value > AnalyzeStackOfEvalWithSourceURL(const v8::Arguments &args)
Definition: test-api.cc:13962
V8EXPORT bool DeleteHiddenValue(Handle< String > key)
Definition: api.cc:3314
void Dispose()
Definition: api.cc:5392
Handle< Boolean > V8EXPORT True()
Definition: api.cc:566
V8EXPORT Local< String > GetSource() const
Definition: api.cc:4997
void(* CallCompletedCallback)()
Definition: v8.h:2694
Handle< Value >(* NamedPropertySetter)(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:2031
static void TearDown()
Definition: test-api.cc:10517
void Dispose()
Definition: v8.h:4065
Handle< Value > HasOwnPropertyAccessorGetter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:15896
void Exit()
Definition: api.cc:5409
Thread(const Options &options)
v8::Handle< Value > ThrowFromC(const v8::Arguments &args)
Definition: test-api.cc:2933
void SetSecurityToken(Handle< Value > token)
Definition: api.cc:4382
Local< Value > Exception() const
Definition: api.cc:1712
static MapCache * cast(Object *obj)
void * GetData()
Definition: v8.h:4480
static bool IsInitialized(v8::Isolate *isolate)
Definition: v8.h:3985
void CallCompletedCallbackNoException()
Definition: test-api.cc:16413
void HandleCreatingCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10807
v8::Persistent< Context > calling_context1
Definition: test-api.cc:12423
V8EXPORT bool StrictEquals(Handle< Value > that) const
Definition: api.cc:2703
Handle< Value > InterceptorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1340
Local< Object > Holder() const
Definition: v8.h:4122
static void SetAddHistogramSampleFunction(AddHistogramSampleCallback)
Definition: api.cc:5189
bool HasOutOfMemoryException()
Definition: api.cc:4418
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2845
static Smi * FromInt(int value)
Definition: objects-inl.h:973
V8EXPORT bool IsNativeError() const
Definition: api.cc:2271
void V8EXPORT RegisterExtension(Extension *extension)
Definition: api.cc:525
Local< Object > NewInstance()
Definition: api.cc:4536
void PrologueCallback(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:14715
#define CHECK_GT(a, b)
Definition: checks.h:227
bool HasCaught() const
Definition: api.cc:1695
V8EXPORT Local< Array > GetOwnPropertyNames()
Definition: api.cc:2959
v8::Persistent< v8::Object > to_be_disposed
Definition: test-api.cc:10780
int echo_named_call_count
Definition: test-api.cc:1290
void SimpleAccessorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1309
v8::Handle< v8::Integer > CheckThisIndexedPropertyQuery(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:1661
value format" "after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false, "print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false, "print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false, "report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true, "flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true, "use incremental marking") DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps") DEFINE_bool(trace_incremental_marking, false, "trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true, "Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false, "Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true, "use inline caching") DEFINE_bool(native_code_counters, false, "generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false, "Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true, "Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false, "Never perform compaction on full GC-testing only") DEFINE_bool(compact_code_space, true, "Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true, "Flush inline caches prior to mark compact collection and" "flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0, "Default seed for initializing random generator" "(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true, "allows verbose printing") DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(trace_sim, false, "Trace simulator execution") DEFINE_bool(check_icache, false, "Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8, "Stack alingment in bytes in simulator(4 or 8, 8 is default)") DEFINE_bool(trace_exception, false, "print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false, "preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true, "randomize hashes to avoid predictable hash collisions" "(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0, "Fixed seed to use to hash property keys(0 means random)" "(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false, "activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true, "generate optimized regexp code") DEFINE_bool(testing_bool_flag, true, "testing_bool_flag") DEFINE_int(testing_int_flag, 13, "testing_int_flag") DEFINE_float(testing_float_flag, 2.5, "float-flag") DEFINE_string(testing_string_flag, "Hello, world!", "string-flag") DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness") DEFINE_string(testing_serialization_file, "/tmp/serdes", "file in which to serialize heap") DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") DEFINE_string(map_counters, "", "Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT, "Pass all remaining arguments to the script.Alias for\"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#43"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2#define FLAG_MODE_DEFINE_DEFAULTS#1"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flag-definitions.h"1#define FLAG_FULL(ftype, ctype, nam, def, cmt)#define FLAG_READONLY(ftype, ctype, nam, def, cmt)#define DEFINE_implication(whenflag, thenflag)#define DEFINE_bool(nam, def, cmt)#define DEFINE_int(nam, def, cmt)#define DEFINE_float(nam, def, cmt)#define DEFINE_string(nam, def, cmt)#define DEFINE_args(nam, def, cmt)#define FLAG DEFINE_bool(use_strict, false,"enforce strict mode") DEFINE_bool(es5_readonly, false,"activate correct semantics for inheriting readonliness") DEFINE_bool(es52_globals, false,"activate new semantics for global var declarations") DEFINE_bool(harmony_typeof, false,"enable harmony semantics for typeof") DEFINE_bool(harmony_scoping, false,"enable harmony block scoping") DEFINE_bool(harmony_modules, false,"enable harmony modules (implies block scoping)") DEFINE_bool(harmony_proxies, false,"enable harmony proxies") DEFINE_bool(harmony_collections, false,"enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony, false,"enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_bool(packed_arrays, false,"optimizes arrays that have no holes") DEFINE_bool(smi_only_arrays, true,"tracks arrays with only smi values") DEFINE_bool(clever_optimizations, true,"Optimize object size, Array shift, DOM strings and string +") DEFINE_bool(unbox_double_arrays, true,"automatically unbox arrays of doubles") DEFINE_bool(string_slices, true,"use string slices") DEFINE_bool(crankshaft, true,"use crankshaft") DEFINE_string(hydrogen_filter,"","optimization filter") DEFINE_bool(use_range, true,"use hydrogen range analysis") DEFINE_bool(eliminate_dead_phis, true,"eliminate dead phis") DEFINE_bool(use_gvn, true,"use hydrogen global value numbering") DEFINE_bool(use_canonicalizing, true,"use hydrogen instruction canonicalizing") DEFINE_bool(use_inlining, true,"use function inlining") DEFINE_int(max_inlined_source_size, 600,"maximum source size in bytes considered for a single inlining") DEFINE_int(max_inlined_nodes, 196,"maximum number of AST nodes considered for a single inlining") DEFINE_int(max_inlined_nodes_cumulative, 196,"maximum cumulative number of AST nodes considered for inlining") DEFINE_bool(loop_invariant_code_motion, true,"loop invariant code motion") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true,"crankshaft harvests type feedback from stub cache") DEFINE_bool(hydrogen_stats, false,"print statistics for hydrogen") DEFINE_bool(trace_hydrogen, false,"trace generated hydrogen to file") DEFINE_string(trace_phase,"Z","trace generated IR for specified phases") DEFINE_bool(trace_inlining, false,"trace inlining decisions") DEFINE_bool(trace_alloc, false,"trace register allocator") DEFINE_bool(trace_all_uses, false,"trace all use positions") DEFINE_bool(trace_range, false,"trace range analysis") DEFINE_bool(trace_gvn, false,"trace global value numbering") DEFINE_bool(trace_representation, false,"trace representation types") DEFINE_bool(stress_pointer_maps, false,"pointer map for every instruction") DEFINE_bool(stress_environments, false,"environment for every instruction") DEFINE_int(deopt_every_n_times, 0,"deoptimize every n times a deopt point is passed") DEFINE_bool(trap_on_deopt, false,"put a break point before deoptimizing") DEFINE_bool(deoptimize_uncommon_cases, true,"deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true,"polymorphic inlining") DEFINE_bool(use_osr, true,"use on-stack replacement") DEFINE_bool(array_bounds_checks_elimination, false,"perform array bounds checks elimination") DEFINE_bool(array_index_dehoisting, false,"perform array index dehoisting") DEFINE_bool(trace_osr, false,"trace on-stack replacement") DEFINE_int(stress_runs, 0,"number of stress runs") DEFINE_bool(optimize_closures, true,"optimize closures") DEFINE_bool(inline_construct, true,"inline constructor calls") DEFINE_bool(inline_arguments, true,"inline functions with arguments object") DEFINE_int(loop_weight, 1,"loop weight for representation inference") DEFINE_bool(optimize_for_in, true,"optimize functions containing for-in loops") DEFINE_bool(experimental_profiler, true,"enable all profiler experiments") DEFINE_bool(watch_ic_patching, false,"profiler considers IC stability") DEFINE_int(frame_count, 1,"number of stack frames inspected by the profiler") DEFINE_bool(self_optimization, false,"primitive functions trigger their own optimization") DEFINE_bool(direct_self_opt, false,"call recompile stub directly when self-optimizing") DEFINE_bool(retry_self_opt, false,"re-try self-optimization if it failed") DEFINE_bool(count_based_interrupts, false,"trigger profiler ticks based on counting instead of timing") DEFINE_bool(interrupt_at_exit, false,"insert an interrupt check at function exit") DEFINE_bool(weighted_back_edges, false,"weight back edges by jump distance for interrupt triggering") DEFINE_int(interrupt_budget, 5900,"execution budget before interrupt is triggered") DEFINE_int(type_info_threshold, 15,"percentage of ICs that must have type info to allow optimization") DEFINE_int(self_opt_count, 130,"call count before self-optimization") DEFINE_implication(experimental_profiler, watch_ic_patching) DEFINE_implication(experimental_profiler, self_optimization) DEFINE_implication(experimental_profiler, retry_self_opt) DEFINE_implication(experimental_profiler, count_based_interrupts) DEFINE_implication(experimental_profiler, interrupt_at_exit) DEFINE_implication(experimental_profiler, weighted_back_edges) DEFINE_bool(trace_opt_verbose, false,"extra verbose compilation tracing") DEFINE_implication(trace_opt_verbose, trace_opt) DEFINE_bool(debug_code, false,"generate extra code (assertions) for debugging") DEFINE_bool(code_comments, false,"emit comments in code disassembly") DEFINE_bool(enable_sse2, true,"enable use of SSE2 instructions if available") DEFINE_bool(enable_sse3, true,"enable use of SSE3 instructions if available") DEFINE_bool(enable_sse4_1, true,"enable use of SSE4.1 instructions if available") DEFINE_bool(enable_cmov, true,"enable use of CMOV instruction if available") DEFINE_bool(enable_rdtsc, true,"enable use of RDTSC instruction if available") DEFINE_bool(enable_sahf, true,"enable use of SAHF instruction if available (X64 only)") DEFINE_bool(enable_vfp3, true,"enable use of VFP3 instructions if available - this implies ""enabling ARMv7 instructions (ARM only)") DEFINE_bool(enable_armv7, true,"enable use of ARMv7 instructions if available (ARM only)") DEFINE_bool(enable_fpu, true,"enable use of MIPS FPU instructions if available (MIPS only)") DEFINE_string(expose_natives_as, NULL,"expose natives in global object") DEFINE_string(expose_debug_as, NULL,"expose debug in global object") DEFINE_bool(expose_gc, false,"expose gc extension") DEFINE_bool(expose_externalize_string, false,"expose externalize string extension") DEFINE_int(stack_trace_limit, 10,"number of stack frames to capture") DEFINE_bool(builtins_in_stack_traces, false,"show built-in functions in stack traces") DEFINE_bool(disable_native_files, false,"disable builtin natives files") DEFINE_bool(inline_new, true,"use fast inline allocation") DEFINE_bool(stack_trace_on_abort, true,"print a stack trace if an assertion failure occurs") DEFINE_bool(trace, false,"trace function calls") DEFINE_bool(mask_constants_with_cookie, true,"use random jit cookie to mask large constants") DEFINE_bool(lazy, true,"use lazy compilation") DEFINE_bool(trace_opt, false,"trace lazy optimization") DEFINE_bool(trace_opt_stats, false,"trace lazy optimization statistics") DEFINE_bool(opt, true,"use adaptive optimizations") DEFINE_bool(always_opt, false,"always try to optimize functions") DEFINE_bool(prepare_always_opt, false,"prepare for turning on always opt") DEFINE_bool(trace_deopt, false,"trace deoptimization") DEFINE_int(min_preparse_length, 1024,"minimum length for automatic enable preparsing") DEFINE_bool(always_full_compiler, false,"try to use the dedicated run-once backend for all code") DEFINE_bool(trace_bailout, false,"print reasons for falling back to using the classic V8 backend") DEFINE_bool(compilation_cache, true,"enable compilation cache") DEFINE_bool(cache_prototype_transitions, true,"cache prototype transitions") DEFINE_bool(trace_debug_json, false,"trace debugging JSON request/response") DEFINE_bool(debugger_auto_break, true,"automatically set the debug break flag when debugger commands are ""in the queue") DEFINE_bool(enable_liveedit, true,"enable liveedit experimental feature") DEFINE_bool(break_on_abort, true,"always cause a debug break before aborting") DEFINE_int(stack_size, kPointerSize *123,"default size of stack region v8 is allowed to use (in kBytes)") DEFINE_int(max_stack_trace_source_length, 300,"maximum length of function source code printed in a stack trace.") DEFINE_bool(always_inline_smi_code, false,"always inline smi code in non-opt code") DEFINE_int(max_new_space_size, 0,"max size of the new generation (in kBytes)") DEFINE_int(max_old_space_size, 0,"max size of the old generation (in Mbytes)") DEFINE_int(max_executable_size, 0,"max size of executable memory (in Mbytes)") DEFINE_bool(gc_global, false,"always perform global GCs") DEFINE_int(gc_interval,-1,"garbage collect after <n> allocations") DEFINE_bool(trace_gc, false,"print one trace line following each garbage collection") DEFINE_bool(trace_gc_nvp, false,"print one detailed trace line in name=value format ""after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false,"print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false,"print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false,"report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true,"garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true,"flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true,"use incremental marking") DEFINE_bool(incremental_marking_steps, true,"do incremental marking steps") DEFINE_bool(trace_incremental_marking, false,"trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true,"Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false,"Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true,"use inline caching") DEFINE_bool(native_code_counters, false,"generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false,"Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true,"Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false,"Never perform compaction on full GC - testing only") DEFINE_bool(compact_code_space, true,"Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true,"Flush inline caches prior to mark compact collection and ""flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0,"Default seed for initializing random generator ""(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true,"allows verbose printing") DEFINE_bool(allow_natives_syntax, false,"allow natives syntax") DEFINE_bool(trace_sim, false,"Trace simulator execution") DEFINE_bool(check_icache, false,"Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0,"Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8,"Stack alingment in bytes in simulator (4 or 8, 8 is default)") DEFINE_bool(trace_exception, false,"print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false,"preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true,"randomize hashes to avoid predictable hash collisions ""(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0,"Fixed seed to use to hash property keys (0 means random)""(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false,"activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true,"generate optimized regexp code") DEFINE_bool(testing_bool_flag, true,"testing_bool_flag") DEFINE_int(testing_int_flag, 13,"testing_int_flag") DEFINE_float(testing_float_flag, 2.5,"float-flag") DEFINE_string(testing_string_flag,"Hello, world!","string-flag") DEFINE_int(testing_prng_seed, 42,"Seed used for threading test randomness") DEFINE_string(testing_serialization_file,"/tmp/serdes","file in which to serialize heap") DEFINE_bool(help, false,"Print usage message, including flags, on console") DEFINE_bool(dump_counters, false,"Dump counters on exit") DEFINE_string(map_counters,"","Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT,"Pass all remaining arguments to the script. Alias for \"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#47"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2 namespace{struct Flag{enum FlagType{TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS} name
Definition: flags.cc:1349
V8EXPORT bool IsBooleanObject() const
Definition: api.cc:2290
~Whammy()
Definition: test-api.cc:5047
static Handle< T > cast(Handle< S > that)
Definition: handles.h:81
Local< String > Get() const
Definition: api.cc:1773
bool pass_on_get
Definition: test-api.cc:12178
static void SetCaptureStackTraceForUncaughtExceptions(bool capture, int frame_limit=10, StackTrace::StackTraceOptions options=StackTrace::kOverview)
Definition: api.cc:5166
static Array * Cast(Value *obj)
Definition: v8.h:4394
void AllowCodeGenerationFromStrings(bool allow)
Definition: api.cc:4503
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
Local< Function > Callee() const
Definition: v8.h:4111
const int kSmiValueSize
Definition: v8.h:3900
int epilogue_call_count
Definition: test-api.cc:14711
void SetData(Handle< String > data)
Definition: api.cc:1652
v8::Handle< Value > AnalyzeStackInNativeCode(const v8::Arguments &args)
Definition: test-api.cc:13675
bool IsAsciiRepresentation()
Definition: objects-inl.h:289
UC16VectorResource(i::Vector< const i::uc16 > vector)
Definition: test-api.cc:11887
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:13654
v8::Handle< Value > ProvokeOutOfMemory(const v8::Arguments &args)
Definition: test-api.cc:2647
static V8EXPORT Local< String > NewSymbol(const char *data, int length=-1)
Definition: api.cc:5075
Local< ObjectTemplate > InstanceTemplate()
Definition: api.cc:1115
size_t used_heap_size()
Definition: v8.h:2746
Handle< Primitive > V8EXPORT Null()
Definition: api.cc:556
v8::Handle< Script > getScript()
Definition: test-api.cc:5050
v8::Persistent< Context > calling_context0
Definition: test-api.cc:12422
int int32_t
Definition: unicode.cc:47
V8EXPORT bool HasRealNamedCallbackProperty(Handle< String > key)
Definition: api.cc:3133
V8EXPORT Local< Value > GetHiddenValue(Handle< String > key)
Definition: api.cc:3301
static Handle< T > Cast(Handle< S > that)
Definition: v8.h:243
static Local< Value > Error(Handle< String > message)
Definition: api.cc:5543
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:1379
Handle< Object > SetAccessor(Handle< JSObject > obj, Handle< AccessorInfo > info)
Definition: handles.cc:342
V8EXPORT Local< Array > GetPropertyNames()
Definition: api.cc:2938
V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType()
Definition: api.cc:3482
#define CHECK_LT(a, b)
Definition: checks.h:229
V8EXPORT Local< Value > Call(Handle< Object > recv, int argc, Handle< Value > argv[])
Definition: api.cc:3629
THREADED_TEST(Handles)
Definition: test-api.cc:140
V8EXPORT bool IsRegExp() const
Definition: api.cc:2298
virtual void VisitExternalString(v8::Handle< v8::String > string)
Definition: test-api.cc:14194
#define ASSERT(condition)
Definition: checks.h:270
void Clear()
Definition: v8.h:213
v8::Handle< Value > WhammyPropertyGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:5069
ApiTestFuzzer * fuzzer_
Definition: cctest.h:155
ExternalArrayType
Definition: v8.h:1407
void CheckProperties(v8::Handle< v8::Value > val, int elmc, const char *elmv[])
Definition: test-api.cc:11040
unsigned short uint16_t
Definition: unicode.cc:46
void DisposingCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10803
v8::Handle< v8::Value > DirectGetterCallback(Local< String > name, const v8::AccessorInfo &info)
Definition: test-api.cc:9425
V8EXPORT void * GetIndexedPropertiesExternalArrayData()
Definition: api.cc:3469
v8::Handle< Script > call_recursively_script
Definition: test-api.cc:1808
Local< Value > Data() const
Definition: v8.h:4128
static V8EXPORT Local< Value > Wrap(void *data)
Definition: api.cc:4583
Whammy()
Definition: test-api.cc:5044
kPropertyAccessorsOffset kNamedPropertyHandlerOffset instance_template
Definition: objects-inl.h:3618
Local< Value > GetInternalField(int index)
Definition: v8.h:4180
static bool IsEnabled()
Definition: snapshot.h:47
V8EXPORT Local< String > ToString() const
Definition: api.cc:2305
v8::Handle< Value > JSCheck(const v8::Arguments &args)
Definition: test-api.cc:3165
#define CHECK(condition)
Definition: checks.h:56
Handle< Value >(* IndexedPropertySetter)(uint32_t index, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:2071
const Register r2
static intptr_t AdjustAmountOfExternalAllocatedMemory(intptr_t change_in_bytes)
Definition: api.cc:5235
void SetVerbose(bool value)
Definition: api.cc:1760
int isnan(double x)
virtual size_t length() const
Definition: test-api.cc:11890
virtual const char * data() const
Definition: test-api.cc:11879
void Set(Handle< String > name, Handle< Data > value, PropertyAttribute attributes=None)
Definition: api.cc:894
v8::Handle< Value > CThrowCountDown(const v8::Arguments &args)
Definition: test-api.cc:3132
static ExternalAsciiString * cast(Object *obj)
int prologue_call_count
Definition: test-api.cc:14710
#define CHECK_GE(a, b)
Definition: checks.h:228
PropertyAttributes
void NewPersistentHandleCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10753
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback)
Definition: api.cc:5203
static void * Unwrap(Handle< Value > obj)
Definition: v8.h:4207
V8EXPORT void SetIndexedPropertiesToExternalArrayData(void *data, ExternalArrayType array_type, int number_of_elements)
Definition: api.cc:3437
Handle< Value > EmptyInterceptorSetter(Local< String > name, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1320
V8EXPORT bool Equals(Handle< Value > that) const
Definition: api.cc:2676
V8EXPORT Handle< Value > GetScriptId() const
Definition: api.cc:3710
static void VisitExternalResources(ExternalResourceVisitor *visitor)
Definition: api.cc:4261
v8::Handle< Value > call_ic_function3
Definition: test-api.cc:9042
void CallCompletedCallbackException()
Definition: test-api.cc:16419
v8::Handle< v8::Value > ThrowingDirectApiCallback(const v8::Arguments &args)
Definition: test-api.cc:9399
Handle< Value > GetScriptResourceName() const
Definition: api.cc:1785
static void AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll)
Definition: api.cc:5259
static Smi * cast(Object *object)
Handle< String > FlattenGetString(Handle< String > string)
Definition: handles.cc:216
V8EXPORT bool IsExternal() const
Definition: api.cc:4023
V8EXPORT bool HasIndexedPropertiesInExternalArrayData()
Definition: api.cc:3460
v8::Persistent< Value > xValue
Definition: test-api.cc:3682
V8EXPORT void SetInternalField(int index, Handle< Value > value)
Definition: api.cc:4150
v8::Handle< Value > CheckThisNamedPropertySetter(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1653
void SetClassName(Handle< String > name)
Definition: api.cc:1132
static V8EXPORT Local< Integer > NewFromUnsigned(uint32_t value)
Definition: api.cc:5113
int foo
Handle< Value >(* IndexedPropertyGetter)(uint32_t index, const AccessorInfo &info)
Definition: v8.h:2063
void CheckCodeGenerationAllowed()
Definition: test-api.cc:15975
static v8::Handle< v8::Value > Echo(const v8::Arguments &args)
Definition: test-api.cc:4796
Local< StackFrame > GetFrame(uint32_t index) const
Definition: api.cc:1968
static const char * GetVersion()
Definition: api.cc:4291
V8EXPORT Local< Value > GetRealNamedProperty(Handle< String > key)
Definition: api.cc:3198
Local< Value > Id()
Definition: api.cc:1635
V8EXPORT bool IsExternalAscii() const
Definition: api.cc:4033
V8EXPORT bool IsStringObject() const
Definition: api.cc:2239
V8EXPORT ScriptOrigin GetScriptOrigin() const
Definition: api.cc:3674
static Local< Script > New(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1499
TestResource(uint16_t *data, int *counter=NULL)
Definition: test-api.cc:337
v8::Handle< Value > CCatcher(const v8::Arguments &args)
Definition: test-api.cc:2939
const SwVfpRegister s3
size_t length() const
Definition: test-api.cc:351
const int MB
Definition: d8.cc:124
V8EXPORT int InternalFieldCount()
Definition: api.cc:4121
#define UNREACHABLE()
Definition: checks.h:50
static bool AddMessageListener(MessageCallback that, Handle< Value > data=Handle< Value >())
Definition: api.cc:5130
Handle< Value >(* InvocationCallback)(const Arguments &args)
Definition: v8.h:2017
static ScriptData * PreCompile(const char *input, int length)
Definition: api.cc:1455
Handle< Value >(* NamedPropertyGetter)(Local< String > property, const AccessorInfo &info)
Definition: v8.h:2023
const char * name()
Definition: cctest.h:156
virtual const char * Data()=0
V8EXPORT void * Value() const
Definition: api.cc:4638
void CheckCodeGenerationDisallowed()
Definition: test-api.cc:15985
T * start() const
Definition: utils.h:389
static void RemoveCallCompletedCallback(CallCompletedCallback callback)
Definition: api.cc:5314
v8::Handle< Value > CheckThisIndexedPropertySetter(uint32_t index, Local< Value > value, const AccessorInfo &info)
Definition: test-api.cc:1644
void set_max_old_space_size(int value)
Definition: v8.h:2610
Handle< Value > RecursiveCall(const Arguments &args)
Definition: test-api.cc:16361
static Local< ObjectTemplate > New()
Definition: api.cc:1246
virtual bool HasError()=0
V8EXPORT bool HasIndexedPropertiesInPixelData()
Definition: api.cc:3404
void DetachGlobal()
Definition: api.cc:4479
Handle< Value > HasOwnPropertyIndexedPropertyGetter(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:15861
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:14723
Handle< Value > ReThrow()
Definition: api.cc:1705
static void Fuzz()
Definition: test-api.cc:10412
V8EXPORT Local< Value > GetPrototype()
Definition: api.cc:2892
static void GetHeapStatistics(HeapStatistics *heap_statistics)
Definition: api.cc:4242
static bool IsValid(intptr_t value)
Definition: objects-inl.h:1051
void set_resource(const Resource *buffer)
Definition: objects-inl.h:2473
TEST(MakingExternalStringConditions)
Definition: test-api.cc:484
V8EXPORT bool ForceDelete(Handle< Value > key)
Definition: api.cc:2821
v8::Handle< v8::Object > bottom
Definition: test-api.cc:1625
void CallCompletedCallback1()
Definition: test-api.cc:16349
TestAsciiResource(const char *data, int *counter=NULL)
Definition: test-api.cc:363
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 trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt 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 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
static const int kNoGCFlags
Definition: heap.h:1049
int p_getter_count
Definition: test-api.cc:5409
virtual ~AsciiVectorResource()
Definition: test-api.cc:11877
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:1284
v8::Handle< v8::Value > DirectApiCallback(const v8::Arguments &args)
Definition: test-api.cc:9370
void SetInternalFieldCount(int value)
Definition: api.cc:1431
int NumberOfWeakCalls()
Definition: test-api.cc:2193
Handle< v8::Integer > HasOwnPropertyNamedPropertyQuery(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:15882
int GetColumn() const
Definition: api.cc:2029
int index_
Definition: test-api.cc:5039
static Isolate * New()
Definition: api.cc:5386
static void SetFatalErrorHandler(FatalErrorCallback that)
Definition: api.cc:454
static int ContextDisposedNotification()
Definition: api.cc:4284
bool CodeGenerationDisallowed(Local< Context > context)
Definition: test-api.cc:16010
int Length() const
Definition: v8.h:4143
V8EXPORT int32_t Int32Value() const
Definition: api.cc:2654
v8::Handle< Value >(* NamedPropertyGetter)(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:8591
void(* AccessorSetter)(Local< String > property, Local< Value > value, const AccessorInfo &info)
Definition: v8.h:1428
V8EXPORT Local< Object > NewInstance() const
Definition: api.cc:3605
IsolateThread(v8::Isolate *isolate, int fib_limit)
Definition: test-api.cc:15287
bool IsConstructor() const
Definition: api.cc:2104
Local< Object > Global()
Definition: api.cc:4467
static FunctionTemplateInfo * cast(Object *obj)
V8EXPORT void SetIndexedPropertiesToPixelData(uint8_t *data, int length)
Definition: api.cc:3384
V8EXPORT void TurnOnAccessCheck()
Definition: api.cc:3214
int prologue_call_count_second
Definition: test-api.cc:14712
int length() const
Definition: utils.h:383
V8EXPORT int GetScriptColumnNumber() const
Definition: api.cc:3701
void Enter()
Definition: api.cc:5403
static void RemoveMessageListeners(MessageCallback that)
Definition: api.cc:5147
GCType
Definition: v8.h:2718
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:9663
V8EXPORT bool Has(Handle< String > key)
Definition: api.cc:3056
const uint16_t * data() const
Definition: test-api.cc:347
void increment()
Definition: test-api.cc:2192
V8EXPORT bool SetHiddenValue(Handle< String > key, Handle< Value > value)
Definition: api.cc:3286
void set_stack_limit(uint32_t *value)
Definition: v8.h:2615
static Persistent< T > New(Handle< T > that)
Definition: v8.h:4043
const SwVfpRegister s0
static const int kMakeHeapIterableMask
Definition: heap.h:1056
uint8_t callback_fired
Definition: test-api.cc:16346
AccessType
Definition: v8.h:2101
virtual void Run()
Definition: test-api.cc:10440
void FailedAccessCheckCallbackGC(Local< v8::Object > target, v8::AccessType type, Local< v8::Value > data)
Definition: test-api.cc:14971
V8EXPORT bool BooleanValue() const
Definition: api.cc:2532
void set_resource(const Resource *buffer)
Definition: objects-inl.h:2505
const FPURegister f2
size_t length() const
Definition: test-api.cc:375
v8::Handle< v8::Array > CheckThisNamedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:1704
Handle< Value > HasOwnPropertyNamedPropertyGetter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:15868
bool IsUndefined() const
Definition: v8.h:4277
void(* WeakReferenceCallback)(Persistent< Value > object, void *parameter)
Definition: v8.h:137
int GetLineNumber() const
Definition: api.cc:1865
Handle< v8::Integer > HasOwnPropertyIndexedPropertyQuery(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:15875
static Local< Value > RangeError(Handle< String > message)
Definition: api.cc:5478
#define CHECK_NE(unexpected, value)
Definition: checks.h:223
Handle< Boolean > V8EXPORT False()
Definition: api.cc:576
static void Sleep(const int milliseconds)
static const int kAbortIncrementalMarkingMask
Definition: heap.h:1052
Vector< const char > CStrVector(const char *data)
Definition: utils.h:525
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:1309
v8::Handle< Value > HandleF(const v8::Arguments &args)
Definition: test-api.cc:2517
static void Print(const char *format,...)
Local< Object > This() const
Definition: v8.h:4117
#define T(name, string, precedence)
Definition: token.cc:48
static void AddCallCompletedCallback(CallCompletedCallback callback)
Definition: api.cc:5305
Definition: v8.h:1714
Local< String > GetScriptName() const
Definition: api.cc:2045
v8::Handle< v8::Value > ThrowingDirectGetterCallback(Local< String > name, const v8::AccessorInfo &info)
Definition: test-api.cc:9451
bool IsString() const
Definition: v8.h:4313
const SwVfpRegister s1
static Local< Object > Cast(Local< S > that)
Definition: v8.h:281
V8EXPORT bool IsObject() const
Definition: api.cc:2169
v8::Handle< v8::Boolean > CheckThisIndexedPropertyDeleter(uint32_t index, const AccessorInfo &info)
Definition: test-api.cc:1678
Definition: v8.h:1401
bool IsCodeGenerationFromStringsAllowed()
Definition: api.cc:4517
static Local< Value > ReferenceError(Handle< String > message)
Definition: api.cc:5494
virtual ~UC16VectorResource()
Definition: test-api.cc:11889
static int SNPrintF(Vector< char > str, const char *format,...)
Local< Value > StackTrace() const
Definition: api.cc:1724
static V8EXPORT v8::Local< v8::String > Empty()
Definition: api.cc:4645
static Semaphore * CreateSemaphore(int count)
#define ISOLATE
Definition: isolate.h:1410
int ToNumber(Register reg)
V8EXPORT bool IsDate() const
Definition: api.cc:2231
void AddInterceptor(Handle< FunctionTemplate > templ, v8::NamedPropertyGetter getter, v8::NamedPropertySetter setter)
Definition: test-api.cc:1359
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:3272
static int NumberOfHandles()
Definition: api.cc:712
static void WriteToFlat(String *source, sinkchar *sink, int from, int to)
Definition: objects.cc:6819
V8EXPORT int GetIndexedPropertiesExternalArrayDataLength()
Definition: api.cc:3512
const Register r1
V8EXPORT uint32_t Uint32Value() const
Definition: api.cc:2735
static double nan_value()
static Local< AccessorSignature > New(Handle< FunctionTemplate > receiver=Handle< FunctionTemplate >())
Definition: api.cc:993
void AddAccessor(Handle< FunctionTemplate > templ, Handle< String > name, v8::AccessorGetter getter, v8::AccessorSetter setter)
Definition: test-api.cc:1352
VisitorImpl(TestResource *r1, TestResource *r2)
Definition: test-api.cc:14188
bool is_null() const
Definition: handles.h:87
V8EXPORT bool IsNumber() const
Definition: api.cc:2175
int cursor_
Definition: test-api.cc:5058
void CallCompletedCallback2()
Definition: test-api.cc:16355
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:14719
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< String > name)
Definition: test-api.cc:4914
V8EXPORT Local< String > StringValue() const
Definition: api.cc:4894
Local< Function > GetFunction()
Definition: api.cc:4551
void CheckVisitedResources()
Definition: test-api.cc:14211
static RegisterThreadedTest * nth(int i)
Definition: cctest.h:145
uint16_t uc16
Definition: globals.h:273
V8EXPORT bool ForceSet(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2799
void DisposeAndForceGcCallback(v8::Persistent< v8::Value > handle, void *)
Definition: test-api.cc:10782
V8EXPORT bool Delete(Handle< String > key)
Definition: api.cc:3045
int GetUtf8Length(Handle< String > str)
Definition: test-api.cc:5529
static Local< Value > SyntaxError(Handle< String > message)
Definition: api.cc:5511
V8EXPORT Local< Object > Clone()
Definition: api.cc:3237
virtual int Length()=0
virtual void Signal()=0
v8::Persistent< v8::Object > bad_handle
Definition: test-api.cc:10751
void CheckOwnProperties(v8::Handle< v8::Value > val, int elmc, const char *elmv[])
Definition: test-api.cc:11051
virtual const i::uc16 * data() const
Definition: test-api.cc:11891
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:3085
ApiTestFuzzer(int num)
Definition: cctest.h:90
Handle< Value > InterceptorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1326
AsciiVectorResource(i::Vector< const char > vector)
Definition: test-api.cc:11875
const char * data() const
Definition: test-api.cc:371
V8EXPORT int GetIndexedPropertiesPixelDataLength()
Definition: api.cc:3425
WeakCallCounter(int id)
Definition: test-api.cc:2190
Local< ObjectTemplate > PrototypeTemplate()
Definition: api.cc:920
#define HEAP
Definition: isolate.h:1408
int global_index
Definition: test-api.cc:5034
V8EXPORT bool IsFalse() const
Definition: api.cc:2141
v8::Handle< v8::Boolean > CheckThisNamedPropertyDeleter(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:1687
V8EXPORT Flags GetFlags() const
Definition: api.cc:5017
const FPURegister f1
static Local< Value > TypeError(Handle< String > message)
Definition: api.cc:5527
static Local< Signature > New(Handle< FunctionTemplate > receiver=Handle< FunctionTemplate >(), int argc=0, Handle< FunctionTemplate > argv[]=0)
Definition: api.cc:970
Definition: v8.h:1782
void USE(T)
Definition: globals.h:303
const SwVfpRegister s4
static V8EXPORT Local< Integer > New(int32_t value)
Definition: api.cc:5100
V8EXPORT int GetScriptLineNumber() const
Definition: api.cc:3691
virtual size_t length() const
Definition: test-api.cc:11878
static void RemoveGCEpilogueCallback(GCEpilogueCallback callback)
Definition: api.cc:5280
Handle< StackTrace > GetStackTrace() const
Definition: api.cc:1819
InitDefaultIsolateThread(TestCase testCase)
Definition: test-api.cc:15367
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< v8::String > name)
Definition: test-api.cc:4791
static void StartPreemption(int every_n_ms)
Definition: v8threads.cc:142
void(* MessageCallback)(Handle< Message > message, Handle< Value > data)
Definition: v8.h:2633
static void SetCreateHistogramFunction(CreateHistogramCallback)
Definition: api.cc:5183
Local< T > Close(Handle< T > value)
Definition: v8.h:4149
V8EXPORT bool IsNumberObject() const
Definition: api.cc:2247
V8EXPORT int WriteAscii(char *buffer, int start=0, int length=-1, int options=NO_OPTIONS) const
Definition: api.cc:3960
static void RemoveGCPrologueCallback(GCPrologueCallback callback)
Definition: api.cc:5266
static bool ReportApiFailure(const char *location, const char *message)
Definition: api.cc:219
Handle< Primitive > V8EXPORT Undefined()
Definition: api.cc:546
static V8EXPORT Local< Number > New(double value)
Definition: api.cc:5087
v8::Handle< v8::Value > WithTryCatch(const v8::Arguments &args)
Definition: test-api.cc:3342
virtual void Wait()=0
bool IsEmpty() const
Definition: v8.h:208
Local< Value > Run()
Definition: api.cc:1590
#define FACTORY
Definition: isolate.h:1409
int echo_indexed_call_count
Definition: test-api.cc:1599
V8EXPORT double NumberValue() const
Definition: api.cc:4851
bool CodeGenerationAllowed(Local< Context > context)
Definition: test-api.cc:16004
GCCallbackFlags
Definition: v8.h:2724
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4308
CcTest::TestFunction * callback()
Definition: cctest.h:154
static Local< StackTrace > CurrentStackTrace(int frame_limit, StackTraceOptions options=kOverview)
Definition: api.cc:1998
static Local< TypeSwitch > New(Handle< FunctionTemplate > type)
Definition: api.cc:999
void CallTest()
Definition: test-api.cc:10551
int epilogue_call_count_second
Definition: test-api.cc:14713
char * StrDup(const char *str)
Definition: allocation.cc:85
V8EXPORT uint32_t Length() const
Definition: api.cc:5040
bool message_received
Definition: test-api.cc:2388
static ScriptData * New(const char *data, int length)
Definition: api.cc:1475
static V8EXPORT Local< External > New(void *value)
Definition: api.cc:4628
Isolate * GetIsolate() const
Definition: v8.h:4133
V8EXPORT bool IsInt32() const
Definition: api.cc:2197
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:3116
static Handle< Boolean > New(bool value)
Definition: v8.h:4170
size_t total_heap_size()
Definition: v8.h:2744
Handle< v8::Array > UnboxedDoubleIndexedPropertyEnumerator(const AccessorInfo &info)
Definition: test-api.cc:3909
static void SetUp(PartOfTest part)
Definition: test-api.cc:10464
static V8EXPORT Local< String > NewExternal(ExternalStringResource *resource)
Definition: api.cc:4747
int p_getter_count2
Definition: test-api.cc:5410
void DeleteArray(T *array)
Definition: allocation.h:91
bool V8EXPORT SetResourceConstraints(ResourceConstraints *constraints)
Definition: api.cc:593
V8EXPORT Handle< Value > GetInferredName() const
Definition: api.cc:3668
void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type)
Definition: test-api.cc:13592
static ConsString * cast(Object *obj)
void ClearWeak()
Definition: v8.h:4082
void MarkIndependent()
Definition: v8.h:4087
static void StopPreemption()
Definition: v8threads.cc:147
Handle< Value > V8EXPORT ThrowException(Handle< Value > exception)
Definition: api.cc:485
void SetData(void *data)
Definition: v8.h:4474
static const int kMaxValue
Definition: objects.h:1006
bool IsConstructCall() const
Definition: v8.h:4138
void Reset()
Definition: api.cc:1753
Handle< Value >(* AccessorGetter)(Local< String > property, const AccessorInfo &info)
Definition: v8.h:1424
v8::Handle< Function > args_fun
Definition: test-api.cc:5231
Definition: v8.h:105
int match(Handle< Value > value)
Definition: api.cc:1022
Local< v8::Message > Message() const
Definition: api.cc:1742
V8EXPORT int Write(uint16_t *buffer, int start=0, int length=-1, int options=NO_OPTIONS) const
Definition: api.cc:3994
Handle< Value > EmptyInterceptorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1315
AccessControl
Definition: v8.h:1446
static bool IsLocked(Isolate *isolate=NULL)
Definition: v8threads.cc:88
void Inherit(Handle< FunctionTemplate > parent)
Definition: api.cc:935
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags)
Definition: test-api.cc:14727
v8::Handle< v8::Integer > CheckThisNamedPropertyQuery(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:1670
static bool Initialize()
Definition: api.cc:4204
NativeFunctionExtension(const char *name, const char *source, v8::InvocationCallback fun=&Echo)
Definition: test-api.cc:4785
FlagType type() const
Definition: flags.cc:1358
Local< String > GetFunctionName() const
Definition: api.cc:2077
Local< String > GetSourceLine() const
Definition: api.cc:1940
static V8EXPORT Local< Object > New()
Definition: api.cc:4829
Handle< v8::Integer > HasOwnPropertyNamedPropertyQuery2(Local< String > property, const AccessorInfo &info)
Definition: test-api.cc:15889
Handle< Value > SimpleAccessorGetter(Local< String > name, const AccessorInfo &info)
Definition: test-api.cc:1303
static void SetCounterFunction(CounterLookupCallback)
Definition: api.cc:5177
V8EXPORT Local< Uint32 > ToArrayIndex() const
Definition: api.cc:2625
static v8::internal::Handle< v8::internal::TemplateInfo > OpenHandle(const Template *that)
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:1347
V8EXPORT bool Value() const
Definition: api.cc:4081
V8EXPORT bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2757
static const int kObjectCount
Definition: test-api.cc:5057
const char * name() const
Definition: platform.h:457
int GetFrameCount() const
Definition: api.cc:1982
v8::Persistent< v8::Object > objects_[kObjectCount]
Definition: test-api.cc:5059
static bool IdleNotification(int hint=1000)
Definition: api.cc:4268
V8EXPORT double NumberValue() const
Definition: api.cc:4924
v8::Handle< Value > call_ic_function2
Definition: test-api.cc:9041
static void IgnoreOutOfMemoryException()
Definition: api.cc:5125