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
43static const bool kLogThreading = false;
44
45static bool IsNaN(double x) {
46#ifdef WIN32
47  return _isnan(x);
48#else
49  return isnan(x);
50#endif
51}
52
53using ::v8::AccessorInfo;
54using ::v8::Arguments;
55using ::v8::Context;
56using ::v8::Extension;
57using ::v8::Function;
58using ::v8::FunctionTemplate;
59using ::v8::Handle;
60using ::v8::HandleScope;
61using ::v8::Local;
62using ::v8::Message;
63using ::v8::MessageCallback;
64using ::v8::Object;
65using ::v8::ObjectTemplate;
66using ::v8::Persistent;
67using ::v8::Script;
68using ::v8::StackTrace;
69using ::v8::String;
70using ::v8::TryCatch;
71using ::v8::Undefined;
72using ::v8::V8;
73using ::v8::Value;
74
75
76static 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
83static 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
89static 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
96static void ExpectTrue(const char* code) {
97  ExpectBoolean(code, true);
98}
99
100
101static void ExpectFalse(const char* code) {
102  ExpectBoolean(code, false);
103}
104
105
106static void ExpectObject(const char* code, Local<Value> expected) {
107  Local<Value> result = CompileRun(code);
108  CHECK(result->Equals(expected));
109}
110
111
112static void ExpectUndefined(const char* code) {
113  Local<Value> result = CompileRun(code);
114  CHECK(result->IsUndefined());
115}
116
117
118static int signature_callback_count;
119static v8::Handle<Value> IncrementingSignatureCallback(
120    const v8::Arguments& args) {
121  ApiTestFuzzer::Fuzz();
122  signature_callback_count++;
123  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
124  for (int i = 0; i < args.Length(); i++)
125    result->Set(v8::Integer::New(i), args[i]);
126  return result;
127}
128
129
130static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
131  ApiTestFuzzer::Fuzz();
132  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
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
140THREADED_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
152  v8::Handle<v8::Primitive> undef = v8::Undefined();
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
165THREADED_TEST(ReceiverSignature) {
166  v8::HandleScope scope;
167  LocalContext env;
168  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
169  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
170  fun->PrototypeTemplate()->Set(
171      v8_str("m"),
172      v8::FunctionTemplate::New(IncrementingSignatureCallback,
173                                v8::Handle<Value>(),
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);
181  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
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();
197  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
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
209THREADED_TEST(ArgumentSignature) {
210  v8::HandleScope scope;
211  LocalContext env;
212  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
213  cons->SetClassName(v8_str("Cons"));
214  v8::Handle<v8::Signature> sig =
215      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
216  v8::Handle<v8::FunctionTemplate> fun =
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
230  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
231  cons1->SetClassName(v8_str("Cons1"));
232  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
233  cons2->SetClassName(v8_str("Cons2"));
234  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
235  cons3->SetClassName(v8_str("Cons3"));
236
237  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
238  v8::Handle<v8::Signature> wsig =
239      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
240  v8::Handle<v8::FunctionTemplate> fun2 =
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
271THREADED_TEST(HulIgennem) {
272  v8::HandleScope scope;
273  LocalContext env;
274  v8::Handle<v8::Primitive> undef = v8::Undefined();
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
283THREADED_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
298THREADED_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
317THREADED_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
327static 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
335class 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
342  ~TestResource() {
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
361class TestAsciiResource: public String::ExternalAsciiStringResource {
362 public:
363  explicit TestAsciiResource(const char* data, int* counter = NULL)
364    : data_(data), length_(strlen(data)), counter_(counter) { }
365
366  ~TestAsciiResource() {
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
385THREADED_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
410THREADED_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
432THREADED_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
458THREADED_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
484TEST(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
530TEST(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
567THREADED_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
585THREADED_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
603THREADED_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
623THREADED_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
642class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
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)
649      : TestAsciiResource(data, &dispose_count),
650        dispose_(dispose) { }
651
652  void Dispose() {
653    ++dispose_calls;
654    if (dispose_) delete this;
655  }
656 private:
657  bool dispose_;
658};
659
660
661int TestAsciiResourceWithDisposeControl::dispose_count = 0;
662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
663
664
665TEST(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
711THREADED_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
757THREADED_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
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768  ApiTestFuzzer::Fuzz();
769  return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774  ApiTestFuzzer::Fuzz();
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
780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781  ApiTestFuzzer::Fuzz();
782  return v8_num(239);
783}
784
785
786THREADED_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
827static void* expected_ptr;
828static 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
835static void TestExternalPointerWrapping() {
836  v8::HandleScope scope;
837  LocalContext env;
838
839  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841  v8::Handle<v8::Object> obj = v8::Object::New();
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
854THREADED_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
900THREADED_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
947THREADED_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
956THREADED_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
970THREADED_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
987THREADED_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
996THREADED_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
1007THREADED_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
1018THREADED_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
1029THREADED_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
1042THREADED_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
1067THREADED_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
1088THREADED_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());
1097  v8::Handle<v8::BooleanObject> as_boxed =
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
1113THREADED_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
1122THREADED_TEST(ToNumber) {
1123  v8::HandleScope scope;
1124  LocalContext env;
1125  Local<String> str = v8_str("3.1415926");
1126  CHECK_EQ(3.1415926, str->NumberValue());
1127  v8::Handle<v8::Boolean> t = v8::True();
1128  CHECK_EQ(1.0, t->NumberValue());
1129  v8::Handle<v8::Boolean> f = v8::False();
1130  CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
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
1145THREADED_TEST(Boolean) {
1146  v8::HandleScope scope;
1147  LocalContext env;
1148  v8::Handle<v8::Boolean> t = v8::True();
1149  CHECK(t->Value());
1150  v8::Handle<v8::Boolean> f = v8::False();
1151  CHECK(!f->Value());
1152  v8::Handle<v8::Primitive> u = v8::Undefined();
1153  CHECK(!u->BooleanValue());
1154  v8::Handle<v8::Primitive> n = v8::Null();
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
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169  ApiTestFuzzer::Fuzz();
1170  return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175  ApiTestFuzzer::Fuzz();
1176  return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181  v8::HandleScope scope;
1182  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
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
1198THREADED_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
1222static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1223  ApiTestFuzzer::Fuzz();
1224  return v8_num(17.2);
1225}
1226
1227
1228static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1229  ApiTestFuzzer::Fuzz();
1230  return v8_num(15.2);
1231}
1232
1233
1234THREADED_TEST(DescriptorInheritance) {
1235  v8::HandleScope scope;
1236  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
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
1243  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1244  base1->Inherit(super);
1245  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1246
1247  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
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
1290int echo_named_call_count;
1291
1292
1293static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1294                                           const AccessorInfo& info) {
1295  ApiTestFuzzer::Fuzz();
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
1303Handle<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
1309void 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
1315Handle<Value> EmptyInterceptorGetter(Local<String> name,
1316                                     const AccessorInfo& info) {
1317  return Handle<Value>();
1318}
1319
1320Handle<Value> EmptyInterceptorSetter(Local<String> name,
1321                                     Local<Value> value,
1322                                     const AccessorInfo& info) {
1323  return Handle<Value>();
1324}
1325
1326Handle<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
1340Handle<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
1352void 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
1359void AddInterceptor(Handle<FunctionTemplate> templ,
1360                    v8::NamedPropertyGetter getter,
1361                    v8::NamedPropertySetter setter) {
1362  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1363}
1364
1365THREADED_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"),
1371              SimpleAccessorGetter, SimpleAccessorSetter);
1372  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
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
1382THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1383  v8::HandleScope scope;
1384  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1385  Handle<FunctionTemplate> child = FunctionTemplate::New();
1386  child->Inherit(parent);
1387  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
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
1402THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1403  v8::HandleScope scope;
1404  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1405  Handle<FunctionTemplate> child = FunctionTemplate::New();
1406  child->Inherit(parent);
1407  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
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
1421THREADED_TEST(SwitchFromInterceptorToAccessor) {
1422  v8::HandleScope scope;
1423  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1424  AddAccessor(templ, v8_str("age"),
1425              SimpleAccessorGetter, SimpleAccessorSetter);
1426  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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
1438THREADED_TEST(SwitchFromAccessorToInterceptor) {
1439  v8::HandleScope scope;
1440  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1441  AddAccessor(templ, v8_str("age"),
1442              SimpleAccessorGetter, SimpleAccessorSetter);
1443  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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
1455THREADED_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"),
1461              SimpleAccessorGetter, SimpleAccessorSetter);
1462  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
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
1474THREADED_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"),
1480              SimpleAccessorGetter, SimpleAccessorSetter);
1481  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
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
1493THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1494  v8::HandleScope scope;
1495  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1496  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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
1517THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1518  v8::HandleScope scope;
1519  Handle<FunctionTemplate> templ = FunctionTemplate::New();
1520  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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
1541THREADED_TEST(SwitchFromInterceptorToProperty) {
1542  v8::HandleScope scope;
1543  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1544  Handle<FunctionTemplate> child = FunctionTemplate::New();
1545  child->Inherit(parent);
1546  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
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
1558THREADED_TEST(SwitchFromPropertyToInterceptor) {
1559  v8::HandleScope scope;
1560  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1561  Handle<FunctionTemplate> child = FunctionTemplate::New();
1562  child->Inherit(parent);
1563  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
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
1575THREADED_TEST(NamedPropertyHandlerGetter) {
1576  echo_named_call_count = 0;
1577  v8::HandleScope scope;
1578  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
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
1599int echo_indexed_call_count = 0;
1600
1601
1602static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1603                                             const AccessorInfo& info) {
1604  ApiTestFuzzer::Fuzz();
1605  CHECK_EQ(v8_num(637), info.Data());
1606  echo_indexed_call_count++;
1607  return v8_num(index);
1608}
1609
1610
1611THREADED_TEST(IndexedPropertyHandlerGetter) {
1612  v8::HandleScope scope;
1613  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
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
1625v8::Handle<v8::Object> bottom;
1626
1627static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1628    uint32_t index,
1629    const AccessorInfo& info) {
1630  ApiTestFuzzer::Fuzz();
1631  CHECK(info.This()->Equals(bottom));
1632  return v8::Handle<Value>();
1633}
1634
1635static v8::Handle<Value> CheckThisNamedPropertyHandler(
1636    Local<String> name,
1637    const AccessorInfo& info) {
1638  ApiTestFuzzer::Fuzz();
1639  CHECK(info.This()->Equals(bottom));
1640  return v8::Handle<Value>();
1641}
1642
1643
1644v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1645                                                 Local<Value> value,
1646                                                 const AccessorInfo& info) {
1647  ApiTestFuzzer::Fuzz();
1648  CHECK(info.This()->Equals(bottom));
1649  return v8::Handle<Value>();
1650}
1651
1652
1653v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1654                                               Local<Value> value,
1655                                               const AccessorInfo& info) {
1656  ApiTestFuzzer::Fuzz();
1657  CHECK(info.This()->Equals(bottom));
1658  return v8::Handle<Value>();
1659}
1660
1661v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1662    uint32_t index,
1663    const AccessorInfo& info) {
1664  ApiTestFuzzer::Fuzz();
1665  CHECK(info.This()->Equals(bottom));
1666  return v8::Handle<v8::Integer>();
1667}
1668
1669
1670v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1671                                                    const AccessorInfo& info) {
1672  ApiTestFuzzer::Fuzz();
1673  CHECK(info.This()->Equals(bottom));
1674  return v8::Handle<v8::Integer>();
1675}
1676
1677
1678v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1679    uint32_t index,
1680    const AccessorInfo& info) {
1681  ApiTestFuzzer::Fuzz();
1682  CHECK(info.This()->Equals(bottom));
1683  return v8::Handle<v8::Boolean>();
1684}
1685
1686
1687v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1688    Local<String> property,
1689    const AccessorInfo& info) {
1690  ApiTestFuzzer::Fuzz();
1691  CHECK(info.This()->Equals(bottom));
1692  return v8::Handle<v8::Boolean>();
1693}
1694
1695
1696v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1697    const AccessorInfo& info) {
1698  ApiTestFuzzer::Fuzz();
1699  CHECK(info.This()->Equals(bottom));
1700  return v8::Handle<v8::Array>();
1701}
1702
1703
1704v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1705    const AccessorInfo& info) {
1706  ApiTestFuzzer::Fuzz();
1707  CHECK(info.This()->Equals(bottom));
1708  return v8::Handle<v8::Array>();
1709}
1710
1711
1712THREADED_TEST(PropertyHandlerInPrototype) {
1713  v8::HandleScope scope;
1714  LocalContext env;
1715
1716  // Set up a prototype chain with three interceptors.
1717  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1718  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1719      CheckThisIndexedPropertyHandler,
1720      CheckThisIndexedPropertySetter,
1721      CheckThisIndexedPropertyQuery,
1722      CheckThisIndexedPropertyDeleter,
1723      CheckThisIndexedPropertyEnumerator);
1724
1725  templ->InstanceTemplate()->SetNamedPropertyHandler(
1726      CheckThisNamedPropertyHandler,
1727      CheckThisNamedPropertySetter,
1728      CheckThisNamedPropertyQuery,
1729      CheckThisNamedPropertyDeleter,
1730      CheckThisNamedPropertyEnumerator);
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
1761static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1762                                               const AccessorInfo& info) {
1763  ApiTestFuzzer::Fuzz();
1764  if (v8_str("pre")->Equals(key)) {
1765    return v8_str("PrePropertyHandler: pre");
1766  }
1767  return v8::Handle<String>();
1768}
1769
1770
1771static 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
1781THREADED_TEST(PrePropertyHandler) {
1782  v8::HandleScope scope;
1783  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
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
1799THREADED_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
1808v8::Handle<Script> call_recursively_script;
1809static const int kTargetRecursionDepth = 200;  // near maximum
1810
1811
1812static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1813  ApiTestFuzzer::Fuzz();
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
1821static v8::Handle<Value> CallFunctionRecursivelyCall(
1822    const v8::Arguments& args) {
1823  ApiTestFuzzer::Fuzz();
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
1836THREADED_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
1855static v8::Handle<Value>
1856    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1857  ApiTestFuzzer::Fuzz();
1858  return v8::ThrowException(key);
1859}
1860
1861
1862static 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
1870THREADED_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
1886THREADED_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
1897THREADED_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
1912THREADED_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
1926THREADED_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
1958THREADED_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
1996THREADED_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
2040THREADED_TEST(HiddenProperties) {
2041  v8::HandleScope scope;
2042  LocalContext env;
2043
2044  v8::Local<v8::Object> obj = v8::Object::New();
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
2088THREADED_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
2095  v8::Local<v8::Object> obj = v8::Object::New();
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
2116static bool interceptor_for_hidden_properties_called;
2117static 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
2124THREADED_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
2144THREADED_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
2176THREADED_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
2188class WeakCallCounter {
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
2200static 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
2208THREADED_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
2293THREADED_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
2375THREADED_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
2388bool message_received;
2389
2390
2391static 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
2400THREADED_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
2418THREADED_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
2445THREADED_TEST(PropertyAttributes) {
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
2489THREADED_TEST(Array) {
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
2517v8::Handle<Value> HandleF(const v8::Arguments& args) {
2518  v8::HandleScope scope;
2519  ApiTestFuzzer::Fuzz();
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
2527THREADED_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
2565THREADED_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
2617static 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.
2623TEST(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;
2636  v8::V8::IgnoreOutOfMemoryException();
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
2647v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2648  ApiTestFuzzer::Fuzz();
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
2664TEST(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"),
2677             v8::FunctionTemplate::New(ProvokeOutOfMemory));
2678  LocalContext context(0, templ);
2679  v8::V8::IgnoreOutOfMemoryException();
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
2693TEST(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.
2704  v8::V8::IgnoreOutOfMemoryException();
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
2720THREADED_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
2772static 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
2780THREADED_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
2828THREADED_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
2879THREADED_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
2933v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2934  ApiTestFuzzer::Fuzz();
2935  return v8::ThrowException(v8_str("konto"));
2936}
2937
2938
2939v8::Handle<Value> CCatcher(const v8::Arguments& args) {
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
2949THREADED_TEST(APICatch) {
2950  v8::HandleScope scope;
2951  Local<ObjectTemplate> templ = ObjectTemplate::New();
2952  templ->Set(v8_str("ThrowFromC"),
2953             v8::FunctionTemplate::New(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
2967THREADED_TEST(APIThrowTryCatch) {
2968  v8::HandleScope scope;
2969  Local<ObjectTemplate> templ = ObjectTemplate::New();
2970  templ->Set(v8_str("ThrowFromC"),
2971             v8::FunctionTemplate::New(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.
2986TEST(TryCatchInTryFinally) {
2987  v8::HandleScope scope;
2988  Local<ObjectTemplate> templ = ObjectTemplate::New();
2989  templ->Set(v8_str("CCatcher"),
2990             v8::FunctionTemplate::New(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
3003static 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
3011static v8::Handle<Value> Fail(const v8::Arguments& args) {
3012  ApiTestFuzzer::Fuzz();
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.
3021TEST(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
3059static void receive_message(v8::Handle<v8::Message> message,
3060                            v8::Handle<v8::Value> data) {
3061  message->Get();
3062  message_received = true;
3063}
3064
3065
3066TEST(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"),
3072             v8::FunctionTemplate::New(ThrowFromC));
3073  LocalContext context(0, templ);
3074  CompileRun("ThrowFromC();");
3075  CHECK(message_received);
3076  v8::V8::RemoveMessageListeners(check_message);
3077}
3078
3079
3080TEST(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"),
3086             v8::FunctionTemplate::New(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
3098TEST(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
3113THREADED_TEST(ExternalScriptException) {
3114  v8::HandleScope scope;
3115  Local<ObjectTemplate> templ = ObjectTemplate::New();
3116  templ->Set(v8_str("ThrowFromC"),
3117             v8::FunctionTemplate::New(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
3132v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3133  ApiTestFuzzer::Fuzz();
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
3165v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3166  ApiTestFuzzer::Fuzz();
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
3180THREADED_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.
3215TEST(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"),
3220             v8::FunctionTemplate::New(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
3272v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3273  ApiTestFuzzer::Fuzz();
3274  CHECK_EQ(1, args.Length());
3275  return v8::ThrowException(args[0]);
3276}
3277
3278
3279THREADED_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);
3284  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
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
3305THREADED_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
3321THREADED_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
3331THREADED_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
3342v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3343  v8::TryCatch try_catch;
3344  return v8::Undefined();
3345}
3346
3347
3348THREADED_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
3366THREADED_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
3391  v8::Handle<v8::Object> obj = v8::Object::New();
3392  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3393  CHECK(alias->StrictEquals(obj));
3394  alias.Dispose();
3395}
3396
3397
3398THREADED_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
3407static v8::Handle<Value> GetXValue(Local<String> name,
3408                                   const AccessorInfo& info) {
3409  ApiTestFuzzer::Fuzz();
3410  CHECK_EQ(info.Data(), v8_str("donut"));
3411  CHECK_EQ(name, v8_str("x"));
3412  return name;
3413}
3414
3415
3416THREADED_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
3429THREADED_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
3476THREADED_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
3522static 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
3528THREADED_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
3602THREADED_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
3649static v8::Handle<Value> Get239Value(Local<String> name,
3650                                     const AccessorInfo& info) {
3651  ApiTestFuzzer::Fuzz();
3652  CHECK_EQ(info.Data(), v8_str("donut"));
3653  CHECK_EQ(name, v8_str("239"));
3654  return name;
3655}
3656
3657
3658THREADED_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
3682v8::Persistent<Value> xValue;
3683
3684
3685static 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
3696THREADED_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
3713static v8::Handle<Value> XPropertyGetter(Local<String> property,
3714                                         const AccessorInfo& info) {
3715  ApiTestFuzzer::Fuzz();
3716  CHECK(info.Data()->IsUndefined());
3717  return property;
3718}
3719
3720
3721THREADED_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
3735THREADED_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
3765THREADED_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
3808static 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.
3819THREADED_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
3835static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3836                                               const AccessorInfo& info) {
3837  ApiTestFuzzer::Fuzz();
3838  if (index == 37) {
3839    return v8::Handle<Value>(v8_num(625));
3840  }
3841  return v8::Handle<Value>();
3842}
3843
3844
3845static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3846                                               Local<Value> value,
3847                                               const AccessorInfo& info) {
3848  ApiTestFuzzer::Fuzz();
3849  if (index == 39) {
3850    return value;
3851  }
3852  return v8::Handle<Value>();
3853}
3854
3855
3856THREADED_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
3886static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3887    uint32_t index,
3888    const AccessorInfo& info) {
3889  ApiTestFuzzer::Fuzz();
3890  if (index < 25) {
3891    return v8::Handle<Value>(v8_num(index));
3892  }
3893  return v8::Handle<Value>();
3894}
3895
3896
3897static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3898    uint32_t index,
3899    Local<Value> value,
3900    const AccessorInfo& info) {
3901  ApiTestFuzzer::Fuzz();
3902  if (index < 25) {
3903    return v8::Handle<Value>(v8_num(index));
3904  }
3905  return v8::Handle<Value>();
3906}
3907
3908
3909Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
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.
3923THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3924  v8::HandleScope scope;
3925  Local<ObjectTemplate> templ = ObjectTemplate::New();
3926  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3927                                   UnboxedDoubleIndexedPropertySetter,
3928                                   0,
3929                                   0,
3930                                   UnboxedDoubleIndexedPropertyEnumerator);
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
3948Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
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
3962static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3963    uint32_t index,
3964    const AccessorInfo& info) {
3965  ApiTestFuzzer::Fuzz();
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.
3975THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3976  v8::HandleScope scope;
3977  Local<ObjectTemplate> templ = ObjectTemplate::New();
3978  templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3979                                   0,
3980                                   0,
3981                                   0,
3982                                   NonStrictArgsIndexedPropertyEnumerator);
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
3994static v8::Handle<Value> IdentityIndexedPropertyGetter(
3995    uint32_t index,
3996    const AccessorInfo& info) {
3997  return v8::Integer::NewFromUnsigned(index);
3998}
3999
4000
4001THREADED_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
4022THREADED_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
4045THREADED_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
4069THREADED_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
4099THREADED_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
4122THREADED_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
4161THREADED_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
4190THREADED_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
4220THREADED_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
4250THREADED_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
4274THREADED_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
4307THREADED_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
4337THREADED_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
4360THREADED_TEST(UndetectableObject) {
4361  v8::HandleScope scope;
4362  LocalContext env;
4363
4364  Local<v8::FunctionTemplate> desc =
4365      v8::FunctionTemplate::New(0, v8::Handle<Value>());
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
4404THREADED_TEST(VoidLiteral) {
4405  v8::HandleScope scope;
4406  LocalContext env;
4407
4408  Local<v8::FunctionTemplate> desc =
4409      v8::FunctionTemplate::New(0, v8::Handle<Value>());
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
4448THREADED_TEST(ExtensibleOnUndetectable) {
4449  v8::HandleScope scope;
4450  LocalContext env;
4451
4452  Local<v8::FunctionTemplate> desc =
4453      v8::FunctionTemplate::New(0, v8::Handle<Value>());
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
4481THREADED_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
4521TEST(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
4553template <typename T> static void USE(T) { }
4554
4555
4556// This test is not intended to be run, just type checked.
4557static inline void PersistentHandles() {
4558  USE(PersistentHandles);
4559  Local<String> str = v8_str("foo");
4560  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4561  USE(p_str);
4562  Local<Script> scr = Script::Compile(v8_str(""));
4563  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4564  USE(p_scr);
4565  Local<ObjectTemplate> templ = ObjectTemplate::New();
4566  v8::Persistent<ObjectTemplate> p_templ =
4567    v8::Persistent<ObjectTemplate>::New(templ);
4568  USE(p_templ);
4569}
4570
4571
4572static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4573  ApiTestFuzzer::Fuzz();
4574  return v8::Undefined();
4575}
4576
4577
4578THREADED_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
4590static const char* kSimpleExtensionSource =
4591  "function Foo() {"
4592  "  return 4;"
4593  "}";
4594
4595
4596THREADED_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
4608static const char* kEmbeddedExtensionSource =
4609    "function Ret54321(){return 54321;}~~@@$"
4610    "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4611static const int kEmbeddedExtensionSourceValidLen = 34;
4612
4613
4614THREADED_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
4625THREADED_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
4649static const char* kEvalExtensionSource1 =
4650  "function UseEval1() {"
4651  "  var x = 42;"
4652  "  return eval('x');"
4653  "}";
4654
4655
4656static const char* kEvalExtensionSource2 =
4657  "(function() {"
4658  "  var x = 42;"
4659  "  function e() {"
4660  "    return eval('x');"
4661  "  }"
4662  "  this.UseEval2 = e;"
4663  "})()";
4664
4665
4666THREADED_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
4681static const char* kWithExtensionSource1 =
4682  "function UseWith1() {"
4683  "  var x = 42;"
4684  "  with({x:87}) { return x; }"
4685  "}";
4686
4687
4688
4689static 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
4699THREADED_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
4714THREADED_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
4726static 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.
4732THREADED_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
4743static 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.
4749THREADED_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
4760static const char* kNativeCallInExtensionSource =
4761    "function call_runtime_last_index_of(x) {"
4762    "  return %StringLastIndexOf(x, 'bob', 10);"
4763    "}";
4764
4765
4766static const char* kNativeCallTest =
4767    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4768
4769// Test that a native runtime calls are supported in extensions.
4770THREADED_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
4783class NativeFunctionExtension : public Extension {
4784 public:
4785  NativeFunctionExtension(const char* name,
4786                          const char* source,
4787                          v8::InvocationCallback fun = &Echo)
4788      : Extension(name, source),
4789        function_(fun) { }
4790
4791  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4792      v8::Handle<v8::String> name) {
4793    return v8::FunctionTemplate::New(function_);
4794  }
4795
4796  static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4797    if (args.Length() >= 1) return (args[0]);
4798    return v8::Undefined();
4799  }
4800 private:
4801  v8::InvocationCallback function_;
4802};
4803
4804
4805THREADED_TEST(NativeFunctionDeclaration) {
4806  v8::HandleScope handle_scope;
4807  const char* name = "nativedecl";
4808  v8::RegisterExtension(new NativeFunctionExtension(name,
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
4819THREADED_TEST(NativeFunctionDeclarationError) {
4820  v8::HandleScope handle_scope;
4821  const char* name = "nativedeclerr";
4822  // Syntax error in extension code.
4823  v8::RegisterExtension(new NativeFunctionExtension(name,
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
4832THREADED_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.
4837  v8::RegisterExtension(new NativeFunctionExtension(
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
4847static 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 */
4862THREADED_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
4884static 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
4895static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4896  ApiTestFuzzer::Fuzz();
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
4905class FunctionExtension : public Extension {
4906 public:
4907  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4908  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4909      v8::Handle<String> name);
4910};
4911
4912
4913static int lookup_count = 0;
4914v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
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 {
4924    return v8::Handle<v8::FunctionTemplate>();
4925  }
4926}
4927
4928
4929THREADED_TEST(FunctionLookup) {
4930  v8::RegisterExtension(new FunctionExtension());
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
4942THREADED_TEST(NativeFunctionConstructCall) {
4943  v8::RegisterExtension(new FunctionExtension());
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.
4951    CHECK_EQ(v8::Integer::New(8),
4952             Script::Compile(v8_str("(new A()).data"))->Run());
4953    CHECK_EQ(v8::Integer::New(7),
4954             Script::Compile(v8_str("(new B()).data"))->Run());
4955    CHECK_EQ(v8::Integer::New(6),
4956             Script::Compile(v8_str("(new C()).data"))->Run());
4957  }
4958}
4959
4960
4961static const char* last_location;
4962static const char* last_message;
4963void 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.
4974TEST(ErrorReporting) {
4975  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
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
4988static 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
4996void OOMCallback(const char* location, const char* message) {
4997  exit(0);
4998}
4999
5000
5001TEST(RegexpOutOfMemory) {
5002  // Execute a script that causes out of memory when flattening a string.
5003  v8::HandleScope scope;
5004  v8::V8::SetFatalErrorHandler(OOMCallback);
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
5015static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5016                                             v8::Handle<Value> data) {
5017  CHECK_EQ(v8::Undefined(), data);
5018  CHECK(message->GetScriptResourceName()->IsUndefined());
5019  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
5020  message->GetLineNumber();
5021  message->GetSourceLine();
5022}
5023
5024
5025THREADED_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
5034int global_index = 0;
5035
5036class Snorkel {
5037 public:
5038  Snorkel() { index_ = global_index++; }
5039  int index_;
5040};
5041
5042class Whammy {
5043 public:
5044  Whammy() {
5045    cursor_ = 0;
5046  }
5047  ~Whammy() {
5048    script_.Dispose();
5049  }
5050  v8::Handle<Script> getScript() {
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_;
5059  v8::Persistent<v8::Object> objects_[kObjectCount];
5060  v8::Persistent<Script> script_;
5061};
5062
5063static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5064  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5065  delete snorkel;
5066  obj.ClearWeak();
5067}
5068
5069v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
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
5076  v8::Handle<v8::Object> obj = v8::Object::New();
5077  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
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
5088THREADED_TEST(WeakReference) {
5089  v8::HandleScope handle_scope;
5090  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
5091  Whammy* whammy = new Whammy();
5092  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
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
5118static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5119  obj.Dispose();
5120  obj.Clear();
5121  *(reinterpret_cast<bool*>(data)) = true;
5122}
5123
5124
5125THREADED_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;
5133    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
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
5144static void InvokeScavenge() {
5145  HEAP->PerformScavenge();
5146}
5147
5148
5149static void InvokeMarkSweep() {
5150  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5151}
5152
5153
5154static 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
5162static 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
5170THREADED_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++) {
5183      v8::Persistent<v8::Object> object;
5184      {
5185        v8::HandleScope handle_scope;
5186        object = v8::Persistent<v8::Object>::New(v8::Object::New());
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
5198static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5199  obj.ClearWeak();
5200  *(reinterpret_cast<bool*>(data)) = true;
5201}
5202
5203
5204THREADED_TEST(IndependentHandleRevival) {
5205  v8::Persistent<Context> context = Context::New();
5206  Context::Scope context_scope(context);
5207
5208  v8::Persistent<v8::Object> object;
5209  {
5210    v8::HandleScope handle_scope;
5211    object = v8::Persistent<v8::Object>::New(v8::Object::New());
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
5231v8::Handle<Function> args_fun;
5232
5233
5234static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5235  ApiTestFuzzer::Fuzz();
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
5248THREADED_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
5258static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5259                                        const AccessorInfo&) {
5260  return v8::Handle<Value>();
5261}
5262
5263
5264static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5265                                        const AccessorInfo&) {
5266  return v8::Handle<Value>();
5267}
5268
5269
5270static 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
5280static 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
5289THREADED_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
5315static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5316  ApiTestFuzzer::Fuzz();
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
5326static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5327  ApiTestFuzzer::Fuzz();
5328  if (index == 0 || index == 1) return v8::Undefined();
5329  return v8::Handle<Value>();
5330}
5331
5332
5333static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5334  ApiTestFuzzer::Fuzz();
5335  v8::Handle<v8::Array> result = v8::Array::New(3);
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
5343static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5344  ApiTestFuzzer::Fuzz();
5345  v8::Handle<v8::Array> result = v8::Array::New(2);
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
5352THREADED_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());
5359  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
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
5409int p_getter_count;
5410int p_getter_count2;
5411
5412
5413static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5414  ApiTestFuzzer::Fuzz();
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
5431static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5432  ApiTestFuzzer::Fuzz();
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
5447static v8::Handle<Value> PGetter2(Local<String> name,
5448                                  const AccessorInfo& info) {
5449  ApiTestFuzzer::Fuzz();
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
5466THREADED_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
5479THREADED_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
5489THREADED_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
5508static 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
5518static 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
5529int GetUtf8Length(Handle<String> str) {
5530  int len = str->Utf8Length();
5531  if (len < 0) {
5532    i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5533    i::FlattenString(istr);
5534    len = str->Utf8Length();
5535  }
5536  return len;
5537}
5538
5539
5540THREADED_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
5759static 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
5781static 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
5788static 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
5859THREADED_TEST(Utf16) {
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
5911static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
5912  i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
5913  i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
5914  return *is1 == *is2;
5915}
5916
5917
5918static 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
5925THREADED_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
5978THREADED_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());
5996  v8::Handle<v8::Number> num = v8::Number::New(1);
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());
6003  v8::Handle<v8::Object> obj = v8::Object::New();
6004  index = obj->ToArrayIndex();
6005  CHECK(index.IsEmpty());
6006}
6007
6008
6009THREADED_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));
6027  v8::Handle<Value> error = v8::Exception::Error(foo);
6028  CHECK(error->IsObject());
6029  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
6030}
6031
6032
6033static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6034  ApiTestFuzzer::Fuzz();
6035  return v8_num(10);
6036}
6037
6038
6039static 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
6049THREADED_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
6062THREADED_TEST(TypeSwitch) {
6063  v8::HandleScope scope;
6064  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6065  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6066  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
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;
6070  v8::Handle<v8::Object> obj0 = v8::Object::New();
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.
6088static bool g_security_callback_result = false;
6089static bool NamedSecurityTestCallback(Local<v8::Object> global,
6090                                      Local<Value> name,
6091                                      v8::AccessType type,
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
6102static 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
6115static int trouble_nesting = 0;
6116static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6117  ApiTestFuzzer::Fuzz();
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
6130static int report_count = 0;
6131static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6132                                             v8::Handle<Value>) {
6133  report_count++;
6134}
6135
6136
6137// Counts uncaught exceptions, but other tests running in parallel
6138// also have uncaught exceptions.
6139TEST(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
6167static const char* script_resource_name = "ExceptionInNativeScript.js";
6168static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6169                                                v8::Handle<Value>) {
6170  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6171  CHECK(!name_val.IsEmpty() && name_val->IsString());
6172  v8::String::AsciiValue name(message->GetScriptResourceName());
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
6179TEST(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
6199TEST(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
6209TEST(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
6230TEST(SecurityHandler) {
6231  v8::HandleScope scope0;
6232  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
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
6292THREADED_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.
6337THREADED_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
6405THREADED_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
6438THREADED_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
6473THREADED_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
6506TEST(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
6536  v8::Persistent<Context> env3 =
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
6570TEST(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.
6607  v8::Persistent<Context> 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
6649static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6650static 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
6659static 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
6668static int g_echo_value = -1;
6669static v8::Handle<Value> EchoGetter(Local<String> name,
6670                                    const AccessorInfo& info) {
6671  return v8_num(g_echo_value);
6672}
6673
6674
6675static 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
6683static 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
6690static void UnreachableSetter(Local<String>, Local<Value>,
6691                              const AccessorInfo&) {
6692  CHECK(false);  // This function should nto be called.
6693}
6694
6695
6696TEST(AccessControl) {
6697  v8::HandleScope handle_scope;
6698  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
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,
6707      v8::Handle<Value>(),
6708      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
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,
6713                               v8::Handle<Value>(),
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
6940TEST(AccessControlES5) {
6941  v8::HandleScope handle_scope;
6942  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
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,
6951      v8::Handle<Value>(),
6952      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
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,
6958                               v8::Handle<Value>(),
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
7010static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7011                                            Local<Value> name,
7012                                            v8::AccessType type,
7013                                            Local<Value> data) {
7014  return false;
7015}
7016
7017
7018static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7019                                              uint32_t key,
7020                                              v8::AccessType type,
7021                                              Local<Value> data) {
7022  return false;
7023}
7024
7025
7026THREADED_TEST(AccessControlGetOwnPropertyNames) {
7027  v8::HandleScope handle_scope;
7028  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
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
7069static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7070  v8::Handle<v8::Array> result = v8::Array::New(1);
7071  result->Set(0, v8_str("x"));
7072  return result;
7073}
7074
7075
7076THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7077  v8::HandleScope handle_scope;
7078  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
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
7094static v8::Handle<Value> ConstTenGetter(Local<String> name,
7095                                        const AccessorInfo& info) {
7096  return v8_num(10);
7097}
7098
7099
7100THREADED_TEST(CrossDomainAccessors) {
7101  v8::HandleScope handle_scope;
7102
7103  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
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,
7114                              v8::Handle<Value>(),
7115                              v8::ALL_CAN_READ);
7116
7117  // Add an accessor that is not accessible by cross-domain JS code.
7118  global_template->SetAccessor(v8_str("unreachable"),
7119                               UnreachableGetter, 0,
7120                               v8::Handle<Value>(),
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
7153static int named_access_count = 0;
7154static int indexed_access_count = 0;
7155
7156static 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
7165static 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.
7175TEST(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.
7187  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
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
7288static 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
7311static 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.
7324THREADED_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.
7336  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
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
7363static v8::Handle<Value> AccessControlNamedGetter(
7364    Local<String>, const AccessorInfo&) {
7365  return v8::Integer::New(42);
7366}
7367
7368
7369static v8::Handle<Value> AccessControlNamedSetter(
7370    Local<String>, Local<Value> value, const AccessorInfo&) {
7371  return value;
7372}
7373
7374
7375static v8::Handle<Value> AccessControlIndexedGetter(
7376      uint32_t index,
7377      const AccessorInfo& info) {
7378  return v8_num(42);
7379}
7380
7381
7382static v8::Handle<Value> AccessControlIndexedSetter(
7383    uint32_t, Local<Value> value, const AccessorInfo&) {
7384  return value;
7385}
7386
7387
7388THREADED_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.
7401  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
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
7455THREADED_TEST(Version) {
7456  v8::V8::GetVersion();
7457}
7458
7459
7460static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7461  ApiTestFuzzer::Fuzz();
7462  return v8_num(12);
7463}
7464
7465
7466THREADED_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
7488static v8::Handle<Value>
7489GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7490  ApiTestFuzzer::Fuzz();
7491  return v8::Handle<Value>();
7492}
7493
7494
7495THREADED_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
7551THREADED_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
7591static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7592  ApiTestFuzzer::Fuzz();
7593  return v8_num(42);
7594}
7595
7596
7597static int shadow_y;
7598static int shadow_y_setter_call_count;
7599static int shadow_y_getter_call_count;
7600
7601
7602static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7603  shadow_y_setter_call_count++;
7604  shadow_y = 42;
7605}
7606
7607
7608static v8::Handle<Value> ShadowYGetter(Local<String> name,
7609                                       const AccessorInfo& info) {
7610  ApiTestFuzzer::Fuzz();
7611  shadow_y_getter_call_count++;
7612  return v8_num(shadow_y);
7613}
7614
7615
7616static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7617                                          const AccessorInfo& info) {
7618  return v8::Handle<Value>();
7619}
7620
7621
7622static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7623                                        const AccessorInfo&) {
7624  return v8::Handle<Value>();
7625}
7626
7627
7628THREADED_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 = 42"))->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
7673THREADED_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
7717THREADED_TEST(SetPrototype) {
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.
7777THREADED_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
7828THREADED_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
7859THREADED_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
7880THREADED_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
7903THREADED_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();
7911  i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
7912  CHECK(obj->IsJSObject());
7913  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7914  CHECK(value->BooleanValue());
7915}
7916
7917
7918static Handle<Value> ConstructorCallback(const Arguments& args) {
7919  ApiTestFuzzer::Fuzz();
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
7938static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7939  ApiTestFuzzer::Fuzz();
7940  return args[0];
7941}
7942
7943
7944THREADED_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
8111THREADED_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
8136THREADED_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
8172THREADED_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.
8255THREADED_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
8290THREADED_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
8310static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8311  ApiTestFuzzer::Fuzz();
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.
8325THREADED_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.
8438THREADED_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
8480static int CountHandles() {
8481  return v8::HandleScope::NumberOfHandles();
8482}
8483
8484
8485static 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
8495THREADED_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
8522static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8523    Local<String> name,
8524    const AccessorInfo& info) {
8525  ApiTestFuzzer::Fuzz();
8526  return v8::Handle<Value>();
8527}
8528
8529
8530THREADED_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
8553static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8554    Local<String> name,
8555    const AccessorInfo& info) {
8556  ApiTestFuzzer::Fuzz();
8557  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8558  return v8::Handle<Value>();
8559}
8560
8561
8562THREADED_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
8591typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8592                                                 const AccessorInfo& info);
8593
8594
8595static 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
8608static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8609                                                 const AccessorInfo& info) {
8610  ApiTestFuzzer::Fuzz();
8611  CHECK_EQ(v8_str("data"), info.Data());
8612  CHECK_EQ(v8_str("x"), name);
8613  return v8::Integer::New(42);
8614}
8615
8616
8617// This test should hit the load IC for the interceptor case.
8618THREADED_TEST(InterceptorLoadIC) {
8619  CheckInterceptorLoadIC(InterceptorLoadICGetter,
8620    "var result = 0;"
8621    "for (var i = 0; i < 1000; i++) {"
8622    "  result = o.x;"
8623    "}",
8624    42);
8625}
8626
8627
8628// Below go several tests which verify that JITing for various
8629// configurations of interceptor and explicit fields works fine
8630// (those cases are special cased to get better performance).
8631
8632static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8633                                                 const AccessorInfo& info) {
8634  ApiTestFuzzer::Fuzz();
8635  return v8_str("x")->Equals(name)
8636      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8637}
8638
8639
8640THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8641  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8642    "var result = 0;"
8643    "o.y = 239;"
8644    "for (var i = 0; i < 1000; i++) {"
8645    "  result = o.y;"
8646    "}",
8647    239);
8648}
8649
8650
8651THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8652  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8653    "var result = 0;"
8654    "o.__proto__ = { 'y': 239 };"
8655    "for (var i = 0; i < 1000; i++) {"
8656    "  result = o.y + o.x;"
8657    "}",
8658    239 + 42);
8659}
8660
8661
8662THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8663  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8664    "var result = 0;"
8665    "o.__proto__.y = 239;"
8666    "for (var i = 0; i < 1000; i++) {"
8667    "  result = o.y + o.x;"
8668    "}",
8669    239 + 42);
8670}
8671
8672
8673THREADED_TEST(InterceptorLoadICUndefined) {
8674  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8675    "var result = 0;"
8676    "for (var i = 0; i < 1000; i++) {"
8677    "  result = (o.y == undefined) ? 239 : 42;"
8678    "}",
8679    239);
8680}
8681
8682
8683THREADED_TEST(InterceptorLoadICWithOverride) {
8684  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8685    "fst = new Object();  fst.__proto__ = o;"
8686    "snd = new Object();  snd.__proto__ = fst;"
8687    "var result1 = 0;"
8688    "for (var i = 0; i < 1000;  i++) {"
8689    "  result1 = snd.x;"
8690    "}"
8691    "fst.x = 239;"
8692    "var result = 0;"
8693    "for (var i = 0; i < 1000; i++) {"
8694    "  result = snd.x;"
8695    "}"
8696    "result + result1",
8697    239 + 42);
8698}
8699
8700
8701// Test the case when we stored field into
8702// a stub, but interceptor produced value on its own.
8703THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8704  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8705    "proto = new Object();"
8706    "o.__proto__ = proto;"
8707    "proto.x = 239;"
8708    "for (var i = 0; i < 1000; i++) {"
8709    "  o.x;"
8710    // Now it should be ICed and keep a reference to x defined on proto
8711    "}"
8712    "var result = 0;"
8713    "for (var i = 0; i < 1000; i++) {"
8714    "  result += o.x;"
8715    "}"
8716    "result;",
8717    42 * 1000);
8718}
8719
8720
8721// Test the case when we stored field into
8722// a stub, but it got invalidated later on.
8723THREADED_TEST(InterceptorLoadICInvalidatedField) {
8724  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8725    "proto1 = new Object();"
8726    "proto2 = new Object();"
8727    "o.__proto__ = proto1;"
8728    "proto1.__proto__ = proto2;"
8729    "proto2.y = 239;"
8730    "for (var i = 0; i < 1000; i++) {"
8731    "  o.y;"
8732    // Now it should be ICed and keep a reference to y defined on proto2
8733    "}"
8734    "proto1.y = 42;"
8735    "var result = 0;"
8736    "for (var i = 0; i < 1000; i++) {"
8737    "  result += o.y;"
8738    "}"
8739    "result;",
8740    42 * 1000);
8741}
8742
8743
8744static int interceptor_load_not_handled_calls = 0;
8745static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8746                                                   const AccessorInfo& info) {
8747  ++interceptor_load_not_handled_calls;
8748  return v8::Handle<v8::Value>();
8749}
8750
8751
8752// Test how post-interceptor lookups are done in the non-cacheable
8753// case: the interceptor should not be invoked during this lookup.
8754THREADED_TEST(InterceptorLoadICPostInterceptor) {
8755  interceptor_load_not_handled_calls = 0;
8756  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8757    "receiver = new Object();"
8758    "receiver.__proto__ = o;"
8759    "proto = new Object();"
8760    "/* Make proto a slow-case object. */"
8761    "for (var i = 0; i < 1000; i++) {"
8762    "  proto[\"xxxxxxxx\" + i] = [];"
8763    "}"
8764    "proto.x = 17;"
8765    "o.__proto__ = proto;"
8766    "var result = 0;"
8767    "for (var i = 0; i < 1000; i++) {"
8768    "  result += receiver.x;"
8769    "}"
8770    "result;",
8771    17 * 1000);
8772  CHECK_EQ(1000, interceptor_load_not_handled_calls);
8773}
8774
8775
8776// Test the case when we stored field into
8777// a stub, but it got invalidated later on due to override on
8778// global object which is between interceptor and fields' holders.
8779THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8780  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8781    "o.__proto__ = this;"  // set a global to be a proto of o.
8782    "this.__proto__.y = 239;"
8783    "for (var i = 0; i < 10; i++) {"
8784    "  if (o.y != 239) throw 'oops: ' + o.y;"
8785    // Now it should be ICed and keep a reference to y defined on field_holder.
8786    "}"
8787    "this.y = 42;"  // Assign on a global.
8788    "var result = 0;"
8789    "for (var i = 0; i < 10; i++) {"
8790    "  result += o.y;"
8791    "}"
8792    "result;",
8793    42 * 10);
8794}
8795
8796
8797static void SetOnThis(Local<String> name,
8798                      Local<Value> value,
8799                      const AccessorInfo& info) {
8800  info.This()->ForceSet(name, value);
8801}
8802
8803
8804THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8805  v8::HandleScope scope;
8806  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8807  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8808  templ->SetAccessor(v8_str("y"), Return239);
8809  LocalContext context;
8810  context->Global()->Set(v8_str("o"), templ->NewInstance());
8811
8812  // Check the case when receiver and interceptor's holder
8813  // are the same objects.
8814  v8::Handle<Value> value = CompileRun(
8815      "var result = 0;"
8816      "for (var i = 0; i < 7; i++) {"
8817      "  result = o.y;"
8818      "}");
8819  CHECK_EQ(239, value->Int32Value());
8820
8821  // Check the case when interceptor's holder is in proto chain
8822  // of receiver.
8823  value = CompileRun(
8824      "r = { __proto__: o };"
8825      "var result = 0;"
8826      "for (var i = 0; i < 7; i++) {"
8827      "  result = r.y;"
8828      "}");
8829  CHECK_EQ(239, value->Int32Value());
8830}
8831
8832
8833THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8834  v8::HandleScope scope;
8835  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8836  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8837  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8838  templ_p->SetAccessor(v8_str("y"), Return239);
8839
8840  LocalContext context;
8841  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8842  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8843
8844  // Check the case when receiver and interceptor's holder
8845  // are the same objects.
8846  v8::Handle<Value> value = CompileRun(
8847      "o.__proto__ = p;"
8848      "var result = 0;"
8849      "for (var i = 0; i < 7; i++) {"
8850      "  result = o.x + o.y;"
8851      "}");
8852  CHECK_EQ(239 + 42, value->Int32Value());
8853
8854  // Check the case when interceptor's holder is in proto chain
8855  // of receiver.
8856  value = CompileRun(
8857      "r = { __proto__: o };"
8858      "var result = 0;"
8859      "for (var i = 0; i < 7; i++) {"
8860      "  result = r.x + r.y;"
8861      "}");
8862  CHECK_EQ(239 + 42, value->Int32Value());
8863}
8864
8865
8866THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8867  v8::HandleScope scope;
8868  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8869  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8870  templ->SetAccessor(v8_str("y"), Return239);
8871
8872  LocalContext context;
8873  context->Global()->Set(v8_str("o"), templ->NewInstance());
8874
8875  v8::Handle<Value> value = CompileRun(
8876    "fst = new Object();  fst.__proto__ = o;"
8877    "snd = new Object();  snd.__proto__ = fst;"
8878    "var result1 = 0;"
8879    "for (var i = 0; i < 7;  i++) {"
8880    "  result1 = snd.x;"
8881    "}"
8882    "fst.x = 239;"
8883    "var result = 0;"
8884    "for (var i = 0; i < 7; i++) {"
8885    "  result = snd.x;"
8886    "}"
8887    "result + result1");
8888  CHECK_EQ(239 + 42, value->Int32Value());
8889}
8890
8891
8892// Test the case when we stored callback into
8893// a stub, but interceptor produced value on its own.
8894THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8895  v8::HandleScope scope;
8896  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8897  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8898  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8899  templ_p->SetAccessor(v8_str("y"), Return239);
8900
8901  LocalContext context;
8902  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8903  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8904
8905  v8::Handle<Value> value = CompileRun(
8906    "o.__proto__ = p;"
8907    "for (var i = 0; i < 7; i++) {"
8908    "  o.x;"
8909    // Now it should be ICed and keep a reference to x defined on p
8910    "}"
8911    "var result = 0;"
8912    "for (var i = 0; i < 7; i++) {"
8913    "  result += o.x;"
8914    "}"
8915    "result");
8916  CHECK_EQ(42 * 7, value->Int32Value());
8917}
8918
8919
8920// Test the case when we stored callback into
8921// a stub, but it got invalidated later on.
8922THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8923  v8::HandleScope scope;
8924  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8925  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8926  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8927  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8928
8929  LocalContext context;
8930  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8931  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8932
8933  v8::Handle<Value> value = CompileRun(
8934    "inbetween = new Object();"
8935    "o.__proto__ = inbetween;"
8936    "inbetween.__proto__ = p;"
8937    "for (var i = 0; i < 10; i++) {"
8938    "  o.y;"
8939    // Now it should be ICed and keep a reference to y defined on p
8940    "}"
8941    "inbetween.y = 42;"
8942    "var result = 0;"
8943    "for (var i = 0; i < 10; i++) {"
8944    "  result += o.y;"
8945    "}"
8946    "result");
8947  CHECK_EQ(42 * 10, value->Int32Value());
8948}
8949
8950
8951// Test the case when we stored callback into
8952// a stub, but it got invalidated later on due to override on
8953// global object which is between interceptor and callbacks' holders.
8954THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8955  v8::HandleScope scope;
8956  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8957  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8958  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8959  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8960
8961  LocalContext context;
8962  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8963  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8964
8965  v8::Handle<Value> value = CompileRun(
8966    "o.__proto__ = this;"
8967    "this.__proto__ = p;"
8968    "for (var i = 0; i < 10; i++) {"
8969    "  if (o.y != 239) throw 'oops: ' + o.y;"
8970    // Now it should be ICed and keep a reference to y defined on p
8971    "}"
8972    "this.y = 42;"
8973    "var result = 0;"
8974    "for (var i = 0; i < 10; i++) {"
8975    "  result += o.y;"
8976    "}"
8977    "result");
8978  CHECK_EQ(42 * 10, value->Int32Value());
8979}
8980
8981
8982static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8983                                                  const AccessorInfo& info) {
8984  ApiTestFuzzer::Fuzz();
8985  CHECK(v8_str("x")->Equals(name));
8986  return v8::Integer::New(0);
8987}
8988
8989
8990THREADED_TEST(InterceptorReturningZero) {
8991  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8992     "o.x == undefined ? 1 : 0",
8993     0);
8994}
8995
8996
8997static v8::Handle<Value> InterceptorStoreICSetter(
8998    Local<String> key, Local<Value> value, const AccessorInfo&) {
8999  CHECK(v8_str("x")->Equals(key));
9000  CHECK_EQ(42, value->Int32Value());
9001  return value;
9002}
9003
9004
9005// This test should hit the store IC for the interceptor case.
9006THREADED_TEST(InterceptorStoreIC) {
9007  v8::HandleScope scope;
9008  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9009  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
9010                                 InterceptorStoreICSetter,
9011                                 0, 0, 0, v8_str("data"));
9012  LocalContext context;
9013  context->Global()->Set(v8_str("o"), templ->NewInstance());
9014  CompileRun(
9015      "for (var i = 0; i < 1000; i++) {"
9016      "  o.x = 42;"
9017      "}");
9018}
9019
9020
9021THREADED_TEST(InterceptorStoreICWithNoSetter) {
9022  v8::HandleScope scope;
9023  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9024  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9025  LocalContext context;
9026  context->Global()->Set(v8_str("o"), templ->NewInstance());
9027  v8::Handle<Value> value = CompileRun(
9028    "for (var i = 0; i < 1000; i++) {"
9029    "  o.y = 239;"
9030    "}"
9031    "42 + o.y");
9032  CHECK_EQ(239 + 42, value->Int32Value());
9033}
9034
9035
9036
9037
9038v8::Handle<Value> call_ic_function;
9039v8::Handle<Value> call_ic_function2;
9040v8::Handle<Value> call_ic_function3;
9041
9042static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9043                                                 const AccessorInfo& info) {
9044  ApiTestFuzzer::Fuzz();
9045  CHECK(v8_str("x")->Equals(name));
9046  return call_ic_function;
9047}
9048
9049
9050// This test should hit the call IC for the interceptor case.
9051THREADED_TEST(InterceptorCallIC) {
9052  v8::HandleScope scope;
9053  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9054  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9055  LocalContext context;
9056  context->Global()->Set(v8_str("o"), templ->NewInstance());
9057  call_ic_function =
9058      v8_compile("function f(x) { return x + 1; }; f")->Run();
9059  v8::Handle<Value> value = CompileRun(
9060    "var result = 0;"
9061    "for (var i = 0; i < 1000; i++) {"
9062    "  result = o.x(41);"
9063    "}");
9064  CHECK_EQ(42, value->Int32Value());
9065}
9066
9067
9068// This test checks that if interceptor doesn't provide
9069// a value, we can fetch regular value.
9070THREADED_TEST(InterceptorCallICSeesOthers) {
9071  v8::HandleScope scope;
9072  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9073  templ->SetNamedPropertyHandler(NoBlockGetterX);
9074  LocalContext context;
9075  context->Global()->Set(v8_str("o"), templ->NewInstance());
9076  v8::Handle<Value> value = CompileRun(
9077    "o.x = function f(x) { return x + 1; };"
9078    "var result = 0;"
9079    "for (var i = 0; i < 7; i++) {"
9080    "  result = o.x(41);"
9081    "}");
9082  CHECK_EQ(42, value->Int32Value());
9083}
9084
9085
9086static v8::Handle<Value> call_ic_function4;
9087static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9088                                                  const AccessorInfo& info) {
9089  ApiTestFuzzer::Fuzz();
9090  CHECK(v8_str("x")->Equals(name));
9091  return call_ic_function4;
9092}
9093
9094
9095// This test checks that if interceptor provides a function,
9096// even if we cached shadowed variant, interceptor's function
9097// is invoked
9098THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9099  v8::HandleScope scope;
9100  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9101  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9102  LocalContext context;
9103  context->Global()->Set(v8_str("o"), templ->NewInstance());
9104  call_ic_function4 =
9105      v8_compile("function f(x) { return x - 1; }; f")->Run();
9106  v8::Handle<Value> value = CompileRun(
9107    "o.__proto__.x = function(x) { return x + 1; };"
9108    "var result = 0;"
9109    "for (var i = 0; i < 1000; i++) {"
9110    "  result = o.x(42);"
9111    "}");
9112  CHECK_EQ(41, value->Int32Value());
9113}
9114
9115
9116// Test the case when we stored cacheable lookup into
9117// a stub, but it got invalidated later on
9118THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9119  v8::HandleScope scope;
9120  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9121  templ->SetNamedPropertyHandler(NoBlockGetterX);
9122  LocalContext context;
9123  context->Global()->Set(v8_str("o"), templ->NewInstance());
9124  v8::Handle<Value> value = CompileRun(
9125    "proto1 = new Object();"
9126    "proto2 = new Object();"
9127    "o.__proto__ = proto1;"
9128    "proto1.__proto__ = proto2;"
9129    "proto2.y = function(x) { return x + 1; };"
9130    // Invoke it many times to compile a stub
9131    "for (var i = 0; i < 7; i++) {"
9132    "  o.y(42);"
9133    "}"
9134    "proto1.y = function(x) { return x - 1; };"
9135    "var result = 0;"
9136    "for (var i = 0; i < 7; i++) {"
9137    "  result += o.y(42);"
9138    "}");
9139  CHECK_EQ(41 * 7, value->Int32Value());
9140}
9141
9142
9143// This test checks that if interceptor doesn't provide a function,
9144// cached constant function is used
9145THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9146  v8::HandleScope scope;
9147  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9148  templ->SetNamedPropertyHandler(NoBlockGetterX);
9149  LocalContext context;
9150  context->Global()->Set(v8_str("o"), templ->NewInstance());
9151  v8::Handle<Value> value = CompileRun(
9152    "function inc(x) { return x + 1; };"
9153    "inc(1);"
9154    "o.x = inc;"
9155    "var result = 0;"
9156    "for (var i = 0; i < 1000; i++) {"
9157    "  result = o.x(42);"
9158    "}");
9159  CHECK_EQ(43, value->Int32Value());
9160}
9161
9162
9163static v8::Handle<Value> call_ic_function5;
9164static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9165                                                  const AccessorInfo& info) {
9166  ApiTestFuzzer::Fuzz();
9167  if (v8_str("x")->Equals(name))
9168    return call_ic_function5;
9169  else
9170    return Local<Value>();
9171}
9172
9173
9174// This test checks that if interceptor provides a function,
9175// even if we cached constant function, interceptor's function
9176// is invoked
9177THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9178  v8::HandleScope scope;
9179  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9180  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9181  LocalContext context;
9182  context->Global()->Set(v8_str("o"), templ->NewInstance());
9183  call_ic_function5 =
9184      v8_compile("function f(x) { return x - 1; }; f")->Run();
9185  v8::Handle<Value> value = CompileRun(
9186    "function inc(x) { return x + 1; };"
9187    "inc(1);"
9188    "o.x = inc;"
9189    "var result = 0;"
9190    "for (var i = 0; i < 1000; i++) {"
9191    "  result = o.x(42);"
9192    "}");
9193  CHECK_EQ(41, value->Int32Value());
9194}
9195
9196
9197static v8::Handle<Value> call_ic_function6;
9198static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9199                                                  const AccessorInfo& info) {
9200  ApiTestFuzzer::Fuzz();
9201  if (v8_str("x")->Equals(name))
9202    return call_ic_function6;
9203  else
9204    return Local<Value>();
9205}
9206
9207
9208// Same test as above, except the code is wrapped in a function
9209// to test the optimized compiler.
9210THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9211  i::FLAG_allow_natives_syntax = true;
9212  v8::HandleScope scope;
9213  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9214  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9215  LocalContext context;
9216  context->Global()->Set(v8_str("o"), templ->NewInstance());
9217  call_ic_function6 =
9218      v8_compile("function f(x) { return x - 1; }; f")->Run();
9219  v8::Handle<Value> value = CompileRun(
9220    "function inc(x) { return x + 1; };"
9221    "inc(1);"
9222    "o.x = inc;"
9223    "function test() {"
9224    "  var result = 0;"
9225    "  for (var i = 0; i < 1000; i++) {"
9226    "    result = o.x(42);"
9227    "  }"
9228    "  return result;"
9229    "};"
9230    "test();"
9231    "test();"
9232    "test();"
9233    "%OptimizeFunctionOnNextCall(test);"
9234    "test()");
9235  CHECK_EQ(41, value->Int32Value());
9236}
9237
9238
9239// Test the case when we stored constant function into
9240// a stub, but it got invalidated later on
9241THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9242  v8::HandleScope scope;
9243  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9244  templ->SetNamedPropertyHandler(NoBlockGetterX);
9245  LocalContext context;
9246  context->Global()->Set(v8_str("o"), templ->NewInstance());
9247  v8::Handle<Value> value = CompileRun(
9248    "function inc(x) { return x + 1; };"
9249    "inc(1);"
9250    "proto1 = new Object();"
9251    "proto2 = new Object();"
9252    "o.__proto__ = proto1;"
9253    "proto1.__proto__ = proto2;"
9254    "proto2.y = inc;"
9255    // Invoke it many times to compile a stub
9256    "for (var i = 0; i < 7; i++) {"
9257    "  o.y(42);"
9258    "}"
9259    "proto1.y = function(x) { return x - 1; };"
9260    "var result = 0;"
9261    "for (var i = 0; i < 7; i++) {"
9262    "  result += o.y(42);"
9263    "}");
9264  CHECK_EQ(41 * 7, value->Int32Value());
9265}
9266
9267
9268// Test the case when we stored constant function into
9269// a stub, but it got invalidated later on due to override on
9270// global object which is between interceptor and constant function' holders.
9271THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9272  v8::HandleScope scope;
9273  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9274  templ->SetNamedPropertyHandler(NoBlockGetterX);
9275  LocalContext context;
9276  context->Global()->Set(v8_str("o"), templ->NewInstance());
9277  v8::Handle<Value> value = CompileRun(
9278    "function inc(x) { return x + 1; };"
9279    "inc(1);"
9280    "o.__proto__ = this;"
9281    "this.__proto__.y = inc;"
9282    // Invoke it many times to compile a stub
9283    "for (var i = 0; i < 7; i++) {"
9284    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9285    "}"
9286    "this.y = function(x) { return x - 1; };"
9287    "var result = 0;"
9288    "for (var i = 0; i < 7; i++) {"
9289    "  result += o.y(42);"
9290    "}");
9291  CHECK_EQ(41 * 7, value->Int32Value());
9292}
9293
9294
9295// Test the case when actual function to call sits on global object.
9296THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9297  v8::HandleScope scope;
9298  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9299  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9300
9301  LocalContext context;
9302  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9303
9304  v8::Handle<Value> value = CompileRun(
9305    "try {"
9306    "  o.__proto__ = this;"
9307    "  for (var i = 0; i < 10; i++) {"
9308    "    var v = o.parseFloat('239');"
9309    "    if (v != 239) throw v;"
9310      // Now it should be ICed and keep a reference to parseFloat.
9311    "  }"
9312    "  var result = 0;"
9313    "  for (var i = 0; i < 10; i++) {"
9314    "    result += o.parseFloat('239');"
9315    "  }"
9316    "  result"
9317    "} catch(e) {"
9318    "  e"
9319    "};");
9320  CHECK_EQ(239 * 10, value->Int32Value());
9321}
9322
9323static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9324                                                  const AccessorInfo& info) {
9325  ApiTestFuzzer::Fuzz();
9326  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9327  ++(*call_count);
9328  if ((*call_count) % 20 == 0) {
9329    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
9330  }
9331  return v8::Handle<Value>();
9332}
9333
9334static v8::Handle<Value> FastApiCallback_TrivialSignature(
9335    const v8::Arguments& args) {
9336  ApiTestFuzzer::Fuzz();
9337  CHECK_EQ(args.This(), args.Holder());
9338  CHECK(args.Data()->Equals(v8_str("method_data")));
9339  return v8::Integer::New(args[0]->Int32Value() + 1);
9340}
9341
9342static v8::Handle<Value> FastApiCallback_SimpleSignature(
9343    const v8::Arguments& args) {
9344  ApiTestFuzzer::Fuzz();
9345  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9346  CHECK(args.Data()->Equals(v8_str("method_data")));
9347  // Note, we're using HasRealNamedProperty instead of Has to avoid
9348  // invoking the interceptor again.
9349  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9350  return v8::Integer::New(args[0]->Int32Value() + 1);
9351}
9352
9353// Helper to maximize the odds of object moving.
9354static void GenerateSomeGarbage() {
9355  CompileRun(
9356      "var garbage;"
9357      "for (var i = 0; i < 1000; i++) {"
9358      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9359      "}"
9360      "garbage = undefined;");
9361}
9362
9363
9364v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9365  static int count = 0;
9366  if (count++ % 3 == 0) {
9367    HEAP->  CollectAllGarbage(true);  // This should move the stub
9368    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
9369  }
9370  return v8::Handle<v8::Value>();
9371}
9372
9373
9374THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9375  v8::HandleScope scope;
9376  LocalContext context;
9377  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9378  nativeobject_templ->Set("callback",
9379                          v8::FunctionTemplate::New(DirectApiCallback));
9380  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9381  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9382  // call the api function multiple times to ensure direct call stub creation.
9383  CompileRun(
9384        "function f() {"
9385        "  for (var i = 1; i <= 30; i++) {"
9386        "    nativeobject.callback();"
9387        "  }"
9388        "}"
9389        "f();");
9390}
9391
9392
9393v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9394  return v8::ThrowException(v8_str("g"));
9395}
9396
9397
9398THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9399  v8::HandleScope scope;
9400  LocalContext context;
9401  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9402  nativeobject_templ->Set("callback",
9403                          v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9404  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9405  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9406  // call the api function multiple times to ensure direct call stub creation.
9407  v8::Handle<Value> result = CompileRun(
9408      "var result = '';"
9409      "function f() {"
9410      "  for (var i = 1; i <= 5; i++) {"
9411      "    try { nativeobject.callback(); } catch (e) { result += e; }"
9412      "  }"
9413      "}"
9414      "f(); result;");
9415  CHECK_EQ(v8_str("ggggg"), result);
9416}
9417
9418
9419v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9420                                           const v8::AccessorInfo& info) {
9421  if (++p_getter_count % 3 == 0) {
9422    HEAP->CollectAllGarbage(true);
9423    GenerateSomeGarbage();
9424  }
9425  return v8::Handle<v8::Value>();
9426}
9427
9428
9429THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9430  v8::HandleScope scope;
9431  LocalContext context;
9432  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9433  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9434  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9435  p_getter_count = 0;
9436  CompileRun(
9437      "function f() {"
9438      "  for (var i = 0; i < 30; i++) o1.p1;"
9439      "}"
9440      "f();");
9441  CHECK_EQ(30, p_getter_count);
9442}
9443
9444
9445v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9446    Local<String> name, const v8::AccessorInfo& info) {
9447  return v8::ThrowException(v8_str("g"));
9448}
9449
9450
9451THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9452  v8::HandleScope scope;
9453  LocalContext context;
9454  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9455  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9456  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9457  v8::Handle<Value> result = CompileRun(
9458      "var result = '';"
9459      "for (var i = 0; i < 5; i++) {"
9460      "    try { o1.p1; } catch (e) { result += e; }"
9461      "}"
9462      "result;");
9463  CHECK_EQ(v8_str("ggggg"), result);
9464}
9465
9466
9467THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9468  int interceptor_call_count = 0;
9469  v8::HandleScope scope;
9470  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9471  v8::Handle<v8::FunctionTemplate> method_templ =
9472      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9473                                v8_str("method_data"),
9474                                v8::Handle<v8::Signature>());
9475  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9476  proto_templ->Set(v8_str("method"), method_templ);
9477  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9478  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9479                                 NULL, NULL, NULL, NULL,
9480                                 v8::External::Wrap(&interceptor_call_count));
9481  LocalContext context;
9482  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9483  GenerateSomeGarbage();
9484  context->Global()->Set(v8_str("o"), fun->NewInstance());
9485  CompileRun(
9486      "var result = 0;"
9487      "for (var i = 0; i < 100; i++) {"
9488      "  result = o.method(41);"
9489      "}");
9490  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9491  CHECK_EQ(100, interceptor_call_count);
9492}
9493
9494THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9495  int interceptor_call_count = 0;
9496  v8::HandleScope scope;
9497  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9498  v8::Handle<v8::FunctionTemplate> method_templ =
9499      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9500                                v8_str("method_data"),
9501                                v8::Signature::New(fun_templ));
9502  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9503  proto_templ->Set(v8_str("method"), method_templ);
9504  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9505  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9506                                 NULL, NULL, NULL, NULL,
9507                                 v8::External::Wrap(&interceptor_call_count));
9508  LocalContext context;
9509  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9510  GenerateSomeGarbage();
9511  context->Global()->Set(v8_str("o"), fun->NewInstance());
9512  CompileRun(
9513      "o.foo = 17;"
9514      "var receiver = {};"
9515      "receiver.__proto__ = o;"
9516      "var result = 0;"
9517      "for (var i = 0; i < 100; i++) {"
9518      "  result = receiver.method(41);"
9519      "}");
9520  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9521  CHECK_EQ(100, interceptor_call_count);
9522}
9523
9524THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9525  int interceptor_call_count = 0;
9526  v8::HandleScope scope;
9527  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9528  v8::Handle<v8::FunctionTemplate> method_templ =
9529      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9530                                v8_str("method_data"),
9531                                v8::Signature::New(fun_templ));
9532  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9533  proto_templ->Set(v8_str("method"), method_templ);
9534  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9535  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9536                                 NULL, NULL, NULL, NULL,
9537                                 v8::External::Wrap(&interceptor_call_count));
9538  LocalContext context;
9539  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9540  GenerateSomeGarbage();
9541  context->Global()->Set(v8_str("o"), fun->NewInstance());
9542  CompileRun(
9543      "o.foo = 17;"
9544      "var receiver = {};"
9545      "receiver.__proto__ = o;"
9546      "var result = 0;"
9547      "var saved_result = 0;"
9548      "for (var i = 0; i < 100; i++) {"
9549      "  result = receiver.method(41);"
9550      "  if (i == 50) {"
9551      "    saved_result = result;"
9552      "    receiver = {method: function(x) { return x - 1 }};"
9553      "  }"
9554      "}");
9555  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9556  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9557  CHECK_GE(interceptor_call_count, 50);
9558}
9559
9560THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9561  int interceptor_call_count = 0;
9562  v8::HandleScope scope;
9563  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9564  v8::Handle<v8::FunctionTemplate> method_templ =
9565      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9566                                v8_str("method_data"),
9567                                v8::Signature::New(fun_templ));
9568  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9569  proto_templ->Set(v8_str("method"), method_templ);
9570  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9571  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9572                                 NULL, NULL, NULL, NULL,
9573                                 v8::External::Wrap(&interceptor_call_count));
9574  LocalContext context;
9575  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9576  GenerateSomeGarbage();
9577  context->Global()->Set(v8_str("o"), fun->NewInstance());
9578  CompileRun(
9579      "o.foo = 17;"
9580      "var receiver = {};"
9581      "receiver.__proto__ = o;"
9582      "var result = 0;"
9583      "var saved_result = 0;"
9584      "for (var i = 0; i < 100; i++) {"
9585      "  result = receiver.method(41);"
9586      "  if (i == 50) {"
9587      "    saved_result = result;"
9588      "    o.method = function(x) { return x - 1 };"
9589      "  }"
9590      "}");
9591  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9592  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9593  CHECK_GE(interceptor_call_count, 50);
9594}
9595
9596THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9597  int interceptor_call_count = 0;
9598  v8::HandleScope scope;
9599  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9600  v8::Handle<v8::FunctionTemplate> method_templ =
9601      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9602                                v8_str("method_data"),
9603                                v8::Signature::New(fun_templ));
9604  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9605  proto_templ->Set(v8_str("method"), method_templ);
9606  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9607  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9608                                 NULL, NULL, NULL, NULL,
9609                                 v8::External::Wrap(&interceptor_call_count));
9610  LocalContext context;
9611  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9612  GenerateSomeGarbage();
9613  context->Global()->Set(v8_str("o"), fun->NewInstance());
9614  v8::TryCatch try_catch;
9615  CompileRun(
9616      "o.foo = 17;"
9617      "var receiver = {};"
9618      "receiver.__proto__ = o;"
9619      "var result = 0;"
9620      "var saved_result = 0;"
9621      "for (var i = 0; i < 100; i++) {"
9622      "  result = receiver.method(41);"
9623      "  if (i == 50) {"
9624      "    saved_result = result;"
9625      "    receiver = 333;"
9626      "  }"
9627      "}");
9628  CHECK(try_catch.HasCaught());
9629  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9630           try_catch.Exception()->ToString());
9631  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9632  CHECK_GE(interceptor_call_count, 50);
9633}
9634
9635THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9636  int interceptor_call_count = 0;
9637  v8::HandleScope scope;
9638  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9639  v8::Handle<v8::FunctionTemplate> method_templ =
9640      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9641                                v8_str("method_data"),
9642                                v8::Signature::New(fun_templ));
9643  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9644  proto_templ->Set(v8_str("method"), method_templ);
9645  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9646  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9647                                 NULL, NULL, NULL, NULL,
9648                                 v8::External::Wrap(&interceptor_call_count));
9649  LocalContext context;
9650  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9651  GenerateSomeGarbage();
9652  context->Global()->Set(v8_str("o"), fun->NewInstance());
9653  v8::TryCatch try_catch;
9654  CompileRun(
9655      "o.foo = 17;"
9656      "var receiver = {};"
9657      "receiver.__proto__ = o;"
9658      "var result = 0;"
9659      "var saved_result = 0;"
9660      "for (var i = 0; i < 100; i++) {"
9661      "  result = receiver.method(41);"
9662      "  if (i == 50) {"
9663      "    saved_result = result;"
9664      "    receiver = {method: receiver.method};"
9665      "  }"
9666      "}");
9667  CHECK(try_catch.HasCaught());
9668  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9669           try_catch.Exception()->ToString());
9670  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9671  CHECK_GE(interceptor_call_count, 50);
9672}
9673
9674THREADED_TEST(CallICFastApi_TrivialSignature) {
9675  v8::HandleScope scope;
9676  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9677  v8::Handle<v8::FunctionTemplate> method_templ =
9678      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9679                                v8_str("method_data"),
9680                                v8::Handle<v8::Signature>());
9681  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9682  proto_templ->Set(v8_str("method"), method_templ);
9683  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9684  USE(templ);
9685  LocalContext context;
9686  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9687  GenerateSomeGarbage();
9688  context->Global()->Set(v8_str("o"), fun->NewInstance());
9689  CompileRun(
9690      "var result = 0;"
9691      "for (var i = 0; i < 100; i++) {"
9692      "  result = o.method(41);"
9693      "}");
9694
9695  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9696}
9697
9698THREADED_TEST(CallICFastApi_SimpleSignature) {
9699  v8::HandleScope scope;
9700  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9701  v8::Handle<v8::FunctionTemplate> method_templ =
9702      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9703                                v8_str("method_data"),
9704                                v8::Signature::New(fun_templ));
9705  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9706  proto_templ->Set(v8_str("method"), method_templ);
9707  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9708  CHECK(!templ.IsEmpty());
9709  LocalContext context;
9710  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9711  GenerateSomeGarbage();
9712  context->Global()->Set(v8_str("o"), fun->NewInstance());
9713  CompileRun(
9714      "o.foo = 17;"
9715      "var receiver = {};"
9716      "receiver.__proto__ = o;"
9717      "var result = 0;"
9718      "for (var i = 0; i < 100; i++) {"
9719      "  result = receiver.method(41);"
9720      "}");
9721
9722  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9723}
9724
9725THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9726  v8::HandleScope scope;
9727  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9728  v8::Handle<v8::FunctionTemplate> method_templ =
9729      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9730                                v8_str("method_data"),
9731                                v8::Signature::New(fun_templ));
9732  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9733  proto_templ->Set(v8_str("method"), method_templ);
9734  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9735  CHECK(!templ.IsEmpty());
9736  LocalContext context;
9737  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9738  GenerateSomeGarbage();
9739  context->Global()->Set(v8_str("o"), fun->NewInstance());
9740  CompileRun(
9741      "o.foo = 17;"
9742      "var receiver = {};"
9743      "receiver.__proto__ = o;"
9744      "var result = 0;"
9745      "var saved_result = 0;"
9746      "for (var i = 0; i < 100; i++) {"
9747      "  result = receiver.method(41);"
9748      "  if (i == 50) {"
9749      "    saved_result = result;"
9750      "    receiver = {method: function(x) { return x - 1 }};"
9751      "  }"
9752      "}");
9753  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9754  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9755}
9756
9757THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9758  v8::HandleScope scope;
9759  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9760  v8::Handle<v8::FunctionTemplate> method_templ =
9761      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9762                                v8_str("method_data"),
9763                                v8::Signature::New(fun_templ));
9764  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9765  proto_templ->Set(v8_str("method"), method_templ);
9766  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9767  CHECK(!templ.IsEmpty());
9768  LocalContext context;
9769  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9770  GenerateSomeGarbage();
9771  context->Global()->Set(v8_str("o"), fun->NewInstance());
9772  v8::TryCatch try_catch;
9773  CompileRun(
9774      "o.foo = 17;"
9775      "var receiver = {};"
9776      "receiver.__proto__ = o;"
9777      "var result = 0;"
9778      "var saved_result = 0;"
9779      "for (var i = 0; i < 100; i++) {"
9780      "  result = receiver.method(41);"
9781      "  if (i == 50) {"
9782      "    saved_result = result;"
9783      "    receiver = 333;"
9784      "  }"
9785      "}");
9786  CHECK(try_catch.HasCaught());
9787  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9788           try_catch.Exception()->ToString());
9789  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9790}
9791
9792
9793v8::Handle<Value> keyed_call_ic_function;
9794
9795static v8::Handle<Value> InterceptorKeyedCallICGetter(
9796    Local<String> name, const AccessorInfo& info) {
9797  ApiTestFuzzer::Fuzz();
9798  if (v8_str("x")->Equals(name)) {
9799    return keyed_call_ic_function;
9800  }
9801  return v8::Handle<Value>();
9802}
9803
9804
9805// Test the case when we stored cacheable lookup into
9806// a stub, but the function name changed (to another cacheable function).
9807THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9808  v8::HandleScope scope;
9809  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9810  templ->SetNamedPropertyHandler(NoBlockGetterX);
9811  LocalContext context;
9812  context->Global()->Set(v8_str("o"), templ->NewInstance());
9813  CompileRun(
9814    "proto = new Object();"
9815    "proto.y = function(x) { return x + 1; };"
9816    "proto.z = function(x) { return x - 1; };"
9817    "o.__proto__ = proto;"
9818    "var result = 0;"
9819    "var method = 'y';"
9820    "for (var i = 0; i < 10; i++) {"
9821    "  if (i == 5) { method = 'z'; };"
9822    "  result += o[method](41);"
9823    "}");
9824  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9825}
9826
9827
9828// Test the case when we stored cacheable lookup into
9829// a stub, but the function name changed (and the new function is present
9830// both before and after the interceptor in the prototype chain).
9831THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9832  v8::HandleScope scope;
9833  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9834  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9835  LocalContext context;
9836  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9837  keyed_call_ic_function =
9838      v8_compile("function f(x) { return x - 1; }; f")->Run();
9839  CompileRun(
9840    "o = new Object();"
9841    "proto2 = new Object();"
9842    "o.y = function(x) { return x + 1; };"
9843    "proto2.y = function(x) { return x + 2; };"
9844    "o.__proto__ = proto1;"
9845    "proto1.__proto__ = proto2;"
9846    "var result = 0;"
9847    "var method = 'x';"
9848    "for (var i = 0; i < 10; i++) {"
9849    "  if (i == 5) { method = 'y'; };"
9850    "  result += o[method](41);"
9851    "}");
9852  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9853}
9854
9855
9856// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9857// on the global object.
9858THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9859  v8::HandleScope scope;
9860  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9861  templ->SetNamedPropertyHandler(NoBlockGetterX);
9862  LocalContext context;
9863  context->Global()->Set(v8_str("o"), templ->NewInstance());
9864  CompileRun(
9865    "function inc(x) { return x + 1; };"
9866    "inc(1);"
9867    "function dec(x) { return x - 1; };"
9868    "dec(1);"
9869    "o.__proto__ = this;"
9870    "this.__proto__.x = inc;"
9871    "this.__proto__.y = dec;"
9872    "var result = 0;"
9873    "var method = 'x';"
9874    "for (var i = 0; i < 10; i++) {"
9875    "  if (i == 5) { method = 'y'; };"
9876    "  result += o[method](41);"
9877    "}");
9878  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9879}
9880
9881
9882// Test the case when actual function to call sits on global object.
9883THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9884  v8::HandleScope scope;
9885  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9886  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9887  LocalContext context;
9888  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9889
9890  CompileRun(
9891    "function len(x) { return x.length; };"
9892    "o.__proto__ = this;"
9893    "var m = 'parseFloat';"
9894    "var result = 0;"
9895    "for (var i = 0; i < 10; i++) {"
9896    "  if (i == 5) {"
9897    "    m = 'len';"
9898    "    saved_result = result;"
9899    "  };"
9900    "  result = o[m]('239');"
9901    "}");
9902  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9903  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9904}
9905
9906// Test the map transition before the interceptor.
9907THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9908  v8::HandleScope scope;
9909  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9910  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9911  LocalContext context;
9912  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9913
9914  CompileRun(
9915    "var o = new Object();"
9916    "o.__proto__ = proto;"
9917    "o.method = function(x) { return x + 1; };"
9918    "var m = 'method';"
9919    "var result = 0;"
9920    "for (var i = 0; i < 10; i++) {"
9921    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
9922    "  result += o[m](41);"
9923    "}");
9924  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9925}
9926
9927
9928// Test the map transition after the interceptor.
9929THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9930  v8::HandleScope scope;
9931  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9932  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9933  LocalContext context;
9934  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9935
9936  CompileRun(
9937    "var proto = new Object();"
9938    "o.__proto__ = proto;"
9939    "proto.method = function(x) { return x + 1; };"
9940    "var m = 'method';"
9941    "var result = 0;"
9942    "for (var i = 0; i < 10; i++) {"
9943    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9944    "  result += o[m](41);"
9945    "}");
9946  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9947}
9948
9949
9950static int interceptor_call_count = 0;
9951
9952static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9953                                                     const AccessorInfo& info) {
9954  ApiTestFuzzer::Fuzz();
9955  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9956    return call_ic_function2;
9957  }
9958  return v8::Handle<Value>();
9959}
9960
9961
9962// This test should hit load and call ICs for the interceptor case.
9963// Once in a while, the interceptor will reply that a property was not
9964// found in which case we should get a reference error.
9965THREADED_TEST(InterceptorICReferenceErrors) {
9966  v8::HandleScope scope;
9967  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9968  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9969  LocalContext context(0, templ, v8::Handle<Value>());
9970  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9971  v8::Handle<Value> value = CompileRun(
9972    "function f() {"
9973    "  for (var i = 0; i < 1000; i++) {"
9974    "    try { x; } catch(e) { return true; }"
9975    "  }"
9976    "  return false;"
9977    "};"
9978    "f();");
9979  CHECK_EQ(true, value->BooleanValue());
9980  interceptor_call_count = 0;
9981  value = CompileRun(
9982    "function g() {"
9983    "  for (var i = 0; i < 1000; i++) {"
9984    "    try { x(42); } catch(e) { return true; }"
9985    "  }"
9986    "  return false;"
9987    "};"
9988    "g();");
9989  CHECK_EQ(true, value->BooleanValue());
9990}
9991
9992
9993static int interceptor_ic_exception_get_count = 0;
9994
9995static v8::Handle<Value> InterceptorICExceptionGetter(
9996    Local<String> name,
9997    const AccessorInfo& info) {
9998  ApiTestFuzzer::Fuzz();
9999  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10000    return call_ic_function3;
10001  }
10002  if (interceptor_ic_exception_get_count == 20) {
10003    return v8::ThrowException(v8_num(42));
10004  }
10005  // Do not handle get for properties other than x.
10006  return v8::Handle<Value>();
10007}
10008
10009// Test interceptor load/call IC where the interceptor throws an
10010// exception once in a while.
10011THREADED_TEST(InterceptorICGetterExceptions) {
10012  interceptor_ic_exception_get_count = 0;
10013  v8::HandleScope scope;
10014  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10015  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10016  LocalContext context(0, templ, v8::Handle<Value>());
10017  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10018  v8::Handle<Value> value = CompileRun(
10019    "function f() {"
10020    "  for (var i = 0; i < 100; i++) {"
10021    "    try { x; } catch(e) { return true; }"
10022    "  }"
10023    "  return false;"
10024    "};"
10025    "f();");
10026  CHECK_EQ(true, value->BooleanValue());
10027  interceptor_ic_exception_get_count = 0;
10028  value = CompileRun(
10029    "function f() {"
10030    "  for (var i = 0; i < 100; i++) {"
10031    "    try { x(42); } catch(e) { return true; }"
10032    "  }"
10033    "  return false;"
10034    "};"
10035    "f();");
10036  CHECK_EQ(true, value->BooleanValue());
10037}
10038
10039
10040static int interceptor_ic_exception_set_count = 0;
10041
10042static v8::Handle<Value> InterceptorICExceptionSetter(
10043      Local<String> key, Local<Value> value, const AccessorInfo&) {
10044  ApiTestFuzzer::Fuzz();
10045  if (++interceptor_ic_exception_set_count > 20) {
10046    return v8::ThrowException(v8_num(42));
10047  }
10048  // Do not actually handle setting.
10049  return v8::Handle<Value>();
10050}
10051
10052// Test interceptor store IC where the interceptor throws an exception
10053// once in a while.
10054THREADED_TEST(InterceptorICSetterExceptions) {
10055  interceptor_ic_exception_set_count = 0;
10056  v8::HandleScope scope;
10057  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10058  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10059  LocalContext context(0, templ, v8::Handle<Value>());
10060  v8::Handle<Value> value = CompileRun(
10061    "function f() {"
10062    "  for (var i = 0; i < 100; i++) {"
10063    "    try { x = 42; } catch(e) { return true; }"
10064    "  }"
10065    "  return false;"
10066    "};"
10067    "f();");
10068  CHECK_EQ(true, value->BooleanValue());
10069}
10070
10071
10072// Test that we ignore null interceptors.
10073THREADED_TEST(NullNamedInterceptor) {
10074  v8::HandleScope scope;
10075  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10076  templ->SetNamedPropertyHandler(0);
10077  LocalContext context;
10078  templ->Set("x", v8_num(42));
10079  v8::Handle<v8::Object> obj = templ->NewInstance();
10080  context->Global()->Set(v8_str("obj"), obj);
10081  v8::Handle<Value> value = CompileRun("obj.x");
10082  CHECK(value->IsInt32());
10083  CHECK_EQ(42, value->Int32Value());
10084}
10085
10086
10087// Test that we ignore null interceptors.
10088THREADED_TEST(NullIndexedInterceptor) {
10089  v8::HandleScope scope;
10090  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10091  templ->SetIndexedPropertyHandler(0);
10092  LocalContext context;
10093  templ->Set("42", v8_num(42));
10094  v8::Handle<v8::Object> obj = templ->NewInstance();
10095  context->Global()->Set(v8_str("obj"), obj);
10096  v8::Handle<Value> value = CompileRun("obj[42]");
10097  CHECK(value->IsInt32());
10098  CHECK_EQ(42, value->Int32Value());
10099}
10100
10101
10102THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10103  v8::HandleScope scope;
10104  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10105  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10106  LocalContext env;
10107  env->Global()->Set(v8_str("obj"),
10108                     templ->GetFunction()->NewInstance());
10109  ExpectTrue("obj.x === 42");
10110  ExpectTrue("!obj.propertyIsEnumerable('x')");
10111}
10112
10113
10114static Handle<Value> ThrowingGetter(Local<String> name,
10115                                    const AccessorInfo& info) {
10116  ApiTestFuzzer::Fuzz();
10117  ThrowException(Handle<Value>());
10118  return Undefined();
10119}
10120
10121
10122THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10123  HandleScope scope;
10124  LocalContext context;
10125
10126  Local<FunctionTemplate> templ = FunctionTemplate::New();
10127  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10128  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10129
10130  Local<Object> instance = templ->GetFunction()->NewInstance();
10131
10132  Local<Object> another = Object::New();
10133  another->SetPrototype(instance);
10134
10135  Local<Object> with_js_getter = CompileRun(
10136      "o = {};\n"
10137      "o.__defineGetter__('f', function() { throw undefined; });\n"
10138      "o\n").As<Object>();
10139  CHECK(!with_js_getter.IsEmpty());
10140
10141  TryCatch try_catch;
10142
10143  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10144  CHECK(try_catch.HasCaught());
10145  try_catch.Reset();
10146  CHECK(result.IsEmpty());
10147
10148  result = another->GetRealNamedProperty(v8_str("f"));
10149  CHECK(try_catch.HasCaught());
10150  try_catch.Reset();
10151  CHECK(result.IsEmpty());
10152
10153  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10154  CHECK(try_catch.HasCaught());
10155  try_catch.Reset();
10156  CHECK(result.IsEmpty());
10157
10158  result = another->Get(v8_str("f"));
10159  CHECK(try_catch.HasCaught());
10160  try_catch.Reset();
10161  CHECK(result.IsEmpty());
10162
10163  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10164  CHECK(try_catch.HasCaught());
10165  try_catch.Reset();
10166  CHECK(result.IsEmpty());
10167
10168  result = with_js_getter->Get(v8_str("f"));
10169  CHECK(try_catch.HasCaught());
10170  try_catch.Reset();
10171  CHECK(result.IsEmpty());
10172}
10173
10174
10175static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10176  TryCatch try_catch;
10177  // Verboseness is important: it triggers message delivery which can call into
10178  // external code.
10179  try_catch.SetVerbose(true);
10180  CompileRun("throw 'from JS';");
10181  CHECK(try_catch.HasCaught());
10182  CHECK(!i::Isolate::Current()->has_pending_exception());
10183  CHECK(!i::Isolate::Current()->has_scheduled_exception());
10184  return Undefined();
10185}
10186
10187
10188static int call_depth;
10189
10190
10191static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10192  TryCatch try_catch;
10193}
10194
10195
10196static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10197  if (--call_depth) CompileRun("throw 'ThrowInJS';");
10198}
10199
10200
10201static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10202  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
10203}
10204
10205
10206static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10207  Handle<String> errorMessageString = message->Get();
10208  CHECK(!errorMessageString.IsEmpty());
10209  message->GetStackTrace();
10210  message->GetScriptResourceName();
10211}
10212
10213THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10214  HandleScope scope;
10215  LocalContext context;
10216
10217  Local<Function> func =
10218      FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10219  context->Global()->Set(v8_str("func"), func);
10220
10221  MessageCallback callbacks[] =
10222      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10223  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10224    MessageCallback callback = callbacks[i];
10225    if (callback != NULL) {
10226      V8::AddMessageListener(callback);
10227    }
10228    // Some small number to control number of times message handler should
10229    // throw an exception.
10230    call_depth = 5;
10231    ExpectFalse(
10232        "var thrown = false;\n"
10233        "try { func(); } catch(e) { thrown = true; }\n"
10234        "thrown\n");
10235    if (callback != NULL) {
10236      V8::RemoveMessageListeners(callback);
10237    }
10238  }
10239}
10240
10241
10242static v8::Handle<Value> ParentGetter(Local<String> name,
10243                                      const AccessorInfo& info) {
10244  ApiTestFuzzer::Fuzz();
10245  return v8_num(1);
10246}
10247
10248
10249static v8::Handle<Value> ChildGetter(Local<String> name,
10250                                     const AccessorInfo& info) {
10251  ApiTestFuzzer::Fuzz();
10252  return v8_num(42);
10253}
10254
10255
10256THREADED_TEST(Overriding) {
10257  v8::HandleScope scope;
10258  LocalContext context;
10259
10260  // Parent template.
10261  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10262  Local<ObjectTemplate> parent_instance_templ =
10263      parent_templ->InstanceTemplate();
10264  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10265
10266  // Template that inherits from the parent template.
10267  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10268  Local<ObjectTemplate> child_instance_templ =
10269      child_templ->InstanceTemplate();
10270  child_templ->Inherit(parent_templ);
10271  // Override 'f'.  The child version of 'f' should get called for child
10272  // instances.
10273  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10274  // Add 'g' twice.  The 'g' added last should get called for instances.
10275  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10276  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10277
10278  // Add 'h' as an accessor to the proto template with ReadOnly attributes
10279  // so 'h' can be shadowed on the instance object.
10280  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10281  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10282      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10283
10284  // Add 'i' as an accessor to the instance template with ReadOnly attributes
10285  // but the attribute does not have effect because it is duplicated with
10286  // NULL setter.
10287  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10288      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10289
10290
10291
10292  // Instantiate the child template.
10293  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10294
10295  // Check that the child function overrides the parent one.
10296  context->Global()->Set(v8_str("o"), instance);
10297  Local<Value> value = v8_compile("o.f")->Run();
10298  // Check that the 'g' that was added last is hit.
10299  CHECK_EQ(42, value->Int32Value());
10300  value = v8_compile("o.g")->Run();
10301  CHECK_EQ(42, value->Int32Value());
10302
10303  // Check 'h' can be shadowed.
10304  value = v8_compile("o.h = 3; o.h")->Run();
10305  CHECK_EQ(3, value->Int32Value());
10306
10307  // Check 'i' is cannot be shadowed or changed.
10308  value = v8_compile("o.i = 3; o.i")->Run();
10309  CHECK_EQ(42, value->Int32Value());
10310}
10311
10312
10313static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10314  ApiTestFuzzer::Fuzz();
10315  return v8::Boolean::New(args.IsConstructCall());
10316}
10317
10318
10319THREADED_TEST(IsConstructCall) {
10320  v8::HandleScope scope;
10321
10322  // Function template with call handler.
10323  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10324  templ->SetCallHandler(IsConstructHandler);
10325
10326  LocalContext context;
10327
10328  context->Global()->Set(v8_str("f"), templ->GetFunction());
10329  Local<Value> value = v8_compile("f()")->Run();
10330  CHECK(!value->BooleanValue());
10331  value = v8_compile("new f()")->Run();
10332  CHECK(value->BooleanValue());
10333}
10334
10335
10336THREADED_TEST(ObjectProtoToString) {
10337  v8::HandleScope scope;
10338  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10339  templ->SetClassName(v8_str("MyClass"));
10340
10341  LocalContext context;
10342
10343  Local<String> customized_tostring = v8_str("customized toString");
10344
10345  // Replace Object.prototype.toString
10346  v8_compile("Object.prototype.toString = function() {"
10347                  "  return 'customized toString';"
10348                  "}")->Run();
10349
10350  // Normal ToString call should call replaced Object.prototype.toString
10351  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10352  Local<String> value = instance->ToString();
10353  CHECK(value->IsString() && value->Equals(customized_tostring));
10354
10355  // ObjectProtoToString should not call replace toString function.
10356  value = instance->ObjectProtoToString();
10357  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10358
10359  // Check global
10360  value = context->Global()->ObjectProtoToString();
10361  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10362
10363  // Check ordinary object
10364  Local<Value> object = v8_compile("new Object()")->Run();
10365  value = object.As<v8::Object>()->ObjectProtoToString();
10366  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10367}
10368
10369
10370THREADED_TEST(ObjectGetConstructorName) {
10371  v8::HandleScope scope;
10372  LocalContext context;
10373  v8_compile("function Parent() {};"
10374             "function Child() {};"
10375             "Child.prototype = new Parent();"
10376             "var outer = { inner: function() { } };"
10377             "var p = new Parent();"
10378             "var c = new Child();"
10379             "var x = new outer.inner();")->Run();
10380
10381  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10382  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10383      v8_str("Parent")));
10384
10385  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10386  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10387      v8_str("Child")));
10388
10389  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10390  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10391      v8_str("outer.inner")));
10392}
10393
10394
10395bool ApiTestFuzzer::fuzzing_ = false;
10396i::Semaphore* ApiTestFuzzer::all_tests_done_=
10397  i::OS::CreateSemaphore(0);
10398int ApiTestFuzzer::active_tests_;
10399int ApiTestFuzzer::tests_being_run_;
10400int ApiTestFuzzer::current_;
10401
10402
10403// We are in a callback and want to switch to another thread (if we
10404// are currently running the thread fuzzing test).
10405void ApiTestFuzzer::Fuzz() {
10406  if (!fuzzing_) return;
10407  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10408  test->ContextSwitch();
10409}
10410
10411
10412// Let the next thread go.  Since it is also waiting on the V8 lock it may
10413// not start immediately.
10414bool ApiTestFuzzer::NextThread() {
10415  int test_position = GetNextTestNumber();
10416  const char* test_name = RegisterThreadedTest::nth(current_)->name();
10417  if (test_position == current_) {
10418    if (kLogThreading)
10419      printf("Stay with %s\n", test_name);
10420    return false;
10421  }
10422  if (kLogThreading) {
10423    printf("Switch from %s to %s\n",
10424           test_name,
10425           RegisterThreadedTest::nth(test_position)->name());
10426  }
10427  current_ = test_position;
10428  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10429  return true;
10430}
10431
10432
10433void ApiTestFuzzer::Run() {
10434  // When it is our turn...
10435  gate_->Wait();
10436  {
10437    // ... get the V8 lock and start running the test.
10438    v8::Locker locker;
10439    CallTest();
10440  }
10441  // This test finished.
10442  active_ = false;
10443  active_tests_--;
10444  // If it was the last then signal that fact.
10445  if (active_tests_ == 0) {
10446    all_tests_done_->Signal();
10447  } else {
10448    // Otherwise select a new test and start that.
10449    NextThread();
10450  }
10451}
10452
10453
10454static unsigned linear_congruential_generator;
10455
10456
10457void ApiTestFuzzer::SetUp(PartOfTest part) {
10458  linear_congruential_generator = i::FLAG_testing_prng_seed;
10459  fuzzing_ = true;
10460  int count = RegisterThreadedTest::count();
10461  int start =  count * part / (LAST_PART + 1);
10462  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10463  active_tests_ = tests_being_run_ = end - start + 1;
10464  for (int i = 0; i < tests_being_run_; i++) {
10465    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10466  }
10467  for (int i = 0; i < active_tests_; i++) {
10468    RegisterThreadedTest::nth(i)->fuzzer_->Start();
10469  }
10470}
10471
10472
10473static void CallTestNumber(int test_number) {
10474  (RegisterThreadedTest::nth(test_number)->callback())();
10475}
10476
10477
10478void ApiTestFuzzer::RunAllTests() {
10479  // Set off the first test.
10480  current_ = -1;
10481  NextThread();
10482  // Wait till they are all done.
10483  all_tests_done_->Wait();
10484}
10485
10486
10487int ApiTestFuzzer::GetNextTestNumber() {
10488  int next_test;
10489  do {
10490    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10491    linear_congruential_generator *= 1664525u;
10492    linear_congruential_generator += 1013904223u;
10493  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10494  return next_test;
10495}
10496
10497
10498void ApiTestFuzzer::ContextSwitch() {
10499  // If the new thread is the same as the current thread there is nothing to do.
10500  if (NextThread()) {
10501    // Now it can start.
10502    v8::Unlocker unlocker;
10503    // Wait till someone starts us again.
10504    gate_->Wait();
10505    // And we're off.
10506  }
10507}
10508
10509
10510void ApiTestFuzzer::TearDown() {
10511  fuzzing_ = false;
10512  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10513    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10514    if (fuzzer != NULL) fuzzer->Join();
10515  }
10516}
10517
10518
10519// Lets not be needlessly self-referential.
10520TEST(Threading) {
10521  ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
10522  ApiTestFuzzer::RunAllTests();
10523  ApiTestFuzzer::TearDown();
10524}
10525
10526TEST(Threading2) {
10527  ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
10528  ApiTestFuzzer::RunAllTests();
10529  ApiTestFuzzer::TearDown();
10530}
10531
10532TEST(Threading3) {
10533  ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
10534  ApiTestFuzzer::RunAllTests();
10535  ApiTestFuzzer::TearDown();
10536}
10537
10538TEST(Threading4) {
10539  ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
10540  ApiTestFuzzer::RunAllTests();
10541  ApiTestFuzzer::TearDown();
10542}
10543
10544void ApiTestFuzzer::CallTest() {
10545  if (kLogThreading)
10546    printf("Start test %d\n", test_number_);
10547  CallTestNumber(test_number_);
10548  if (kLogThreading)
10549    printf("End test %d\n", test_number_);
10550}
10551
10552
10553static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10554  CHECK(v8::Locker::IsLocked());
10555  ApiTestFuzzer::Fuzz();
10556  v8::Unlocker unlocker;
10557  const char* code = "throw 7;";
10558  {
10559    v8::Locker nested_locker;
10560    v8::HandleScope scope;
10561    v8::Handle<Value> exception;
10562    { v8::TryCatch try_catch;
10563      v8::Handle<Value> value = CompileRun(code);
10564      CHECK(value.IsEmpty());
10565      CHECK(try_catch.HasCaught());
10566      // Make sure to wrap the exception in a new handle because
10567      // the handle returned from the TryCatch is destroyed
10568      // when the TryCatch is destroyed.
10569      exception = Local<Value>::New(try_catch.Exception());
10570    }
10571    return v8::ThrowException(exception);
10572  }
10573}
10574
10575
10576static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10577  CHECK(v8::Locker::IsLocked());
10578  ApiTestFuzzer::Fuzz();
10579  v8::Unlocker unlocker;
10580  const char* code = "throw 7;";
10581  {
10582    v8::Locker nested_locker;
10583    v8::HandleScope scope;
10584    v8::Handle<Value> value = CompileRun(code);
10585    CHECK(value.IsEmpty());
10586    return v8_str("foo");
10587  }
10588}
10589
10590
10591// These are locking tests that don't need to be run again
10592// as part of the locking aggregation tests.
10593TEST(NestedLockers) {
10594  v8::Locker locker;
10595  CHECK(v8::Locker::IsLocked());
10596  v8::HandleScope scope;
10597  LocalContext env;
10598  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10599  Local<Function> fun = fun_templ->GetFunction();
10600  env->Global()->Set(v8_str("throw_in_js"), fun);
10601  Local<Script> script = v8_compile("(function () {"
10602                                    "  try {"
10603                                    "    throw_in_js();"
10604                                    "    return 42;"
10605                                    "  } catch (e) {"
10606                                    "    return e * 13;"
10607                                    "  }"
10608                                    "})();");
10609  CHECK_EQ(91, script->Run()->Int32Value());
10610}
10611
10612
10613// These are locking tests that don't need to be run again
10614// as part of the locking aggregation tests.
10615TEST(NestedLockersNoTryCatch) {
10616  v8::Locker locker;
10617  v8::HandleScope scope;
10618  LocalContext env;
10619  Local<v8::FunctionTemplate> fun_templ =
10620      v8::FunctionTemplate::New(ThrowInJSNoCatch);
10621  Local<Function> fun = fun_templ->GetFunction();
10622  env->Global()->Set(v8_str("throw_in_js"), fun);
10623  Local<Script> script = v8_compile("(function () {"
10624                                    "  try {"
10625                                    "    throw_in_js();"
10626                                    "    return 42;"
10627                                    "  } catch (e) {"
10628                                    "    return e * 13;"
10629                                    "  }"
10630                                    "})();");
10631  CHECK_EQ(91, script->Run()->Int32Value());
10632}
10633
10634
10635THREADED_TEST(RecursiveLocking) {
10636  v8::Locker locker;
10637  {
10638    v8::Locker locker2;
10639    CHECK(v8::Locker::IsLocked());
10640  }
10641}
10642
10643
10644static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10645  ApiTestFuzzer::Fuzz();
10646  v8::Unlocker unlocker;
10647  return v8::Undefined();
10648}
10649
10650
10651THREADED_TEST(LockUnlockLock) {
10652  {
10653    v8::Locker locker;
10654    v8::HandleScope scope;
10655    LocalContext env;
10656    Local<v8::FunctionTemplate> fun_templ =
10657        v8::FunctionTemplate::New(UnlockForAMoment);
10658    Local<Function> fun = fun_templ->GetFunction();
10659    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10660    Local<Script> script = v8_compile("(function () {"
10661                                      "  unlock_for_a_moment();"
10662                                      "  return 42;"
10663                                      "})();");
10664    CHECK_EQ(42, script->Run()->Int32Value());
10665  }
10666  {
10667    v8::Locker locker;
10668    v8::HandleScope scope;
10669    LocalContext env;
10670    Local<v8::FunctionTemplate> fun_templ =
10671        v8::FunctionTemplate::New(UnlockForAMoment);
10672    Local<Function> fun = fun_templ->GetFunction();
10673    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10674    Local<Script> script = v8_compile("(function () {"
10675                                      "  unlock_for_a_moment();"
10676                                      "  return 42;"
10677                                      "})();");
10678    CHECK_EQ(42, script->Run()->Int32Value());
10679  }
10680}
10681
10682
10683static int GetGlobalObjectsCount() {
10684  i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10685  int count = 0;
10686  i::HeapIterator it;
10687  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10688    if (object->IsJSGlobalObject()) count++;
10689  return count;
10690}
10691
10692
10693static void CheckSurvivingGlobalObjectsCount(int expected) {
10694  // We need to collect all garbage twice to be sure that everything
10695  // has been collected.  This is because inline caches are cleared in
10696  // the first garbage collection but some of the maps have already
10697  // been marked at that point.  Therefore some of the maps are not
10698  // collected until the second garbage collection.
10699  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10700  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10701  int count = GetGlobalObjectsCount();
10702#ifdef DEBUG
10703  if (count != expected) HEAP->TracePathToGlobal();
10704#endif
10705  CHECK_EQ(expected, count);
10706}
10707
10708
10709TEST(DontLeakGlobalObjects) {
10710  // Regression test for issues 1139850 and 1174891.
10711
10712  v8::V8::Initialize();
10713
10714  for (int i = 0; i < 5; i++) {
10715    { v8::HandleScope scope;
10716      LocalContext context;
10717    }
10718    CheckSurvivingGlobalObjectsCount(0);
10719
10720    { v8::HandleScope scope;
10721      LocalContext context;
10722      v8_compile("Date")->Run();
10723    }
10724    CheckSurvivingGlobalObjectsCount(0);
10725
10726    { v8::HandleScope scope;
10727      LocalContext context;
10728      v8_compile("/aaa/")->Run();
10729    }
10730    CheckSurvivingGlobalObjectsCount(0);
10731
10732    { v8::HandleScope scope;
10733      const char* extension_list[] = { "v8/gc" };
10734      v8::ExtensionConfiguration extensions(1, extension_list);
10735      LocalContext context(&extensions);
10736      v8_compile("gc();")->Run();
10737    }
10738    CheckSurvivingGlobalObjectsCount(0);
10739  }
10740}
10741
10742
10743v8::Persistent<v8::Object> some_object;
10744v8::Persistent<v8::Object> bad_handle;
10745
10746void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10747  v8::HandleScope scope;
10748  bad_handle = v8::Persistent<v8::Object>::New(some_object);
10749  handle.Dispose();
10750}
10751
10752
10753THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10754  LocalContext context;
10755
10756  v8::Persistent<v8::Object> handle1, handle2;
10757  {
10758    v8::HandleScope scope;
10759    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10760    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10761    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10762  }
10763  // Note: order is implementation dependent alas: currently
10764  // global handle nodes are processed by PostGarbageCollectionProcessing
10765  // in reverse allocation order, so if second allocated handle is deleted,
10766  // weak callback of the first handle would be able to 'reallocate' it.
10767  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10768  handle2.Dispose();
10769  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10770}
10771
10772
10773v8::Persistent<v8::Object> to_be_disposed;
10774
10775void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10776  to_be_disposed.Dispose();
10777  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10778  handle.Dispose();
10779}
10780
10781
10782THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10783  LocalContext context;
10784
10785  v8::Persistent<v8::Object> handle1, handle2;
10786  {
10787    v8::HandleScope scope;
10788    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10789    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10790  }
10791  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10792  to_be_disposed = handle2;
10793  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10794}
10795
10796void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10797  handle.Dispose();
10798}
10799
10800void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10801  v8::HandleScope scope;
10802  v8::Persistent<v8::Object>::New(v8::Object::New());
10803  handle.Dispose();
10804}
10805
10806
10807THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10808  LocalContext context;
10809
10810  v8::Persistent<v8::Object> handle1, handle2, handle3;
10811  {
10812    v8::HandleScope scope;
10813    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10814    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10815    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10816  }
10817  handle2.MakeWeak(NULL, DisposingCallback);
10818  handle3.MakeWeak(NULL, HandleCreatingCallback);
10819  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10820}
10821
10822
10823THREADED_TEST(CheckForCrossContextObjectLiterals) {
10824  v8::V8::Initialize();
10825
10826  const int nof = 2;
10827  const char* sources[nof] = {
10828    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10829    "Object()"
10830  };
10831
10832  for (int i = 0; i < nof; i++) {
10833    const char* source = sources[i];
10834    { v8::HandleScope scope;
10835      LocalContext context;
10836      CompileRun(source);
10837    }
10838    { v8::HandleScope scope;
10839      LocalContext context;
10840      CompileRun(source);
10841    }
10842  }
10843}
10844
10845
10846static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10847  v8::HandleScope inner;
10848  env->Enter();
10849  v8::Handle<Value> three = v8_num(3);
10850  v8::Handle<Value> value = inner.Close(three);
10851  env->Exit();
10852  return value;
10853}
10854
10855
10856THREADED_TEST(NestedHandleScopeAndContexts) {
10857  v8::HandleScope outer;
10858  v8::Persistent<Context> env = Context::New();
10859  env->Enter();
10860  v8::Handle<Value> value = NestedScope(env);
10861  v8::Handle<String> str(value->ToString());
10862  CHECK(!str.IsEmpty());
10863  env->Exit();
10864  env.Dispose();
10865}
10866
10867
10868THREADED_TEST(ExternalAllocatedMemory) {
10869  v8::HandleScope outer;
10870  v8::Persistent<Context> env(Context::New());
10871  CHECK(!env.IsEmpty());
10872  const int kSize = 1024*1024;
10873  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10874  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10875}
10876
10877
10878THREADED_TEST(DisposeEnteredContext) {
10879  v8::HandleScope scope;
10880  LocalContext outer;
10881  { v8::Persistent<v8::Context> inner = v8::Context::New();
10882    inner->Enter();
10883    inner.Dispose();
10884    inner.Clear();
10885    inner->Exit();
10886  }
10887}
10888
10889
10890// Regression test for issue 54, object templates with internal fields
10891// but no accessors or interceptors did not get their internal field
10892// count set on instances.
10893THREADED_TEST(Regress54) {
10894  v8::HandleScope outer;
10895  LocalContext context;
10896  static v8::Persistent<v8::ObjectTemplate> templ;
10897  if (templ.IsEmpty()) {
10898    v8::HandleScope inner;
10899    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10900    local->SetInternalFieldCount(1);
10901    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10902  }
10903  v8::Handle<v8::Object> result = templ->NewInstance();
10904  CHECK_EQ(1, result->InternalFieldCount());
10905}
10906
10907
10908// If part of the threaded tests, this test makes ThreadingTest fail
10909// on mac.
10910TEST(CatchStackOverflow) {
10911  v8::HandleScope scope;
10912  LocalContext context;
10913  v8::TryCatch try_catch;
10914  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10915    "function f() {"
10916    "  return f();"
10917    "}"
10918    ""
10919    "f();"));
10920  v8::Handle<v8::Value> result = script->Run();
10921  CHECK(result.IsEmpty());
10922}
10923
10924
10925static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10926                                    const char* resource_name,
10927                                    int line_offset) {
10928  v8::HandleScope scope;
10929  v8::TryCatch try_catch;
10930  v8::Handle<v8::Value> result = script->Run();
10931  CHECK(result.IsEmpty());
10932  CHECK(try_catch.HasCaught());
10933  v8::Handle<v8::Message> message = try_catch.Message();
10934  CHECK(!message.IsEmpty());
10935  CHECK_EQ(10 + line_offset, message->GetLineNumber());
10936  CHECK_EQ(91, message->GetStartPosition());
10937  CHECK_EQ(92, message->GetEndPosition());
10938  CHECK_EQ(2, message->GetStartColumn());
10939  CHECK_EQ(3, message->GetEndColumn());
10940  v8::String::AsciiValue line(message->GetSourceLine());
10941  CHECK_EQ("  throw 'nirk';", *line);
10942  v8::String::AsciiValue name(message->GetScriptResourceName());
10943  CHECK_EQ(resource_name, *name);
10944}
10945
10946
10947THREADED_TEST(TryCatchSourceInfo) {
10948  v8::HandleScope scope;
10949  LocalContext context;
10950  v8::Handle<v8::String> source = v8::String::New(
10951      "function Foo() {\n"
10952      "  return Bar();\n"
10953      "}\n"
10954      "\n"
10955      "function Bar() {\n"
10956      "  return Baz();\n"
10957      "}\n"
10958      "\n"
10959      "function Baz() {\n"
10960      "  throw 'nirk';\n"
10961      "}\n"
10962      "\n"
10963      "Foo();\n");
10964
10965  const char* resource_name;
10966  v8::Handle<v8::Script> script;
10967  resource_name = "test.js";
10968  script = v8::Script::Compile(source, v8::String::New(resource_name));
10969  CheckTryCatchSourceInfo(script, resource_name, 0);
10970
10971  resource_name = "test1.js";
10972  v8::ScriptOrigin origin1(v8::String::New(resource_name));
10973  script = v8::Script::Compile(source, &origin1);
10974  CheckTryCatchSourceInfo(script, resource_name, 0);
10975
10976  resource_name = "test2.js";
10977  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10978  script = v8::Script::Compile(source, &origin2);
10979  CheckTryCatchSourceInfo(script, resource_name, 7);
10980}
10981
10982
10983THREADED_TEST(CompilationCache) {
10984  v8::HandleScope scope;
10985  LocalContext context;
10986  v8::Handle<v8::String> source0 = v8::String::New("1234");
10987  v8::Handle<v8::String> source1 = v8::String::New("1234");
10988  v8::Handle<v8::Script> script0 =
10989      v8::Script::Compile(source0, v8::String::New("test.js"));
10990  v8::Handle<v8::Script> script1 =
10991      v8::Script::Compile(source1, v8::String::New("test.js"));
10992  v8::Handle<v8::Script> script2 =
10993      v8::Script::Compile(source0);  // different origin
10994  CHECK_EQ(1234, script0->Run()->Int32Value());
10995  CHECK_EQ(1234, script1->Run()->Int32Value());
10996  CHECK_EQ(1234, script2->Run()->Int32Value());
10997}
10998
10999
11000static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11001  ApiTestFuzzer::Fuzz();
11002  return v8_num(42);
11003}
11004
11005
11006THREADED_TEST(CallbackFunctionName) {
11007  v8::HandleScope scope;
11008  LocalContext context;
11009  Local<ObjectTemplate> t = ObjectTemplate::New();
11010  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11011  context->Global()->Set(v8_str("obj"), t->NewInstance());
11012  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11013  CHECK(value->IsString());
11014  v8::String::AsciiValue name(value);
11015  CHECK_EQ("asdf", *name);
11016}
11017
11018
11019THREADED_TEST(DateAccess) {
11020  v8::HandleScope scope;
11021  LocalContext context;
11022  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11023  CHECK(date->IsDate());
11024  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
11025}
11026
11027
11028void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
11029  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11030  v8::Handle<v8::Array> props = obj->GetPropertyNames();
11031  CHECK_EQ(elmc, props->Length());
11032  for (int i = 0; i < elmc; i++) {
11033    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11034    CHECK_EQ(elmv[i], *elm);
11035  }
11036}
11037
11038
11039void CheckOwnProperties(v8::Handle<v8::Value> val,
11040                        int elmc,
11041                        const char* elmv[]) {
11042  v8::Handle<v8::Object> obj = val.As<v8::Object>();
11043  v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11044  CHECK_EQ(elmc, props->Length());
11045  for (int i = 0; i < elmc; i++) {
11046    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11047    CHECK_EQ(elmv[i], *elm);
11048  }
11049}
11050
11051
11052THREADED_TEST(PropertyEnumeration) {
11053  v8::HandleScope scope;
11054  LocalContext context;
11055  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11056      "var result = [];"
11057      "result[0] = {};"
11058      "result[1] = {a: 1, b: 2};"
11059      "result[2] = [1, 2, 3];"
11060      "var proto = {x: 1, y: 2, z: 3};"
11061      "var x = { __proto__: proto, w: 0, z: 1 };"
11062      "result[3] = x;"
11063      "result;"))->Run();
11064  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11065  CHECK_EQ(4, elms->Length());
11066  int elmc0 = 0;
11067  const char** elmv0 = NULL;
11068  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11069  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11070  int elmc1 = 2;
11071  const char* elmv1[] = {"a", "b"};
11072  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11073  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11074  int elmc2 = 3;
11075  const char* elmv2[] = {"0", "1", "2"};
11076  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11077  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11078  int elmc3 = 4;
11079  const char* elmv3[] = {"w", "z", "x", "y"};
11080  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
11081  int elmc4 = 2;
11082  const char* elmv4[] = {"w", "z"};
11083  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
11084}
11085
11086THREADED_TEST(PropertyEnumeration2) {
11087  v8::HandleScope scope;
11088  LocalContext context;
11089  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11090      "var result = [];"
11091      "result[0] = {};"
11092      "result[1] = {a: 1, b: 2};"
11093      "result[2] = [1, 2, 3];"
11094      "var proto = {x: 1, y: 2, z: 3};"
11095      "var x = { __proto__: proto, w: 0, z: 1 };"
11096      "result[3] = x;"
11097      "result;"))->Run();
11098  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11099  CHECK_EQ(4, elms->Length());
11100  int elmc0 = 0;
11101  const char** elmv0 = NULL;
11102  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11103
11104  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11105  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11106  CHECK_EQ(0, props->Length());
11107  for (uint32_t i = 0; i < props->Length(); i++) {
11108    printf("p[%d]\n", i);
11109  }
11110}
11111
11112static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11113                                  Local<Value> name,
11114                                  v8::AccessType type,
11115                                  Local<Value> data) {
11116  return type != v8::ACCESS_SET;
11117}
11118
11119
11120static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11121                                    uint32_t key,
11122                                    v8::AccessType type,
11123                                    Local<Value> data) {
11124  return type != v8::ACCESS_SET;
11125}
11126
11127
11128THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11129  v8::HandleScope scope;
11130  LocalContext context;
11131  Local<ObjectTemplate> templ = ObjectTemplate::New();
11132  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11133                                 IndexedSetAccessBlocker);
11134  templ->Set(v8_str("x"), v8::True());
11135  Local<v8::Object> instance = templ->NewInstance();
11136  context->Global()->Set(v8_str("obj"), instance);
11137  Local<Value> value = CompileRun("obj.x");
11138  CHECK(value->BooleanValue());
11139}
11140
11141
11142static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11143                                  Local<Value> name,
11144                                  v8::AccessType type,
11145                                  Local<Value> data) {
11146  return false;
11147}
11148
11149
11150static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11151                                    uint32_t key,
11152                                    v8::AccessType type,
11153                                    Local<Value> data) {
11154  return false;
11155}
11156
11157
11158
11159THREADED_TEST(AccessChecksReenabledCorrectly) {
11160  v8::HandleScope scope;
11161  LocalContext context;
11162  Local<ObjectTemplate> templ = ObjectTemplate::New();
11163  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11164                                 IndexedGetAccessBlocker);
11165  templ->Set(v8_str("a"), v8_str("a"));
11166  // Add more than 8 (see kMaxFastProperties) properties
11167  // so that the constructor will force copying map.
11168  // Cannot sprintf, gcc complains unsafety.
11169  char buf[4];
11170  for (char i = '0'; i <= '9' ; i++) {
11171    buf[0] = i;
11172    for (char j = '0'; j <= '9'; j++) {
11173      buf[1] = j;
11174      for (char k = '0'; k <= '9'; k++) {
11175        buf[2] = k;
11176        buf[3] = 0;
11177        templ->Set(v8_str(buf), v8::Number::New(k));
11178      }
11179    }
11180  }
11181
11182  Local<v8::Object> instance_1 = templ->NewInstance();
11183  context->Global()->Set(v8_str("obj_1"), instance_1);
11184
11185  Local<Value> value_1 = CompileRun("obj_1.a");
11186  CHECK(value_1->IsUndefined());
11187
11188  Local<v8::Object> instance_2 = templ->NewInstance();
11189  context->Global()->Set(v8_str("obj_2"), instance_2);
11190
11191  Local<Value> value_2 = CompileRun("obj_2.a");
11192  CHECK(value_2->IsUndefined());
11193}
11194
11195
11196// This tests that access check information remains on the global
11197// object template when creating contexts.
11198THREADED_TEST(AccessControlRepeatedContextCreation) {
11199  v8::HandleScope handle_scope;
11200  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11201  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11202                                           IndexedSetAccessBlocker);
11203  i::Handle<i::ObjectTemplateInfo> internal_template =
11204      v8::Utils::OpenHandle(*global_template);
11205  CHECK(!internal_template->constructor()->IsUndefined());
11206  i::Handle<i::FunctionTemplateInfo> constructor(
11207      i::FunctionTemplateInfo::cast(internal_template->constructor()));
11208  CHECK(!constructor->access_check_info()->IsUndefined());
11209  v8::Persistent<Context> context0(Context::New(NULL, global_template));
11210  CHECK(!context0.IsEmpty());
11211  CHECK(!constructor->access_check_info()->IsUndefined());
11212}
11213
11214
11215THREADED_TEST(TurnOnAccessCheck) {
11216  v8::HandleScope handle_scope;
11217
11218  // Create an environment with access check to the global object disabled by
11219  // default.
11220  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11221  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11222                                           IndexedGetAccessBlocker,
11223                                           v8::Handle<v8::Value>(),
11224                                           false);
11225  v8::Persistent<Context> context = Context::New(NULL, global_template);
11226  Context::Scope context_scope(context);
11227
11228  // Set up a property and a number of functions.
11229  context->Global()->Set(v8_str("a"), v8_num(1));
11230  CompileRun("function f1() {return a;}"
11231             "function f2() {return a;}"
11232             "function g1() {return h();}"
11233             "function g2() {return h();}"
11234             "function h() {return 1;}");
11235  Local<Function> f1 =
11236      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11237  Local<Function> f2 =
11238      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11239  Local<Function> g1 =
11240      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11241  Local<Function> g2 =
11242      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11243  Local<Function> h =
11244      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11245
11246  // Get the global object.
11247  v8::Handle<v8::Object> global = context->Global();
11248
11249  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11250  // uses the runtime system to retreive property a whereas f2 uses global load
11251  // inline cache.
11252  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11253  for (int i = 0; i < 4; i++) {
11254    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11255  }
11256
11257  // Same for g1 and g2.
11258  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11259  for (int i = 0; i < 4; i++) {
11260    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11261  }
11262
11263  // Detach the global and turn on access check.
11264  context->DetachGlobal();
11265  context->Global()->TurnOnAccessCheck();
11266
11267  // Failing access check to property get results in undefined.
11268  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11269  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11270
11271  // Failing access check to function call results in exception.
11272  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11273  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11274
11275  // No failing access check when just returning a constant.
11276  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11277}
11278
11279
11280static const char* kPropertyA = "a";
11281static const char* kPropertyH = "h";
11282
11283static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11284                                       Local<Value> name,
11285                                       v8::AccessType type,
11286                                       Local<Value> data) {
11287  if (!name->IsString()) return false;
11288  i::Handle<i::String> name_handle =
11289      v8::Utils::OpenHandle(String::Cast(*name));
11290  return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11291      && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
11292}
11293
11294
11295THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11296  v8::HandleScope handle_scope;
11297
11298  // Create an environment with access check to the global object disabled by
11299  // default. When the registered access checker will block access to properties
11300  // a and h.
11301  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11302  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11303                                           IndexedGetAccessBlocker,
11304                                           v8::Handle<v8::Value>(),
11305                                           false);
11306  v8::Persistent<Context> context = Context::New(NULL, global_template);
11307  Context::Scope context_scope(context);
11308
11309  // Set up a property and a number of functions.
11310  context->Global()->Set(v8_str("a"), v8_num(1));
11311  static const char* source = "function f1() {return a;}"
11312                              "function f2() {return a;}"
11313                              "function g1() {return h();}"
11314                              "function g2() {return h();}"
11315                              "function h() {return 1;}";
11316
11317  CompileRun(source);
11318  Local<Function> f1;
11319  Local<Function> f2;
11320  Local<Function> g1;
11321  Local<Function> g2;
11322  Local<Function> h;
11323  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11324  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11325  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11326  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11327  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11328
11329  // Get the global object.
11330  v8::Handle<v8::Object> global = context->Global();
11331
11332  // Call f1 one time and f2 a number of times. This will ensure that f1 still
11333  // uses the runtime system to retreive property a whereas f2 uses global load
11334  // inline cache.
11335  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11336  for (int i = 0; i < 4; i++) {
11337    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11338  }
11339
11340  // Same for g1 and g2.
11341  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11342  for (int i = 0; i < 4; i++) {
11343    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11344  }
11345
11346  // Detach the global and turn on access check now blocking access to property
11347  // a and function h.
11348  context->DetachGlobal();
11349  context->Global()->TurnOnAccessCheck();
11350
11351  // Failing access check to property get results in undefined.
11352  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11353  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11354
11355  // Failing access check to function call results in exception.
11356  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11357  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11358
11359  // No failing access check when just returning a constant.
11360  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11361
11362  // Now compile the source again. And get the newly compiled functions, except
11363  // for h for which access is blocked.
11364  CompileRun(source);
11365  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11366  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11367  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11368  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11369  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11370
11371  // Failing access check to property get results in undefined.
11372  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11373  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11374
11375  // Failing access check to function call results in exception.
11376  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11377  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11378}
11379
11380
11381// This test verifies that pre-compilation (aka preparsing) can be called
11382// without initializing the whole VM. Thus we cannot run this test in a
11383// multi-threaded setup.
11384TEST(PreCompile) {
11385  // TODO(155): This test would break without the initialization of V8. This is
11386  // a workaround for now to make this test not fail.
11387  v8::V8::Initialize();
11388  const char* script = "function foo(a) { return a+1; }";
11389  v8::ScriptData* sd =
11390      v8::ScriptData::PreCompile(script, i::StrLength(script));
11391  CHECK_NE(sd->Length(), 0);
11392  CHECK_NE(sd->Data(), NULL);
11393  CHECK(!sd->HasError());
11394  delete sd;
11395}
11396
11397
11398TEST(PreCompileWithError) {
11399  v8::V8::Initialize();
11400  const char* script = "function foo(a) { return 1 * * 2; }";
11401  v8::ScriptData* sd =
11402      v8::ScriptData::PreCompile(script, i::StrLength(script));
11403  CHECK(sd->HasError());
11404  delete sd;
11405}
11406
11407
11408TEST(Regress31661) {
11409  v8::V8::Initialize();
11410  const char* script = " The Definintive Guide";
11411  v8::ScriptData* sd =
11412      v8::ScriptData::PreCompile(script, i::StrLength(script));
11413  CHECK(sd->HasError());
11414  delete sd;
11415}
11416
11417
11418// Tests that ScriptData can be serialized and deserialized.
11419TEST(PreCompileSerialization) {
11420  v8::V8::Initialize();
11421  const char* script = "function foo(a) { return a+1; }";
11422  v8::ScriptData* sd =
11423      v8::ScriptData::PreCompile(script, i::StrLength(script));
11424
11425  // Serialize.
11426  int serialized_data_length = sd->Length();
11427  char* serialized_data = i::NewArray<char>(serialized_data_length);
11428  memcpy(serialized_data, sd->Data(), serialized_data_length);
11429
11430  // Deserialize.
11431  v8::ScriptData* deserialized_sd =
11432      v8::ScriptData::New(serialized_data, serialized_data_length);
11433
11434  // Verify that the original is the same as the deserialized.
11435  CHECK_EQ(sd->Length(), deserialized_sd->Length());
11436  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11437  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11438
11439  delete sd;
11440  delete deserialized_sd;
11441}
11442
11443
11444// Attempts to deserialize bad data.
11445TEST(PreCompileDeserializationError) {
11446  v8::V8::Initialize();
11447  const char* data = "DONT CARE";
11448  int invalid_size = 3;
11449  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11450
11451  CHECK_EQ(0, sd->Length());
11452
11453  delete sd;
11454}
11455
11456
11457// Attempts to deserialize bad data.
11458TEST(PreCompileInvalidPreparseDataError) {
11459  v8::V8::Initialize();
11460  v8::HandleScope scope;
11461  LocalContext context;
11462
11463  const char* script = "function foo(){ return 5;}\n"
11464      "function bar(){ return 6 + 7;}  foo();";
11465  v8::ScriptData* sd =
11466      v8::ScriptData::PreCompile(script, i::StrLength(script));
11467  CHECK(!sd->HasError());
11468  // ScriptDataImpl private implementation details
11469  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11470  const int kFunctionEntrySize = i::FunctionEntry::kSize;
11471  const int kFunctionEntryStartOffset = 0;
11472  const int kFunctionEntryEndOffset = 1;
11473  unsigned* sd_data =
11474      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11475
11476  // Overwrite function bar's end position with 0.
11477  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11478  v8::TryCatch try_catch;
11479
11480  Local<String> source = String::New(script);
11481  Local<Script> compiled_script = Script::New(source, NULL, sd);
11482  CHECK(try_catch.HasCaught());
11483  String::AsciiValue exception_value(try_catch.Message()->Get());
11484  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11485           *exception_value);
11486
11487  try_catch.Reset();
11488
11489  // Overwrite function bar's start position with 200.  The function entry
11490  // will not be found when searching for it by position and we should fall
11491  // back on eager compilation.
11492  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11493  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11494  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11495      200;
11496  compiled_script = Script::New(source, NULL, sd);
11497  CHECK(!try_catch.HasCaught());
11498
11499  delete sd;
11500}
11501
11502
11503// Verifies that the Handle<String> and const char* versions of the API produce
11504// the same results (at least for one trivial case).
11505TEST(PreCompileAPIVariationsAreSame) {
11506  v8::V8::Initialize();
11507  v8::HandleScope scope;
11508
11509  const char* cstring = "function foo(a) { return a+1; }";
11510
11511  v8::ScriptData* sd_from_cstring =
11512      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11513
11514  TestAsciiResource* resource = new TestAsciiResource(cstring);
11515  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
11516      v8::String::NewExternal(resource));
11517
11518  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11519      v8::String::New(cstring));
11520
11521  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
11522  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11523                     sd_from_external_string->Data(),
11524                     sd_from_cstring->Length()));
11525
11526  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11527  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11528                     sd_from_string->Data(),
11529                     sd_from_cstring->Length()));
11530
11531
11532  delete sd_from_cstring;
11533  delete sd_from_external_string;
11534  delete sd_from_string;
11535}
11536
11537
11538// This tests that we do not allow dictionary load/call inline caches
11539// to use functions that have not yet been compiled.  The potential
11540// problem of loading a function that has not yet been compiled can
11541// arise because we share code between contexts via the compilation
11542// cache.
11543THREADED_TEST(DictionaryICLoadedFunction) {
11544  v8::HandleScope scope;
11545  // Test LoadIC.
11546  for (int i = 0; i < 2; i++) {
11547    LocalContext context;
11548    context->Global()->Set(v8_str("tmp"), v8::True());
11549    context->Global()->Delete(v8_str("tmp"));
11550    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11551  }
11552  // Test CallIC.
11553  for (int i = 0; i < 2; i++) {
11554    LocalContext context;
11555    context->Global()->Set(v8_str("tmp"), v8::True());
11556    context->Global()->Delete(v8_str("tmp"));
11557    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11558  }
11559}
11560
11561
11562// Test that cross-context new calls use the context of the callee to
11563// create the new JavaScript object.
11564THREADED_TEST(CrossContextNew) {
11565  v8::HandleScope scope;
11566  v8::Persistent<Context> context0 = Context::New();
11567  v8::Persistent<Context> context1 = Context::New();
11568
11569  // Allow cross-domain access.
11570  Local<String> token = v8_str("<security token>");
11571  context0->SetSecurityToken(token);
11572  context1->SetSecurityToken(token);
11573
11574  // Set an 'x' property on the Object prototype and define a
11575  // constructor function in context0.
11576  context0->Enter();
11577  CompileRun("Object.prototype.x = 42; function C() {};");
11578  context0->Exit();
11579
11580  // Call the constructor function from context0 and check that the
11581  // result has the 'x' property.
11582  context1->Enter();
11583  context1->Global()->Set(v8_str("other"), context0->Global());
11584  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11585  CHECK(value->IsInt32());
11586  CHECK_EQ(42, value->Int32Value());
11587  context1->Exit();
11588
11589  // Dispose the contexts to allow them to be garbage collected.
11590  context0.Dispose();
11591  context1.Dispose();
11592}
11593
11594
11595class RegExpInterruptTest {
11596 public:
11597  RegExpInterruptTest() : block_(NULL) {}
11598  ~RegExpInterruptTest() { delete block_; }
11599  void RunTest() {
11600    block_ = i::OS::CreateSemaphore(0);
11601    gc_count_ = 0;
11602    gc_during_regexp_ = 0;
11603    regexp_success_ = false;
11604    gc_success_ = false;
11605    GCThread gc_thread(this);
11606    gc_thread.Start();
11607    v8::Locker::StartPreemption(1);
11608
11609    LongRunningRegExp();
11610    {
11611      v8::Unlocker unlock;
11612      gc_thread.Join();
11613    }
11614    v8::Locker::StopPreemption();
11615    CHECK(regexp_success_);
11616    CHECK(gc_success_);
11617  }
11618
11619 private:
11620  // Number of garbage collections required.
11621  static const int kRequiredGCs = 5;
11622
11623  class GCThread : public i::Thread {
11624   public:
11625    explicit GCThread(RegExpInterruptTest* test)
11626        : Thread("GCThread"), test_(test) {}
11627    virtual void Run() {
11628      test_->CollectGarbage();
11629    }
11630   private:
11631     RegExpInterruptTest* test_;
11632  };
11633
11634  void CollectGarbage() {
11635    block_->Wait();
11636    while (gc_during_regexp_ < kRequiredGCs) {
11637      {
11638        v8::Locker lock;
11639        // TODO(lrn): Perhaps create some garbage before collecting.
11640        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11641        gc_count_++;
11642      }
11643      i::OS::Sleep(1);
11644    }
11645    gc_success_ = true;
11646  }
11647
11648  void LongRunningRegExp() {
11649    block_->Signal();  // Enable garbage collection thread on next preemption.
11650    int rounds = 0;
11651    while (gc_during_regexp_ < kRequiredGCs) {
11652      int gc_before = gc_count_;
11653      {
11654        // Match 15-30 "a"'s against 14 and a "b".
11655        const char* c_source =
11656            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11657            ".exec('aaaaaaaaaaaaaaab') === null";
11658        Local<String> source = String::New(c_source);
11659        Local<Script> script = Script::Compile(source);
11660        Local<Value> result = script->Run();
11661        if (!result->BooleanValue()) {
11662          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
11663          return;
11664        }
11665      }
11666      {
11667        // Match 15-30 "a"'s against 15 and a "b".
11668        const char* c_source =
11669            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11670            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11671        Local<String> source = String::New(c_source);
11672        Local<Script> script = Script::Compile(source);
11673        Local<Value> result = script->Run();
11674        if (!result->BooleanValue()) {
11675          gc_during_regexp_ = kRequiredGCs;
11676          return;
11677        }
11678      }
11679      int gc_after = gc_count_;
11680      gc_during_regexp_ += gc_after - gc_before;
11681      rounds++;
11682      i::OS::Sleep(1);
11683    }
11684    regexp_success_ = true;
11685  }
11686
11687  i::Semaphore* block_;
11688  int gc_count_;
11689  int gc_during_regexp_;
11690  bool regexp_success_;
11691  bool gc_success_;
11692};
11693
11694
11695// Test that a regular expression execution can be interrupted and
11696// survive a garbage collection.
11697TEST(RegExpInterruption) {
11698  v8::Locker lock;
11699  v8::V8::Initialize();
11700  v8::HandleScope scope;
11701  Local<Context> local_env;
11702  {
11703    LocalContext env;
11704    local_env = env.local();
11705  }
11706
11707  // Local context should still be live.
11708  CHECK(!local_env.IsEmpty());
11709  local_env->Enter();
11710
11711  // Should complete without problems.
11712  RegExpInterruptTest().RunTest();
11713
11714  local_env->Exit();
11715}
11716
11717
11718class ApplyInterruptTest {
11719 public:
11720  ApplyInterruptTest() : block_(NULL) {}
11721  ~ApplyInterruptTest() { delete block_; }
11722  void RunTest() {
11723    block_ = i::OS::CreateSemaphore(0);
11724    gc_count_ = 0;
11725    gc_during_apply_ = 0;
11726    apply_success_ = false;
11727    gc_success_ = false;
11728    GCThread gc_thread(this);
11729    gc_thread.Start();
11730    v8::Locker::StartPreemption(1);
11731
11732    LongRunningApply();
11733    {
11734      v8::Unlocker unlock;
11735      gc_thread.Join();
11736    }
11737    v8::Locker::StopPreemption();
11738    CHECK(apply_success_);
11739    CHECK(gc_success_);
11740  }
11741
11742 private:
11743  // Number of garbage collections required.
11744  static const int kRequiredGCs = 2;
11745
11746  class GCThread : public i::Thread {
11747   public:
11748    explicit GCThread(ApplyInterruptTest* test)
11749        : Thread("GCThread"), test_(test) {}
11750    virtual void Run() {
11751      test_->CollectGarbage();
11752    }
11753   private:
11754     ApplyInterruptTest* test_;
11755  };
11756
11757  void CollectGarbage() {
11758    block_->Wait();
11759    while (gc_during_apply_ < kRequiredGCs) {
11760      {
11761        v8::Locker lock;
11762        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11763        gc_count_++;
11764      }
11765      i::OS::Sleep(1);
11766    }
11767    gc_success_ = true;
11768  }
11769
11770  void LongRunningApply() {
11771    block_->Signal();
11772    int rounds = 0;
11773    while (gc_during_apply_ < kRequiredGCs) {
11774      int gc_before = gc_count_;
11775      {
11776        const char* c_source =
11777            "function do_very_little(bar) {"
11778            "  this.foo = bar;"
11779            "}"
11780            "for (var i = 0; i < 100000; i++) {"
11781            "  do_very_little.apply(this, ['bar']);"
11782            "}";
11783        Local<String> source = String::New(c_source);
11784        Local<Script> script = Script::Compile(source);
11785        Local<Value> result = script->Run();
11786        // Check that no exception was thrown.
11787        CHECK(!result.IsEmpty());
11788      }
11789      int gc_after = gc_count_;
11790      gc_during_apply_ += gc_after - gc_before;
11791      rounds++;
11792    }
11793    apply_success_ = true;
11794  }
11795
11796  i::Semaphore* block_;
11797  int gc_count_;
11798  int gc_during_apply_;
11799  bool apply_success_;
11800  bool gc_success_;
11801};
11802
11803
11804// Test that nothing bad happens if we get a preemption just when we were
11805// about to do an apply().
11806TEST(ApplyInterruption) {
11807  v8::Locker lock;
11808  v8::V8::Initialize();
11809  v8::HandleScope scope;
11810  Local<Context> local_env;
11811  {
11812    LocalContext env;
11813    local_env = env.local();
11814  }
11815
11816  // Local context should still be live.
11817  CHECK(!local_env.IsEmpty());
11818  local_env->Enter();
11819
11820  // Should complete without problems.
11821  ApplyInterruptTest().RunTest();
11822
11823  local_env->Exit();
11824}
11825
11826
11827// Verify that we can clone an object
11828TEST(ObjectClone) {
11829  v8::HandleScope scope;
11830  LocalContext env;
11831
11832  const char* sample =
11833    "var rv = {};"      \
11834    "rv.alpha = 'hello';" \
11835    "rv.beta = 123;"     \
11836    "rv;";
11837
11838  // Create an object, verify basics.
11839  Local<Value> val = CompileRun(sample);
11840  CHECK(val->IsObject());
11841  Local<v8::Object> obj = val.As<v8::Object>();
11842  obj->Set(v8_str("gamma"), v8_str("cloneme"));
11843
11844  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11845  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11846  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11847
11848  // Clone it.
11849  Local<v8::Object> clone = obj->Clone();
11850  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11851  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11852  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11853
11854  // Set a property on the clone, verify each object.
11855  clone->Set(v8_str("beta"), v8::Integer::New(456));
11856  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11857  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11858}
11859
11860
11861class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11862 public:
11863  explicit AsciiVectorResource(i::Vector<const char> vector)
11864      : data_(vector) {}
11865  virtual ~AsciiVectorResource() {}
11866  virtual size_t length() const { return data_.length(); }
11867  virtual const char* data() const { return data_.start(); }
11868 private:
11869  i::Vector<const char> data_;
11870};
11871
11872
11873class UC16VectorResource : public v8::String::ExternalStringResource {
11874 public:
11875  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11876      : data_(vector) {}
11877  virtual ~UC16VectorResource() {}
11878  virtual size_t length() const { return data_.length(); }
11879  virtual const i::uc16* data() const { return data_.start(); }
11880 private:
11881  i::Vector<const i::uc16> data_;
11882};
11883
11884
11885static void MorphAString(i::String* string,
11886                         AsciiVectorResource* ascii_resource,
11887                         UC16VectorResource* uc16_resource) {
11888  CHECK(i::StringShape(string).IsExternal());
11889  if (string->IsAsciiRepresentation()) {
11890    // Check old map is not symbol or long.
11891    CHECK(string->map() == HEAP->external_ascii_string_map());
11892    // Morph external string to be TwoByte string.
11893    string->set_map(HEAP->external_string_map());
11894    i::ExternalTwoByteString* morphed =
11895         i::ExternalTwoByteString::cast(string);
11896    morphed->set_resource(uc16_resource);
11897  } else {
11898    // Check old map is not symbol or long.
11899    CHECK(string->map() == HEAP->external_string_map());
11900    // Morph external string to be ASCII string.
11901    string->set_map(HEAP->external_ascii_string_map());
11902    i::ExternalAsciiString* morphed =
11903         i::ExternalAsciiString::cast(string);
11904    morphed->set_resource(ascii_resource);
11905  }
11906}
11907
11908
11909// Test that we can still flatten a string if the components it is built up
11910// from have been turned into 16 bit strings in the mean time.
11911THREADED_TEST(MorphCompositeStringTest) {
11912  char utf_buffer[129];
11913  const char* c_string = "Now is the time for all good men"
11914                         " to come to the aid of the party";
11915  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11916  {
11917    v8::HandleScope scope;
11918    LocalContext env;
11919    AsciiVectorResource ascii_resource(
11920        i::Vector<const char>(c_string, i::StrLength(c_string)));
11921    UC16VectorResource uc16_resource(
11922        i::Vector<const uint16_t>(two_byte_string,
11923                                  i::StrLength(c_string)));
11924
11925    Local<String> lhs(v8::Utils::ToLocal(
11926        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11927    Local<String> rhs(v8::Utils::ToLocal(
11928        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11929
11930    env->Global()->Set(v8_str("lhs"), lhs);
11931    env->Global()->Set(v8_str("rhs"), rhs);
11932
11933    CompileRun(
11934        "var cons = lhs + rhs;"
11935        "var slice = lhs.substring(1, lhs.length - 1);"
11936        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11937
11938    CHECK(!lhs->MayContainNonAscii());
11939    CHECK(!rhs->MayContainNonAscii());
11940
11941    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11942    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11943
11944    // This should UTF-8 without flattening, since everything is ASCII.
11945    Handle<String> cons = v8_compile("cons")->Run().As<String>();
11946    CHECK_EQ(128, cons->Utf8Length());
11947    int nchars = -1;
11948    CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11949    CHECK_EQ(128, nchars);
11950    CHECK_EQ(0, strcmp(
11951        utf_buffer,
11952        "Now is the time for all good men to come to the aid of the party"
11953        "Now is the time for all good men to come to the aid of the party"));
11954
11955    // Now do some stuff to make sure the strings are flattened, etc.
11956    CompileRun(
11957        "/[^a-z]/.test(cons);"
11958        "/[^a-z]/.test(slice);"
11959        "/[^a-z]/.test(slice_on_cons);");
11960    const char* expected_cons =
11961        "Now is the time for all good men to come to the aid of the party"
11962        "Now is the time for all good men to come to the aid of the party";
11963    const char* expected_slice =
11964        "ow is the time for all good men to come to the aid of the part";
11965    const char* expected_slice_on_cons =
11966        "ow is the time for all good men to come to the aid of the party"
11967        "Now is the time for all good men to come to the aid of the part";
11968    CHECK_EQ(String::New(expected_cons),
11969             env->Global()->Get(v8_str("cons")));
11970    CHECK_EQ(String::New(expected_slice),
11971             env->Global()->Get(v8_str("slice")));
11972    CHECK_EQ(String::New(expected_slice_on_cons),
11973             env->Global()->Get(v8_str("slice_on_cons")));
11974  }
11975  i::DeleteArray(two_byte_string);
11976}
11977
11978
11979TEST(CompileExternalTwoByteSource) {
11980  v8::HandleScope scope;
11981  LocalContext context;
11982
11983  // This is a very short list of sources, which currently is to check for a
11984  // regression caused by r2703.
11985  const char* ascii_sources[] = {
11986    "0.5",
11987    "-0.5",   // This mainly testes PushBack in the Scanner.
11988    "--0.5",  // This mainly testes PushBack in the Scanner.
11989    NULL
11990  };
11991
11992  // Compile the sources as external two byte strings.
11993  for (int i = 0; ascii_sources[i] != NULL; i++) {
11994    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11995    UC16VectorResource uc16_resource(
11996        i::Vector<const uint16_t>(two_byte_string,
11997                                  i::StrLength(ascii_sources[i])));
11998    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11999    v8::Script::Compile(source);
12000    i::DeleteArray(two_byte_string);
12001  }
12002}
12003
12004
12005class RegExpStringModificationTest {
12006 public:
12007  RegExpStringModificationTest()
12008      : block_(i::OS::CreateSemaphore(0)),
12009        morphs_(0),
12010        morphs_during_regexp_(0),
12011        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12012        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12013  ~RegExpStringModificationTest() { delete block_; }
12014  void RunTest() {
12015    regexp_success_ = false;
12016    morph_success_ = false;
12017
12018    // Initialize the contents of two_byte_content_ to be a uc16 representation
12019    // of "aaaaaaaaaaaaaab".
12020    for (int i = 0; i < 14; i++) {
12021      two_byte_content_[i] = 'a';
12022    }
12023    two_byte_content_[14] = 'b';
12024
12025    // Create the input string for the regexp - the one we are going to change
12026    // properties of.
12027    input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
12028
12029    // Inject the input as a global variable.
12030    i::Handle<i::String> input_name =
12031        FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
12032    i::Isolate::Current()->global_context()->global()->SetProperty(
12033        *input_name,
12034        *input_,
12035        NONE,
12036        i::kNonStrictMode)->ToObjectChecked();
12037
12038    MorphThread morph_thread(this);
12039    morph_thread.Start();
12040    v8::Locker::StartPreemption(1);
12041    LongRunningRegExp();
12042    {
12043      v8::Unlocker unlock;
12044      morph_thread.Join();
12045    }
12046    v8::Locker::StopPreemption();
12047    CHECK(regexp_success_);
12048    CHECK(morph_success_);
12049  }
12050
12051 private:
12052  // Number of string modifications required.
12053  static const int kRequiredModifications = 5;
12054  static const int kMaxModifications = 100;
12055
12056  class MorphThread : public i::Thread {
12057   public:
12058    explicit MorphThread(RegExpStringModificationTest* test)
12059        : Thread("MorphThread"), test_(test) {}
12060    virtual void Run() {
12061      test_->MorphString();
12062    }
12063   private:
12064     RegExpStringModificationTest* test_;
12065  };
12066
12067  void MorphString() {
12068    block_->Wait();
12069    while (morphs_during_regexp_ < kRequiredModifications &&
12070           morphs_ < kMaxModifications) {
12071      {
12072        v8::Locker lock;
12073        // Swap string between ascii and two-byte representation.
12074        i::String* string = *input_;
12075        MorphAString(string, &ascii_resource_, &uc16_resource_);
12076        morphs_++;
12077      }
12078      i::OS::Sleep(1);
12079    }
12080    morph_success_ = true;
12081  }
12082
12083  void LongRunningRegExp() {
12084    block_->Signal();  // Enable morphing thread on next preemption.
12085    while (morphs_during_regexp_ < kRequiredModifications &&
12086           morphs_ < kMaxModifications) {
12087      int morphs_before = morphs_;
12088      {
12089        v8::HandleScope scope;
12090        // Match 15-30 "a"'s against 14 and a "b".
12091        const char* c_source =
12092            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12093            ".exec(input) === null";
12094        Local<String> source = String::New(c_source);
12095        Local<Script> script = Script::Compile(source);
12096        Local<Value> result = script->Run();
12097        CHECK(result->IsTrue());
12098      }
12099      int morphs_after = morphs_;
12100      morphs_during_regexp_ += morphs_after - morphs_before;
12101    }
12102    regexp_success_ = true;
12103  }
12104
12105  i::uc16 two_byte_content_[15];
12106  i::Semaphore* block_;
12107  int morphs_;
12108  int morphs_during_regexp_;
12109  bool regexp_success_;
12110  bool morph_success_;
12111  i::Handle<i::String> input_;
12112  AsciiVectorResource ascii_resource_;
12113  UC16VectorResource uc16_resource_;
12114};
12115
12116
12117// Test that a regular expression execution can be interrupted and
12118// the string changed without failing.
12119TEST(RegExpStringModification) {
12120  v8::Locker lock;
12121  v8::V8::Initialize();
12122  v8::HandleScope scope;
12123  Local<Context> local_env;
12124  {
12125    LocalContext env;
12126    local_env = env.local();
12127  }
12128
12129  // Local context should still be live.
12130  CHECK(!local_env.IsEmpty());
12131  local_env->Enter();
12132
12133  // Should complete without problems.
12134  RegExpStringModificationTest().RunTest();
12135
12136  local_env->Exit();
12137}
12138
12139
12140// Test that we can set a property on the global object even if there
12141// is a read-only property in the prototype chain.
12142TEST(ReadOnlyPropertyInGlobalProto) {
12143  v8::HandleScope scope;
12144  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12145  LocalContext context(0, templ);
12146  v8::Handle<v8::Object> global = context->Global();
12147  v8::Handle<v8::Object> global_proto =
12148      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12149  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12150  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12151  // Check without 'eval' or 'with'.
12152  v8::Handle<v8::Value> res =
12153      CompileRun("function f() { x = 42; return x; }; f()");
12154  // Check with 'eval'.
12155  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
12156  CHECK_EQ(v8::Integer::New(42), res);
12157  // Check with 'with'.
12158  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
12159  CHECK_EQ(v8::Integer::New(42), res);
12160}
12161
12162static int force_set_set_count = 0;
12163static int force_set_get_count = 0;
12164bool pass_on_get = false;
12165
12166static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12167                                            const v8::AccessorInfo& info) {
12168  force_set_get_count++;
12169  if (pass_on_get) {
12170    return v8::Handle<v8::Value>();
12171  } else {
12172    return v8::Int32::New(3);
12173  }
12174}
12175
12176static void ForceSetSetter(v8::Local<v8::String> name,
12177                           v8::Local<v8::Value> value,
12178                           const v8::AccessorInfo& info) {
12179  force_set_set_count++;
12180}
12181
12182static v8::Handle<v8::Value> ForceSetInterceptSetter(
12183    v8::Local<v8::String> name,
12184    v8::Local<v8::Value> value,
12185    const v8::AccessorInfo& info) {
12186  force_set_set_count++;
12187  return v8::Undefined();
12188}
12189
12190TEST(ForceSet) {
12191  force_set_get_count = 0;
12192  force_set_set_count = 0;
12193  pass_on_get = false;
12194
12195  v8::HandleScope scope;
12196  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12197  v8::Handle<v8::String> access_property = v8::String::New("a");
12198  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12199  LocalContext context(NULL, templ);
12200  v8::Handle<v8::Object> global = context->Global();
12201
12202  // Ordinary properties
12203  v8::Handle<v8::String> simple_property = v8::String::New("p");
12204  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12205  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12206  // This should fail because the property is read-only
12207  global->Set(simple_property, v8::Int32::New(5));
12208  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12209  // This should succeed even though the property is read-only
12210  global->ForceSet(simple_property, v8::Int32::New(6));
12211  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12212
12213  // Accessors
12214  CHECK_EQ(0, force_set_set_count);
12215  CHECK_EQ(0, force_set_get_count);
12216  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12217  // CHECK_EQ the property shouldn't override it, just call the setter
12218  // which in this case does nothing.
12219  global->Set(access_property, v8::Int32::New(7));
12220  CHECK_EQ(3, global->Get(access_property)->Int32Value());
12221  CHECK_EQ(1, force_set_set_count);
12222  CHECK_EQ(2, force_set_get_count);
12223  // Forcing the property to be set should override the accessor without
12224  // calling it
12225  global->ForceSet(access_property, v8::Int32::New(8));
12226  CHECK_EQ(8, global->Get(access_property)->Int32Value());
12227  CHECK_EQ(1, force_set_set_count);
12228  CHECK_EQ(2, force_set_get_count);
12229}
12230
12231TEST(ForceSetWithInterceptor) {
12232  force_set_get_count = 0;
12233  force_set_set_count = 0;
12234  pass_on_get = false;
12235
12236  v8::HandleScope scope;
12237  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12238  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12239  LocalContext context(NULL, templ);
12240  v8::Handle<v8::Object> global = context->Global();
12241
12242  v8::Handle<v8::String> some_property = v8::String::New("a");
12243  CHECK_EQ(0, force_set_set_count);
12244  CHECK_EQ(0, force_set_get_count);
12245  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12246  // Setting the property shouldn't override it, just call the setter
12247  // which in this case does nothing.
12248  global->Set(some_property, v8::Int32::New(7));
12249  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12250  CHECK_EQ(1, force_set_set_count);
12251  CHECK_EQ(2, force_set_get_count);
12252  // Getting the property when the interceptor returns an empty handle
12253  // should yield undefined, since the property isn't present on the
12254  // object itself yet.
12255  pass_on_get = true;
12256  CHECK(global->Get(some_property)->IsUndefined());
12257  CHECK_EQ(1, force_set_set_count);
12258  CHECK_EQ(3, force_set_get_count);
12259  // Forcing the property to be set should cause the value to be
12260  // set locally without calling the interceptor.
12261  global->ForceSet(some_property, v8::Int32::New(8));
12262  CHECK_EQ(8, global->Get(some_property)->Int32Value());
12263  CHECK_EQ(1, force_set_set_count);
12264  CHECK_EQ(4, force_set_get_count);
12265  // Reenabling the interceptor should cause it to take precedence over
12266  // the property
12267  pass_on_get = false;
12268  CHECK_EQ(3, global->Get(some_property)->Int32Value());
12269  CHECK_EQ(1, force_set_set_count);
12270  CHECK_EQ(5, force_set_get_count);
12271  // The interceptor should also work for other properties
12272  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12273  CHECK_EQ(1, force_set_set_count);
12274  CHECK_EQ(6, force_set_get_count);
12275}
12276
12277
12278THREADED_TEST(ForceDelete) {
12279  v8::HandleScope scope;
12280  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12281  LocalContext context(NULL, templ);
12282  v8::Handle<v8::Object> global = context->Global();
12283
12284  // Ordinary properties
12285  v8::Handle<v8::String> simple_property = v8::String::New("p");
12286  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12287  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12288  // This should fail because the property is dont-delete.
12289  CHECK(!global->Delete(simple_property));
12290  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12291  // This should succeed even though the property is dont-delete.
12292  CHECK(global->ForceDelete(simple_property));
12293  CHECK(global->Get(simple_property)->IsUndefined());
12294}
12295
12296
12297static int force_delete_interceptor_count = 0;
12298static bool pass_on_delete = false;
12299
12300
12301static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12302    v8::Local<v8::String> name,
12303    const v8::AccessorInfo& info) {
12304  force_delete_interceptor_count++;
12305  if (pass_on_delete) {
12306    return v8::Handle<v8::Boolean>();
12307  } else {
12308    return v8::True();
12309  }
12310}
12311
12312
12313THREADED_TEST(ForceDeleteWithInterceptor) {
12314  force_delete_interceptor_count = 0;
12315  pass_on_delete = false;
12316
12317  v8::HandleScope scope;
12318  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12319  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12320  LocalContext context(NULL, templ);
12321  v8::Handle<v8::Object> global = context->Global();
12322
12323  v8::Handle<v8::String> some_property = v8::String::New("a");
12324  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12325
12326  // Deleting a property should get intercepted and nothing should
12327  // happen.
12328  CHECK_EQ(0, force_delete_interceptor_count);
12329  CHECK(global->Delete(some_property));
12330  CHECK_EQ(1, force_delete_interceptor_count);
12331  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12332  // Deleting the property when the interceptor returns an empty
12333  // handle should not delete the property since it is DontDelete.
12334  pass_on_delete = true;
12335  CHECK(!global->Delete(some_property));
12336  CHECK_EQ(2, force_delete_interceptor_count);
12337  CHECK_EQ(42, global->Get(some_property)->Int32Value());
12338  // Forcing the property to be deleted should delete the value
12339  // without calling the interceptor.
12340  CHECK(global->ForceDelete(some_property));
12341  CHECK(global->Get(some_property)->IsUndefined());
12342  CHECK_EQ(2, force_delete_interceptor_count);
12343}
12344
12345
12346// Make sure that forcing a delete invalidates any IC stubs, so we
12347// don't read the hole value.
12348THREADED_TEST(ForceDeleteIC) {
12349  v8::HandleScope scope;
12350  LocalContext context;
12351  // Create a DontDelete variable on the global object.
12352  CompileRun("this.__proto__ = { foo: 'horse' };"
12353             "var foo = 'fish';"
12354             "function f() { return foo.length; }");
12355  // Initialize the IC for foo in f.
12356  CompileRun("for (var i = 0; i < 4; i++) f();");
12357  // Make sure the value of foo is correct before the deletion.
12358  CHECK_EQ(4, CompileRun("f()")->Int32Value());
12359  // Force the deletion of foo.
12360  CHECK(context->Global()->ForceDelete(v8_str("foo")));
12361  // Make sure the value for foo is read from the prototype, and that
12362  // we don't get in trouble with reading the deleted cell value
12363  // sentinel.
12364  CHECK_EQ(5, CompileRun("f()")->Int32Value());
12365}
12366
12367
12368v8::Persistent<Context> calling_context0;
12369v8::Persistent<Context> calling_context1;
12370v8::Persistent<Context> calling_context2;
12371
12372
12373// Check that the call to the callback is initiated in
12374// calling_context2, the directly calling context is calling_context1
12375// and the callback itself is in calling_context0.
12376static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12377  ApiTestFuzzer::Fuzz();
12378  CHECK(Context::GetCurrent() == calling_context0);
12379  CHECK(Context::GetCalling() == calling_context1);
12380  CHECK(Context::GetEntered() == calling_context2);
12381  return v8::Integer::New(42);
12382}
12383
12384
12385THREADED_TEST(GetCallingContext) {
12386  v8::HandleScope scope;
12387
12388  calling_context0 = Context::New();
12389  calling_context1 = Context::New();
12390  calling_context2 = Context::New();
12391
12392  // Allow cross-domain access.
12393  Local<String> token = v8_str("<security token>");
12394  calling_context0->SetSecurityToken(token);
12395  calling_context1->SetSecurityToken(token);
12396  calling_context2->SetSecurityToken(token);
12397
12398  // Create an object with a C++ callback in context0.
12399  calling_context0->Enter();
12400  Local<v8::FunctionTemplate> callback_templ =
12401      v8::FunctionTemplate::New(GetCallingContextCallback);
12402  calling_context0->Global()->Set(v8_str("callback"),
12403                                  callback_templ->GetFunction());
12404  calling_context0->Exit();
12405
12406  // Expose context0 in context1 and set up a function that calls the
12407  // callback function.
12408  calling_context1->Enter();
12409  calling_context1->Global()->Set(v8_str("context0"),
12410                                  calling_context0->Global());
12411  CompileRun("function f() { context0.callback() }");
12412  calling_context1->Exit();
12413
12414  // Expose context1 in context2 and call the callback function in
12415  // context0 indirectly through f in context1.
12416  calling_context2->Enter();
12417  calling_context2->Global()->Set(v8_str("context1"),
12418                                  calling_context1->Global());
12419  CompileRun("context1.f()");
12420  calling_context2->Exit();
12421
12422  // Dispose the contexts to allow them to be garbage collected.
12423  calling_context0.Dispose();
12424  calling_context1.Dispose();
12425  calling_context2.Dispose();
12426  calling_context0.Clear();
12427  calling_context1.Clear();
12428  calling_context2.Clear();
12429}
12430
12431
12432// Check that a variable declaration with no explicit initialization
12433// value does not shadow an existing property in the prototype chain.
12434//
12435// This is consistent with Firefox and Safari.
12436//
12437// See http://crbug.com/12548.
12438THREADED_TEST(InitGlobalVarInProtoChain) {
12439  v8::HandleScope scope;
12440  LocalContext context;
12441  // Introduce a variable in the prototype chain.
12442  CompileRun("__proto__.x = 42");
12443  v8::Handle<v8::Value> result = CompileRun("var x; x");
12444  CHECK(!result->IsUndefined());
12445  CHECK_EQ(42, result->Int32Value());
12446}
12447
12448
12449// Regression test for issue 398.
12450// If a function is added to an object, creating a constant function
12451// field, and the result is cloned, replacing the constant function on the
12452// original should not affect the clone.
12453// See http://code.google.com/p/v8/issues/detail?id=398
12454THREADED_TEST(ReplaceConstantFunction) {
12455  v8::HandleScope scope;
12456  LocalContext context;
12457  v8::Handle<v8::Object> obj = v8::Object::New();
12458  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12459  v8::Handle<v8::String> foo_string = v8::String::New("foo");
12460  obj->Set(foo_string, func_templ->GetFunction());
12461  v8::Handle<v8::Object> obj_clone = obj->Clone();
12462  obj_clone->Set(foo_string, v8::String::New("Hello"));
12463  CHECK(!obj->Get(foo_string)->IsUndefined());
12464}
12465
12466
12467// Regression test for http://crbug.com/16276.
12468THREADED_TEST(Regress16276) {
12469  v8::HandleScope scope;
12470  LocalContext context;
12471  // Force the IC in f to be a dictionary load IC.
12472  CompileRun("function f(obj) { return obj.x; }\n"
12473             "var obj = { x: { foo: 42 }, y: 87 };\n"
12474             "var x = obj.x;\n"
12475             "delete obj.y;\n"
12476             "for (var i = 0; i < 5; i++) f(obj);");
12477  // Detach the global object to make 'this' refer directly to the
12478  // global object (not the proxy), and make sure that the dictionary
12479  // load IC doesn't mess up loading directly from the global object.
12480  context->DetachGlobal();
12481  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12482}
12483
12484
12485THREADED_TEST(PixelArray) {
12486  v8::HandleScope scope;
12487  LocalContext context;
12488  const int kElementCount = 260;
12489  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12490  i::Handle<i::ExternalPixelArray> pixels =
12491      i::Handle<i::ExternalPixelArray>::cast(
12492          FACTORY->NewExternalArray(kElementCount,
12493                                    v8::kExternalPixelArray,
12494                                    pixel_data));
12495  // Force GC to trigger verification.
12496  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12497  for (int i = 0; i < kElementCount; i++) {
12498    pixels->set(i, i % 256);
12499  }
12500  // Force GC to trigger verification.
12501  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12502  for (int i = 0; i < kElementCount; i++) {
12503    CHECK_EQ(i % 256, pixels->get_scalar(i));
12504    CHECK_EQ(i % 256, pixel_data[i]);
12505  }
12506
12507  v8::Handle<v8::Object> obj = v8::Object::New();
12508  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12509  // Set the elements to be the pixels.
12510  // jsobj->set_elements(*pixels);
12511  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12512  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12513  obj->Set(v8_str("field"), v8::Int32::New(1503));
12514  context->Global()->Set(v8_str("pixels"), obj);
12515  v8::Handle<v8::Value> result = CompileRun("pixels.field");
12516  CHECK_EQ(1503, result->Int32Value());
12517  result = CompileRun("pixels[1]");
12518  CHECK_EQ(1, result->Int32Value());
12519
12520  result = CompileRun("var sum = 0;"
12521                      "for (var i = 0; i < 8; i++) {"
12522                      "  sum += pixels[i] = pixels[i] = -i;"
12523                      "}"
12524                      "sum;");
12525  CHECK_EQ(-28, result->Int32Value());
12526
12527  result = CompileRun("var sum = 0;"
12528                      "for (var i = 0; i < 8; i++) {"
12529                      "  sum += pixels[i] = pixels[i] = 0;"
12530                      "}"
12531                      "sum;");
12532  CHECK_EQ(0, result->Int32Value());
12533
12534  result = CompileRun("var sum = 0;"
12535                      "for (var i = 0; i < 8; i++) {"
12536                      "  sum += pixels[i] = pixels[i] = 255;"
12537                      "}"
12538                      "sum;");
12539  CHECK_EQ(8 * 255, result->Int32Value());
12540
12541  result = CompileRun("var sum = 0;"
12542                      "for (var i = 0; i < 8; i++) {"
12543                      "  sum += pixels[i] = pixels[i] = 256 + i;"
12544                      "}"
12545                      "sum;");
12546  CHECK_EQ(2076, result->Int32Value());
12547
12548  result = CompileRun("var sum = 0;"
12549                      "for (var i = 0; i < 8; i++) {"
12550                      "  sum += pixels[i] = pixels[i] = i;"
12551                      "}"
12552                      "sum;");
12553  CHECK_EQ(28, result->Int32Value());
12554
12555  result = CompileRun("var sum = 0;"
12556                      "for (var i = 0; i < 8; i++) {"
12557                      "  sum += pixels[i];"
12558                      "}"
12559                      "sum;");
12560  CHECK_EQ(28, result->Int32Value());
12561
12562  i::Handle<i::Smi> value(i::Smi::FromInt(2));
12563  i::Handle<i::Object> no_failure;
12564  no_failure =
12565      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12566  ASSERT(!no_failure.is_null());
12567  i::USE(no_failure);
12568  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12569  *value.location() = i::Smi::FromInt(256);
12570  no_failure =
12571      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12572  ASSERT(!no_failure.is_null());
12573  i::USE(no_failure);
12574  CHECK_EQ(255,
12575           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12576  *value.location() = i::Smi::FromInt(-1);
12577  no_failure =
12578      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
12579  ASSERT(!no_failure.is_null());
12580  i::USE(no_failure);
12581  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12582
12583  result = CompileRun("for (var i = 0; i < 8; i++) {"
12584                      "  pixels[i] = (i * 65) - 109;"
12585                      "}"
12586                      "pixels[1] + pixels[6];");
12587  CHECK_EQ(255, result->Int32Value());
12588  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12589  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12590  CHECK_EQ(21,
12591           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12592  CHECK_EQ(86,
12593           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12594  CHECK_EQ(151,
12595           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12596  CHECK_EQ(216,
12597           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12598  CHECK_EQ(255,
12599           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12600  CHECK_EQ(255,
12601           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12602  result = CompileRun("var sum = 0;"
12603                      "for (var i = 0; i < 8; i++) {"
12604                      "  sum += pixels[i];"
12605                      "}"
12606                      "sum;");
12607  CHECK_EQ(984, result->Int32Value());
12608
12609  result = CompileRun("for (var i = 0; i < 8; i++) {"
12610                      "  pixels[i] = (i * 1.1);"
12611                      "}"
12612                      "pixels[1] + pixels[6];");
12613  CHECK_EQ(8, result->Int32Value());
12614  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12615  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12616  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12617  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12618  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12619  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12620  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12621  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12622
12623  result = CompileRun("for (var i = 0; i < 8; i++) {"
12624                      "  pixels[7] = undefined;"
12625                      "}"
12626                      "pixels[7];");
12627  CHECK_EQ(0, result->Int32Value());
12628  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12629
12630  result = CompileRun("for (var i = 0; i < 8; i++) {"
12631                      "  pixels[6] = '2.3';"
12632                      "}"
12633                      "pixels[6];");
12634  CHECK_EQ(2, result->Int32Value());
12635  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12636
12637  result = CompileRun("for (var i = 0; i < 8; i++) {"
12638                      "  pixels[5] = NaN;"
12639                      "}"
12640                      "pixels[5];");
12641  CHECK_EQ(0, result->Int32Value());
12642  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12643
12644  result = CompileRun("for (var i = 0; i < 8; i++) {"
12645                      "  pixels[8] = Infinity;"
12646                      "}"
12647                      "pixels[8];");
12648  CHECK_EQ(255, result->Int32Value());
12649  CHECK_EQ(255,
12650           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
12651
12652  result = CompileRun("for (var i = 0; i < 8; i++) {"
12653                      "  pixels[9] = -Infinity;"
12654                      "}"
12655                      "pixels[9];");
12656  CHECK_EQ(0, result->Int32Value());
12657  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
12658
12659  result = CompileRun("pixels[3] = 33;"
12660                      "delete pixels[3];"
12661                      "pixels[3];");
12662  CHECK_EQ(33, result->Int32Value());
12663
12664  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12665                      "pixels[2] = 12; pixels[3] = 13;"
12666                      "pixels.__defineGetter__('2',"
12667                      "function() { return 120; });"
12668                      "pixels[2];");
12669  CHECK_EQ(12, result->Int32Value());
12670
12671  result = CompileRun("var js_array = new Array(40);"
12672                      "js_array[0] = 77;"
12673                      "js_array;");
12674  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12675
12676  result = CompileRun("pixels[1] = 23;"
12677                      "pixels.__proto__ = [];"
12678                      "js_array.__proto__ = pixels;"
12679                      "js_array.concat(pixels);");
12680  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12681  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12682
12683  result = CompileRun("pixels[1] = 23;");
12684  CHECK_EQ(23, result->Int32Value());
12685
12686  // Test for index greater than 255.  Regression test for:
12687  // http://code.google.com/p/chromium/issues/detail?id=26337.
12688  result = CompileRun("pixels[256] = 255;");
12689  CHECK_EQ(255, result->Int32Value());
12690  result = CompileRun("var i = 0;"
12691                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12692                      "i");
12693  CHECK_EQ(255, result->Int32Value());
12694
12695  // Make sure that pixel array ICs recognize when a non-pixel array
12696  // is passed to it.
12697  result = CompileRun("function pa_load(p) {"
12698                      "  var sum = 0;"
12699                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12700                      "  return sum;"
12701                      "}"
12702                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12703                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12704                      "just_ints = new Object();"
12705                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12706                      "for (var i = 0; i < 10; ++i) {"
12707                      "  result = pa_load(just_ints);"
12708                      "}"
12709                      "result");
12710  CHECK_EQ(32640, result->Int32Value());
12711
12712  // Make sure that pixel array ICs recognize out-of-bound accesses.
12713  result = CompileRun("function pa_load(p, start) {"
12714                      "  var sum = 0;"
12715                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12716                      "  return sum;"
12717                      "}"
12718                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12719                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12720                      "for (var i = 0; i < 10; ++i) {"
12721                      "  result = pa_load(pixels,-10);"
12722                      "}"
12723                      "result");
12724  CHECK_EQ(0, result->Int32Value());
12725
12726  // Make sure that generic ICs properly handles a pixel array.
12727  result = CompileRun("function pa_load(p) {"
12728                      "  var sum = 0;"
12729                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12730                      "  return sum;"
12731                      "}"
12732                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12733                      "just_ints = new Object();"
12734                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12735                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12736                      "for (var i = 0; i < 10; ++i) {"
12737                      "  result = pa_load(pixels);"
12738                      "}"
12739                      "result");
12740  CHECK_EQ(32640, result->Int32Value());
12741
12742  // Make sure that generic load ICs recognize out-of-bound accesses in
12743  // pixel arrays.
12744  result = CompileRun("function pa_load(p, start) {"
12745                      "  var sum = 0;"
12746                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12747                      "  return sum;"
12748                      "}"
12749                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12750                      "just_ints = new Object();"
12751                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12752                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12753                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12754                      "for (var i = 0; i < 10; ++i) {"
12755                      "  result = pa_load(pixels,-10);"
12756                      "}"
12757                      "result");
12758  CHECK_EQ(0, result->Int32Value());
12759
12760  // Make sure that generic ICs properly handles other types than pixel
12761  // arrays (that the inlined fast pixel array test leaves the right information
12762  // in the right registers).
12763  result = CompileRun("function pa_load(p) {"
12764                      "  var sum = 0;"
12765                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12766                      "  return sum;"
12767                      "}"
12768                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12769                      "just_ints = new Object();"
12770                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12771                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12772                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12773                      "sparse_array = new Object();"
12774                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12775                      "sparse_array[1000000] = 3;"
12776                      "for (var i = 0; i < 10; ++i) {"
12777                      "  result = pa_load(sparse_array);"
12778                      "}"
12779                      "result");
12780  CHECK_EQ(32640, result->Int32Value());
12781
12782  // Make sure that pixel array store ICs clamp values correctly.
12783  result = CompileRun("function pa_store(p) {"
12784                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12785                      "}"
12786                      "pa_store(pixels);"
12787                      "var sum = 0;"
12788                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12789                      "sum");
12790  CHECK_EQ(48896, result->Int32Value());
12791
12792  // Make sure that pixel array stores correctly handle accesses outside
12793  // of the pixel array..
12794  result = CompileRun("function pa_store(p,start) {"
12795                      "  for (var j = 0; j < 256; j++) {"
12796                      "    p[j+start] = j * 2;"
12797                      "  }"
12798                      "}"
12799                      "pa_store(pixels,0);"
12800                      "pa_store(pixels,-128);"
12801                      "var sum = 0;"
12802                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12803                      "sum");
12804  CHECK_EQ(65280, result->Int32Value());
12805
12806  // Make sure that the generic store stub correctly handle accesses outside
12807  // of the pixel array..
12808  result = CompileRun("function pa_store(p,start) {"
12809                      "  for (var j = 0; j < 256; j++) {"
12810                      "    p[j+start] = j * 2;"
12811                      "  }"
12812                      "}"
12813                      "pa_store(pixels,0);"
12814                      "just_ints = new Object();"
12815                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12816                      "pa_store(just_ints, 0);"
12817                      "pa_store(pixels,-128);"
12818                      "var sum = 0;"
12819                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12820                      "sum");
12821  CHECK_EQ(65280, result->Int32Value());
12822
12823  // Make sure that the generic keyed store stub clamps pixel array values
12824  // correctly.
12825  result = CompileRun("function pa_store(p) {"
12826                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12827                      "}"
12828                      "pa_store(pixels);"
12829                      "just_ints = new Object();"
12830                      "pa_store(just_ints);"
12831                      "pa_store(pixels);"
12832                      "var sum = 0;"
12833                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12834                      "sum");
12835  CHECK_EQ(48896, result->Int32Value());
12836
12837  // Make sure that pixel array loads are optimized by crankshaft.
12838  result = CompileRun("function pa_load(p) {"
12839                      "  var sum = 0;"
12840                      "  for (var i=0; i<256; ++i) {"
12841                      "    sum += p[i];"
12842                      "  }"
12843                      "  return sum; "
12844                      "}"
12845                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12846                      "for (var i = 0; i < 5000; ++i) {"
12847                      "  result = pa_load(pixels);"
12848                      "}"
12849                      "result");
12850  CHECK_EQ(32640, result->Int32Value());
12851
12852  // Make sure that pixel array stores are optimized by crankshaft.
12853  result = CompileRun("function pa_init(p) {"
12854                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12855                      "}"
12856                      "function pa_load(p) {"
12857                      "  var sum = 0;"
12858                      "  for (var i=0; i<256; ++i) {"
12859                      "    sum += p[i];"
12860                      "  }"
12861                      "  return sum; "
12862                      "}"
12863                      "for (var i = 0; i < 5000; ++i) {"
12864                      "  pa_init(pixels);"
12865                      "}"
12866                      "result = pa_load(pixels);"
12867                      "result");
12868  CHECK_EQ(32640, result->Int32Value());
12869
12870  free(pixel_data);
12871}
12872
12873
12874THREADED_TEST(PixelArrayInfo) {
12875  v8::HandleScope scope;
12876  LocalContext context;
12877  for (int size = 0; size < 100; size += 10) {
12878    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12879    v8::Handle<v8::Object> obj = v8::Object::New();
12880    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12881    CHECK(obj->HasIndexedPropertiesInPixelData());
12882    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12883    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12884    free(pixel_data);
12885  }
12886}
12887
12888
12889static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12890    uint32_t index,
12891    const AccessorInfo& info) {
12892  ApiTestFuzzer::Fuzz();
12893  return v8::Handle<Value>();
12894}
12895
12896
12897static v8::Handle<Value> NotHandledIndexedPropertySetter(
12898    uint32_t index,
12899    Local<Value> value,
12900    const AccessorInfo& info) {
12901  ApiTestFuzzer::Fuzz();
12902  return v8::Handle<Value>();
12903}
12904
12905
12906THREADED_TEST(PixelArrayWithInterceptor) {
12907  v8::HandleScope scope;
12908  LocalContext context;
12909  const int kElementCount = 260;
12910  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12911  i::Handle<i::ExternalPixelArray> pixels =
12912      i::Handle<i::ExternalPixelArray>::cast(
12913          FACTORY->NewExternalArray(kElementCount,
12914                                    v8::kExternalPixelArray,
12915                                    pixel_data));
12916  for (int i = 0; i < kElementCount; i++) {
12917    pixels->set(i, i % 256);
12918  }
12919  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12920  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12921                                   NotHandledIndexedPropertySetter);
12922  v8::Handle<v8::Object> obj = templ->NewInstance();
12923  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12924  context->Global()->Set(v8_str("pixels"), obj);
12925  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12926  CHECK_EQ(1, result->Int32Value());
12927  result = CompileRun("var sum = 0;"
12928                      "for (var i = 0; i < 8; i++) {"
12929                      "  sum += pixels[i] = pixels[i] = -i;"
12930                      "}"
12931                      "sum;");
12932  CHECK_EQ(-28, result->Int32Value());
12933  result = CompileRun("pixels.hasOwnProperty('1')");
12934  CHECK(result->BooleanValue());
12935  free(pixel_data);
12936}
12937
12938
12939static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12940  switch (array_type) {
12941    case v8::kExternalByteArray:
12942    case v8::kExternalUnsignedByteArray:
12943    case v8::kExternalPixelArray:
12944      return 1;
12945      break;
12946    case v8::kExternalShortArray:
12947    case v8::kExternalUnsignedShortArray:
12948      return 2;
12949      break;
12950    case v8::kExternalIntArray:
12951    case v8::kExternalUnsignedIntArray:
12952    case v8::kExternalFloatArray:
12953      return 4;
12954      break;
12955    case v8::kExternalDoubleArray:
12956      return 8;
12957      break;
12958    default:
12959      UNREACHABLE();
12960      return -1;
12961  }
12962  UNREACHABLE();
12963  return -1;
12964}
12965
12966
12967template <class ExternalArrayClass, class ElementType>
12968static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12969                                    int64_t low,
12970                                    int64_t high) {
12971  v8::HandleScope scope;
12972  LocalContext context;
12973  const int kElementCount = 40;
12974  int element_size = ExternalArrayElementSize(array_type);
12975  ElementType* array_data =
12976      static_cast<ElementType*>(malloc(kElementCount * element_size));
12977  i::Handle<ExternalArrayClass> array =
12978      i::Handle<ExternalArrayClass>::cast(
12979          FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12980  // Force GC to trigger verification.
12981  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12982  for (int i = 0; i < kElementCount; i++) {
12983    array->set(i, static_cast<ElementType>(i));
12984  }
12985  // Force GC to trigger verification.
12986  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12987  for (int i = 0; i < kElementCount; i++) {
12988    CHECK_EQ(static_cast<int64_t>(i),
12989             static_cast<int64_t>(array->get_scalar(i)));
12990    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12991  }
12992
12993  v8::Handle<v8::Object> obj = v8::Object::New();
12994  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12995  // Set the elements to be the external array.
12996  obj->SetIndexedPropertiesToExternalArrayData(array_data,
12997                                               array_type,
12998                                               kElementCount);
12999  CHECK_EQ(
13000      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
13001  obj->Set(v8_str("field"), v8::Int32::New(1503));
13002  context->Global()->Set(v8_str("ext_array"), obj);
13003  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13004  CHECK_EQ(1503, result->Int32Value());
13005  result = CompileRun("ext_array[1]");
13006  CHECK_EQ(1, result->Int32Value());
13007
13008  // Check pass through of assigned smis
13009  result = CompileRun("var sum = 0;"
13010                      "for (var i = 0; i < 8; i++) {"
13011                      "  sum += ext_array[i] = ext_array[i] = -i;"
13012                      "}"
13013                      "sum;");
13014  CHECK_EQ(-28, result->Int32Value());
13015
13016  // Check assigned smis
13017  result = CompileRun("for (var i = 0; i < 8; i++) {"
13018                      "  ext_array[i] = i;"
13019                      "}"
13020                      "var sum = 0;"
13021                      "for (var i = 0; i < 8; i++) {"
13022                      "  sum += ext_array[i];"
13023                      "}"
13024                      "sum;");
13025  CHECK_EQ(28, result->Int32Value());
13026
13027  // Check assigned smis in reverse order
13028  result = CompileRun("for (var i = 8; --i >= 0; ) {"
13029                      "  ext_array[i] = i;"
13030                      "}"
13031                      "var sum = 0;"
13032                      "for (var i = 0; i < 8; i++) {"
13033                      "  sum += ext_array[i];"
13034                      "}"
13035                      "sum;");
13036  CHECK_EQ(28, result->Int32Value());
13037
13038  // Check pass through of assigned HeapNumbers
13039  result = CompileRun("var sum = 0;"
13040                      "for (var i = 0; i < 16; i+=2) {"
13041                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13042                      "}"
13043                      "sum;");
13044  CHECK_EQ(-28, result->Int32Value());
13045
13046  // Check assigned HeapNumbers
13047  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13048                      "  ext_array[i] = (i * 0.5);"
13049                      "}"
13050                      "var sum = 0;"
13051                      "for (var i = 0; i < 16; i+=2) {"
13052                      "  sum += ext_array[i];"
13053                      "}"
13054                      "sum;");
13055  CHECK_EQ(28, result->Int32Value());
13056
13057  // Check assigned HeapNumbers in reverse order
13058  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13059                      "  ext_array[i] = (i * 0.5);"
13060                      "}"
13061                      "var sum = 0;"
13062                      "for (var i = 0; i < 16; i+=2) {"
13063                      "  sum += ext_array[i];"
13064                      "}"
13065                      "sum;");
13066  CHECK_EQ(28, result->Int32Value());
13067
13068  i::ScopedVector<char> test_buf(1024);
13069
13070  // Check legal boundary conditions.
13071  // The repeated loads and stores ensure the ICs are exercised.
13072  const char* boundary_program =
13073      "var res = 0;"
13074      "for (var i = 0; i < 16; i++) {"
13075      "  ext_array[i] = %lld;"
13076      "  if (i > 8) {"
13077      "    res = ext_array[i];"
13078      "  }"
13079      "}"
13080      "res;";
13081  i::OS::SNPrintF(test_buf,
13082                  boundary_program,
13083                  low);
13084  result = CompileRun(test_buf.start());
13085  CHECK_EQ(low, result->IntegerValue());
13086
13087  i::OS::SNPrintF(test_buf,
13088                  boundary_program,
13089                  high);
13090  result = CompileRun(test_buf.start());
13091  CHECK_EQ(high, result->IntegerValue());
13092
13093  // Check misprediction of type in IC.
13094  result = CompileRun("var tmp_array = ext_array;"
13095                      "var sum = 0;"
13096                      "for (var i = 0; i < 8; i++) {"
13097                      "  tmp_array[i] = i;"
13098                      "  sum += tmp_array[i];"
13099                      "  if (i == 4) {"
13100                      "    tmp_array = {};"
13101                      "  }"
13102                      "}"
13103                      "sum;");
13104  // Force GC to trigger verification.
13105  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13106  CHECK_EQ(28, result->Int32Value());
13107
13108  // Make sure out-of-range loads do not throw.
13109  i::OS::SNPrintF(test_buf,
13110                  "var caught_exception = false;"
13111                  "try {"
13112                  "  ext_array[%d];"
13113                  "} catch (e) {"
13114                  "  caught_exception = true;"
13115                  "}"
13116                  "caught_exception;",
13117                  kElementCount);
13118  result = CompileRun(test_buf.start());
13119  CHECK_EQ(false, result->BooleanValue());
13120
13121  // Make sure out-of-range stores do not throw.
13122  i::OS::SNPrintF(test_buf,
13123                  "var caught_exception = false;"
13124                  "try {"
13125                  "  ext_array[%d] = 1;"
13126                  "} catch (e) {"
13127                  "  caught_exception = true;"
13128                  "}"
13129                  "caught_exception;",
13130                  kElementCount);
13131  result = CompileRun(test_buf.start());
13132  CHECK_EQ(false, result->BooleanValue());
13133
13134  // Check other boundary conditions, values and operations.
13135  result = CompileRun("for (var i = 0; i < 8; i++) {"
13136                      "  ext_array[7] = undefined;"
13137                      "}"
13138                      "ext_array[7];");
13139  CHECK_EQ(0, result->Int32Value());
13140  if (array_type == v8::kExternalDoubleArray ||
13141      array_type == v8::kExternalFloatArray) {
13142    CHECK_EQ(
13143        static_cast<int>(i::OS::nan_value()),
13144        static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13145  } else {
13146    CHECK_EQ(0, static_cast<int>(
13147        jsobj->GetElement(7)->ToObjectChecked()->Number()));
13148  }
13149
13150  result = CompileRun("for (var i = 0; i < 8; i++) {"
13151                      "  ext_array[6] = '2.3';"
13152                      "}"
13153                      "ext_array[6];");
13154  CHECK_EQ(2, result->Int32Value());
13155  CHECK_EQ(
13156      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
13157
13158  if (array_type != v8::kExternalFloatArray &&
13159      array_type != v8::kExternalDoubleArray) {
13160    // Though the specification doesn't state it, be explicit about
13161    // converting NaNs and +/-Infinity to zero.
13162    result = CompileRun("for (var i = 0; i < 8; i++) {"
13163                        "  ext_array[i] = 5;"
13164                        "}"
13165                        "for (var i = 0; i < 8; i++) {"
13166                        "  ext_array[i] = NaN;"
13167                        "}"
13168                        "ext_array[5];");
13169    CHECK_EQ(0, result->Int32Value());
13170    CHECK_EQ(0,
13171             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13172
13173    result = CompileRun("for (var i = 0; i < 8; i++) {"
13174                        "  ext_array[i] = 5;"
13175                        "}"
13176                        "for (var i = 0; i < 8; i++) {"
13177                        "  ext_array[i] = Infinity;"
13178                        "}"
13179                        "ext_array[5];");
13180    int expected_value =
13181        (array_type == v8::kExternalPixelArray) ? 255 : 0;
13182    CHECK_EQ(expected_value, result->Int32Value());
13183    CHECK_EQ(expected_value,
13184             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13185
13186    result = CompileRun("for (var i = 0; i < 8; i++) {"
13187                        "  ext_array[i] = 5;"
13188                        "}"
13189                        "for (var i = 0; i < 8; i++) {"
13190                        "  ext_array[i] = -Infinity;"
13191                        "}"
13192                        "ext_array[5];");
13193    CHECK_EQ(0, result->Int32Value());
13194    CHECK_EQ(0,
13195             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13196
13197    // Check truncation behavior of integral arrays.
13198    const char* unsigned_data =
13199        "var source_data = [0.6, 10.6];"
13200        "var expected_results = [0, 10];";
13201    const char* signed_data =
13202        "var source_data = [0.6, 10.6, -0.6, -10.6];"
13203        "var expected_results = [0, 10, 0, -10];";
13204    const char* pixel_data =
13205        "var source_data = [0.6, 10.6];"
13206        "var expected_results = [1, 11];";
13207    bool is_unsigned =
13208        (array_type == v8::kExternalUnsignedByteArray ||
13209         array_type == v8::kExternalUnsignedShortArray ||
13210         array_type == v8::kExternalUnsignedIntArray);
13211    bool is_pixel_data = array_type == v8::kExternalPixelArray;
13212
13213    i::OS::SNPrintF(test_buf,
13214                    "%s"
13215                    "var all_passed = true;"
13216                    "for (var i = 0; i < source_data.length; i++) {"
13217                    "  for (var j = 0; j < 8; j++) {"
13218                    "    ext_array[j] = source_data[i];"
13219                    "  }"
13220                    "  all_passed = all_passed &&"
13221                    "               (ext_array[5] == expected_results[i]);"
13222                    "}"
13223                    "all_passed;",
13224                    (is_unsigned ?
13225                         unsigned_data :
13226                         (is_pixel_data ? pixel_data : signed_data)));
13227    result = CompileRun(test_buf.start());
13228    CHECK_EQ(true, result->BooleanValue());
13229  }
13230
13231  for (int i = 0; i < kElementCount; i++) {
13232    array->set(i, static_cast<ElementType>(i));
13233  }
13234  // Test complex assignments
13235  result = CompileRun("function ee_op_test_complex_func(sum) {"
13236                      " for (var i = 0; i < 40; ++i) {"
13237                      "   sum += (ext_array[i] += 1);"
13238                      "   sum += (ext_array[i] -= 1);"
13239                      " } "
13240                      " return sum;"
13241                      "}"
13242                      "sum=0;"
13243                      "for (var i=0;i<10000;++i) {"
13244                      "  sum=ee_op_test_complex_func(sum);"
13245                      "}"
13246                      "sum;");
13247  CHECK_EQ(16000000, result->Int32Value());
13248
13249  // Test count operations
13250  result = CompileRun("function ee_op_test_count_func(sum) {"
13251                      " for (var i = 0; i < 40; ++i) {"
13252                      "   sum += (++ext_array[i]);"
13253                      "   sum += (--ext_array[i]);"
13254                      " } "
13255                      " return sum;"
13256                      "}"
13257                      "sum=0;"
13258                      "for (var i=0;i<10000;++i) {"
13259                      "  sum=ee_op_test_count_func(sum);"
13260                      "}"
13261                      "sum;");
13262  CHECK_EQ(16000000, result->Int32Value());
13263
13264  result = CompileRun("ext_array[3] = 33;"
13265                      "delete ext_array[3];"
13266                      "ext_array[3];");
13267  CHECK_EQ(33, result->Int32Value());
13268
13269  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13270                      "ext_array[2] = 12; ext_array[3] = 13;"
13271                      "ext_array.__defineGetter__('2',"
13272                      "function() { return 120; });"
13273                      "ext_array[2];");
13274  CHECK_EQ(12, result->Int32Value());
13275
13276  result = CompileRun("var js_array = new Array(40);"
13277                      "js_array[0] = 77;"
13278                      "js_array;");
13279  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13280
13281  result = CompileRun("ext_array[1] = 23;"
13282                      "ext_array.__proto__ = [];"
13283                      "js_array.__proto__ = ext_array;"
13284                      "js_array.concat(ext_array);");
13285  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13286  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13287
13288  result = CompileRun("ext_array[1] = 23;");
13289  CHECK_EQ(23, result->Int32Value());
13290
13291  // Test more complex manipulations which cause eax to contain values
13292  // that won't be completely overwritten by loads from the arrays.
13293  // This catches bugs in the instructions used for the KeyedLoadIC
13294  // for byte and word types.
13295  {
13296    const int kXSize = 300;
13297    const int kYSize = 300;
13298    const int kLargeElementCount = kXSize * kYSize * 4;
13299    ElementType* large_array_data =
13300        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
13301    v8::Handle<v8::Object> large_obj = v8::Object::New();
13302    // Set the elements to be the external array.
13303    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13304                                                       array_type,
13305                                                       kLargeElementCount);
13306    context->Global()->Set(v8_str("large_array"), large_obj);
13307    // Initialize contents of a few rows.
13308    for (int x = 0; x < 300; x++) {
13309      int row = 0;
13310      int offset = row * 300 * 4;
13311      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13312      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13313      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13314      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13315      row = 150;
13316      offset = row * 300 * 4;
13317      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13318      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13319      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13320      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13321      row = 298;
13322      offset = row * 300 * 4;
13323      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13324      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13325      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13326      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13327    }
13328    // The goal of the code below is to make "offset" large enough
13329    // that the computation of the index (which goes into eax) has
13330    // high bits set which will not be overwritten by a byte or short
13331    // load.
13332    result = CompileRun("var failed = false;"
13333                        "var offset = 0;"
13334                        "for (var i = 0; i < 300; i++) {"
13335                        "  if (large_array[4 * i] != 127 ||"
13336                        "      large_array[4 * i + 1] != 0 ||"
13337                        "      large_array[4 * i + 2] != 0 ||"
13338                        "      large_array[4 * i + 3] != 127) {"
13339                        "    failed = true;"
13340                        "  }"
13341                        "}"
13342                        "offset = 150 * 300 * 4;"
13343                        "for (var i = 0; i < 300; i++) {"
13344                        "  if (large_array[offset + 4 * i] != 127 ||"
13345                        "      large_array[offset + 4 * i + 1] != 0 ||"
13346                        "      large_array[offset + 4 * i + 2] != 0 ||"
13347                        "      large_array[offset + 4 * i + 3] != 127) {"
13348                        "    failed = true;"
13349                        "  }"
13350                        "}"
13351                        "offset = 298 * 300 * 4;"
13352                        "for (var i = 0; i < 300; i++) {"
13353                        "  if (large_array[offset + 4 * i] != 127 ||"
13354                        "      large_array[offset + 4 * i + 1] != 0 ||"
13355                        "      large_array[offset + 4 * i + 2] != 0 ||"
13356                        "      large_array[offset + 4 * i + 3] != 127) {"
13357                        "    failed = true;"
13358                        "  }"
13359                        "}"
13360                        "!failed;");
13361    CHECK_EQ(true, result->BooleanValue());
13362    free(large_array_data);
13363  }
13364
13365  // The "" property descriptor is overloaded to store information about
13366  // the external array. Ensure that setting and accessing the "" property
13367  // works (it should overwrite the information cached about the external
13368  // array in the DescriptorArray) in various situations.
13369  result = CompileRun("ext_array[''] = 23; ext_array['']");
13370  CHECK_EQ(23, result->Int32Value());
13371
13372  // Property "" set after the external array is associated with the object.
13373  {
13374    v8::Handle<v8::Object> obj2 = v8::Object::New();
13375    obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13376    obj2->Set(v8_str(""), v8::Int32::New(1503));
13377    // Set the elements to be the external array.
13378    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13379                                                  array_type,
13380                                                  kElementCount);
13381    context->Global()->Set(v8_str("ext_array"), obj2);
13382    result = CompileRun("ext_array['']");
13383    CHECK_EQ(1503, result->Int32Value());
13384  }
13385
13386  // Property "" set after the external array is associated with the object.
13387  {
13388    v8::Handle<v8::Object> obj2 = v8::Object::New();
13389    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13390    // Set the elements to be the external array.
13391    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13392                                                  array_type,
13393                                                  kElementCount);
13394    obj2->Set(v8_str(""), v8::Int32::New(1503));
13395    context->Global()->Set(v8_str("ext_array"), obj2);
13396    result = CompileRun("ext_array['']");
13397    CHECK_EQ(1503, result->Int32Value());
13398  }
13399
13400  // Should reuse the map from previous test.
13401  {
13402    v8::Handle<v8::Object> obj2 = v8::Object::New();
13403    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13404    // Set the elements to be the external array. Should re-use the map
13405    // from previous test.
13406    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13407                                                  array_type,
13408                                                  kElementCount);
13409    context->Global()->Set(v8_str("ext_array"), obj2);
13410    result = CompileRun("ext_array['']");
13411  }
13412
13413  // Property "" is a constant function that shouldn't not be interfered with
13414  // when an external array is set.
13415  {
13416    v8::Handle<v8::Object> obj2 = v8::Object::New();
13417    // Start
13418    obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13419
13420    // Add a constant function to an object.
13421    context->Global()->Set(v8_str("ext_array"), obj2);
13422    result = CompileRun("ext_array[''] = function() {return 1503;};"
13423                        "ext_array['']();");
13424
13425    // Add an external array transition to the same map that
13426    // has the constant transition.
13427    v8::Handle<v8::Object> obj3 = v8::Object::New();
13428    obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13429    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13430                                                  array_type,
13431                                                  kElementCount);
13432    context->Global()->Set(v8_str("ext_array"), obj3);
13433  }
13434
13435  // If a external array transition is in the map, it should get clobbered
13436  // by a constant function.
13437  {
13438    // Add an external array transition.
13439    v8::Handle<v8::Object> obj3 = v8::Object::New();
13440    obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13441    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13442                                                  array_type,
13443                                                  kElementCount);
13444
13445    // Add a constant function to the same map that just got an external array
13446    // transition.
13447    v8::Handle<v8::Object> obj2 = v8::Object::New();
13448    obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13449    context->Global()->Set(v8_str("ext_array"), obj2);
13450    result = CompileRun("ext_array[''] = function() {return 1503;};"
13451                        "ext_array['']();");
13452  }
13453
13454  free(array_data);
13455}
13456
13457
13458THREADED_TEST(ExternalByteArray) {
13459  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
13460      v8::kExternalByteArray,
13461      -128,
13462      127);
13463}
13464
13465
13466THREADED_TEST(ExternalUnsignedByteArray) {
13467  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
13468      v8::kExternalUnsignedByteArray,
13469      0,
13470      255);
13471}
13472
13473
13474THREADED_TEST(ExternalPixelArray) {
13475  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13476      v8::kExternalPixelArray,
13477      0,
13478      255);
13479}
13480
13481
13482THREADED_TEST(ExternalShortArray) {
13483  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
13484      v8::kExternalShortArray,
13485      -32768,
13486      32767);
13487}
13488
13489
13490THREADED_TEST(ExternalUnsignedShortArray) {
13491  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
13492      v8::kExternalUnsignedShortArray,
13493      0,
13494      65535);
13495}
13496
13497
13498THREADED_TEST(ExternalIntArray) {
13499  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
13500      v8::kExternalIntArray,
13501      INT_MIN,   // -2147483648
13502      INT_MAX);  //  2147483647
13503}
13504
13505
13506THREADED_TEST(ExternalUnsignedIntArray) {
13507  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
13508      v8::kExternalUnsignedIntArray,
13509      0,
13510      UINT_MAX);  // 4294967295
13511}
13512
13513
13514THREADED_TEST(ExternalFloatArray) {
13515  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
13516      v8::kExternalFloatArray,
13517      -500,
13518      500);
13519}
13520
13521
13522THREADED_TEST(ExternalDoubleArray) {
13523  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13524      v8::kExternalDoubleArray,
13525      -500,
13526      500);
13527}
13528
13529
13530THREADED_TEST(ExternalArrays) {
13531  TestExternalByteArray();
13532  TestExternalUnsignedByteArray();
13533  TestExternalShortArray();
13534  TestExternalUnsignedShortArray();
13535  TestExternalIntArray();
13536  TestExternalUnsignedIntArray();
13537  TestExternalFloatArray();
13538}
13539
13540
13541void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13542  v8::HandleScope scope;
13543  LocalContext context;
13544  for (int size = 0; size < 100; size += 10) {
13545    int element_size = ExternalArrayElementSize(array_type);
13546    void* external_data = malloc(size * element_size);
13547    v8::Handle<v8::Object> obj = v8::Object::New();
13548    obj->SetIndexedPropertiesToExternalArrayData(
13549        external_data, array_type, size);
13550    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13551    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13552    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13553    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13554    free(external_data);
13555  }
13556}
13557
13558
13559THREADED_TEST(ExternalArrayInfo) {
13560  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13561  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13562  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13563  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13564  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13565  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13566  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
13567  ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
13568  ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
13569}
13570
13571
13572THREADED_TEST(ScriptContextDependence) {
13573  v8::HandleScope scope;
13574  LocalContext c1;
13575  const char *source = "foo";
13576  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13577  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13578  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13579  CHECK_EQ(dep->Run()->Int32Value(), 100);
13580  CHECK_EQ(indep->Run()->Int32Value(), 100);
13581  LocalContext c2;
13582  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13583  CHECK_EQ(dep->Run()->Int32Value(), 100);
13584  CHECK_EQ(indep->Run()->Int32Value(), 101);
13585}
13586
13587
13588THREADED_TEST(StackTrace) {
13589  v8::HandleScope scope;
13590  LocalContext context;
13591  v8::TryCatch try_catch;
13592  const char *source = "function foo() { FAIL.FAIL; }; foo();";
13593  v8::Handle<v8::String> src = v8::String::New(source);
13594  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13595  v8::Script::New(src, origin)->Run();
13596  CHECK(try_catch.HasCaught());
13597  v8::String::Utf8Value stack(try_catch.StackTrace());
13598  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13599}
13600
13601
13602// Checks that a StackFrame has certain expected values.
13603void checkStackFrame(const char* expected_script_name,
13604    const char* expected_func_name, int expected_line_number,
13605    int expected_column, bool is_eval, bool is_constructor,
13606    v8::Handle<v8::StackFrame> frame) {
13607  v8::HandleScope scope;
13608  v8::String::Utf8Value func_name(frame->GetFunctionName());
13609  v8::String::Utf8Value script_name(frame->GetScriptName());
13610  if (*script_name == NULL) {
13611    // The situation where there is no associated script, like for evals.
13612    CHECK(expected_script_name == NULL);
13613  } else {
13614    CHECK(strstr(*script_name, expected_script_name) != NULL);
13615  }
13616  CHECK(strstr(*func_name, expected_func_name) != NULL);
13617  CHECK_EQ(expected_line_number, frame->GetLineNumber());
13618  CHECK_EQ(expected_column, frame->GetColumn());
13619  CHECK_EQ(is_eval, frame->IsEval());
13620  CHECK_EQ(is_constructor, frame->IsConstructor());
13621}
13622
13623
13624v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13625  v8::HandleScope scope;
13626  const char* origin = "capture-stack-trace-test";
13627  const int kOverviewTest = 1;
13628  const int kDetailedTest = 2;
13629
13630  ASSERT(args.Length() == 1);
13631
13632  int testGroup = args[0]->Int32Value();
13633  if (testGroup == kOverviewTest) {
13634    v8::Handle<v8::StackTrace> stackTrace =
13635        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13636    CHECK_EQ(4, stackTrace->GetFrameCount());
13637    checkStackFrame(origin, "bar", 2, 10, false, false,
13638                    stackTrace->GetFrame(0));
13639    checkStackFrame(origin, "foo", 6, 3, false, false,
13640                    stackTrace->GetFrame(1));
13641    // This is the source string inside the eval which has the call to foo.
13642    checkStackFrame(NULL, "", 1, 5, false, false,
13643                    stackTrace->GetFrame(2));
13644    // The last frame is an anonymous function which has the initial eval call.
13645    checkStackFrame(origin, "", 8, 7, false, false,
13646                    stackTrace->GetFrame(3));
13647
13648    CHECK(stackTrace->AsArray()->IsArray());
13649  } else if (testGroup == kDetailedTest) {
13650    v8::Handle<v8::StackTrace> stackTrace =
13651        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13652    CHECK_EQ(4, stackTrace->GetFrameCount());
13653    checkStackFrame(origin, "bat", 4, 22, false, false,
13654                    stackTrace->GetFrame(0));
13655    checkStackFrame(origin, "baz", 8, 3, false, true,
13656                    stackTrace->GetFrame(1));
13657#ifdef ENABLE_DEBUGGER_SUPPORT
13658    bool is_eval = true;
13659#else  // ENABLE_DEBUGGER_SUPPORT
13660    bool is_eval = false;
13661#endif  // ENABLE_DEBUGGER_SUPPORT
13662
13663    // This is the source string inside the eval which has the call to baz.
13664    checkStackFrame(NULL, "", 1, 5, is_eval, false,
13665                    stackTrace->GetFrame(2));
13666    // The last frame is an anonymous function which has the initial eval call.
13667    checkStackFrame(origin, "", 10, 1, false, false,
13668                    stackTrace->GetFrame(3));
13669
13670    CHECK(stackTrace->AsArray()->IsArray());
13671  }
13672  return v8::Undefined();
13673}
13674
13675
13676// Tests the C++ StackTrace API.
13677// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13678// THREADED_TEST(CaptureStackTrace) {
13679TEST(CaptureStackTrace) {
13680  v8::HandleScope scope;
13681  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13682  Local<ObjectTemplate> templ = ObjectTemplate::New();
13683  templ->Set(v8_str("AnalyzeStackInNativeCode"),
13684             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13685  LocalContext context(0, templ);
13686
13687  // Test getting OVERVIEW information. Should ignore information that is not
13688  // script name, function name, line number, and column offset.
13689  const char *overview_source =
13690    "function bar() {\n"
13691    "  var y; AnalyzeStackInNativeCode(1);\n"
13692    "}\n"
13693    "function foo() {\n"
13694    "\n"
13695    "  bar();\n"
13696    "}\n"
13697    "var x;eval('new foo();');";
13698  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
13699  v8::Handle<Value> overview_result(
13700      v8::Script::New(overview_src, origin)->Run());
13701  CHECK(!overview_result.IsEmpty());
13702  CHECK(overview_result->IsObject());
13703
13704  // Test getting DETAILED information.
13705  const char *detailed_source =
13706    "function bat() {AnalyzeStackInNativeCode(2);\n"
13707    "}\n"
13708    "\n"
13709    "function baz() {\n"
13710    "  bat();\n"
13711    "}\n"
13712    "eval('new baz();');";
13713  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13714  // Make the script using a non-zero line and column offset.
13715  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13716  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13717  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13718  v8::Handle<v8::Script> detailed_script(
13719      v8::Script::New(detailed_src, &detailed_origin));
13720  v8::Handle<Value> detailed_result(detailed_script->Run());
13721  CHECK(!detailed_result.IsEmpty());
13722  CHECK(detailed_result->IsObject());
13723}
13724
13725
13726static void StackTraceForUncaughtExceptionListener(
13727    v8::Handle<v8::Message> message,
13728    v8::Handle<Value>) {
13729  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13730  CHECK_EQ(2, stack_trace->GetFrameCount());
13731  checkStackFrame("origin", "foo", 2, 3, false, false,
13732                  stack_trace->GetFrame(0));
13733  checkStackFrame("origin", "bar", 5, 3, false, false,
13734                  stack_trace->GetFrame(1));
13735}
13736
13737TEST(CaptureStackTraceForUncaughtException) {
13738  report_count = 0;
13739  v8::HandleScope scope;
13740  LocalContext env;
13741  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13742  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13743
13744  Script::Compile(v8_str("function foo() {\n"
13745                         "  throw 1;\n"
13746                         "};\n"
13747                         "function bar() {\n"
13748                         "  foo();\n"
13749                         "};"),
13750                  v8_str("origin"))->Run();
13751  v8::Local<v8::Object> global = env->Global();
13752  Local<Value> trouble = global->Get(v8_str("bar"));
13753  CHECK(trouble->IsFunction());
13754  Function::Cast(*trouble)->Call(global, 0, NULL);
13755  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13756  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13757}
13758
13759
13760TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13761  v8::HandleScope scope;
13762  LocalContext env;
13763  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13764                                                    1024,
13765                                                    v8::StackTrace::kDetailed);
13766
13767  CompileRun(
13768      "var setters = ['column', 'lineNumber', 'scriptName',\n"
13769      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13770      "    'isConstructor'];\n"
13771      "for (var i = 0; i < setters.length; i++) {\n"
13772      "  var prop = setters[i];\n"
13773      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13774      "}\n");
13775  CompileRun("throw 'exception';");
13776  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13777}
13778
13779
13780static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
13781                                     v8::Handle<v8::Value> data) {
13782  // Use the frame where JavaScript is called from.
13783  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13784  CHECK(!stack_trace.IsEmpty());
13785  int frame_count = stack_trace->GetFrameCount();
13786  CHECK_EQ(3, frame_count);
13787  int line_number[] = {1, 2, 5};
13788  for (int i = 0; i < frame_count; i++) {
13789    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13790  }
13791}
13792
13793
13794// Test that we only return the stack trace at the site where the exception
13795// is first thrown (not where it is rethrown).
13796TEST(RethrowStackTrace) {
13797  v8::HandleScope scope;
13798  LocalContext env;
13799  // We make sure that
13800  // - the stack trace of the ReferenceError in g() is reported.
13801  // - the stack trace is not overwritten when e1 is rethrown by t().
13802  // - the stack trace of e2 does not overwrite that of e1.
13803  const char* source =
13804      "function g() { error; }          \n"
13805      "function f() { g(); }            \n"
13806      "function t(e) { throw e; }       \n"
13807      "try {                            \n"
13808      "  f();                           \n"
13809      "} catch (e1) {                   \n"
13810      "  try {                          \n"
13811      "    error;                       \n"
13812      "  } catch (e2) {                 \n"
13813      "    t(e1);                       \n"
13814      "  }                              \n"
13815      "}                                \n";
13816  v8::V8::AddMessageListener(RethrowStackTraceHandler);
13817  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13818  CompileRun(source);
13819  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13820  v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
13821}
13822
13823
13824static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
13825                                              v8::Handle<v8::Value> data) {
13826  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13827  CHECK(!stack_trace.IsEmpty());
13828  int frame_count = stack_trace->GetFrameCount();
13829  CHECK_EQ(2, frame_count);
13830  int line_number[] = {3, 7};
13831  for (int i = 0; i < frame_count; i++) {
13832    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
13833  }
13834}
13835
13836
13837// Test that we do not recognize identity for primitive exceptions.
13838TEST(RethrowPrimitiveStackTrace) {
13839  v8::HandleScope scope;
13840  LocalContext env;
13841  // We do not capture stack trace for non Error objects on creation time.
13842  // Instead, we capture the stack trace on last throw.
13843  const char* source =
13844      "function g() { throw 404; }      \n"
13845      "function f() { g(); }            \n"
13846      "function t(e) { throw e; }       \n"
13847      "try {                            \n"
13848      "  f();                           \n"
13849      "} catch (e1) {                   \n"
13850      "  t(e1)                          \n"
13851      "}                                \n";
13852  v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
13853  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13854  CompileRun(source);
13855  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13856  v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
13857}
13858
13859
13860static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
13861                                              v8::Handle<v8::Value> data) {
13862  // Use the frame where JavaScript is called from.
13863  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13864  CHECK(!stack_trace.IsEmpty());
13865  CHECK_EQ(1, stack_trace->GetFrameCount());
13866  CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
13867}
13868
13869
13870// Test that the stack trace is captured when the error object is created and
13871// not where it is thrown.
13872TEST(RethrowExistingStackTrace) {
13873  v8::HandleScope scope;
13874  LocalContext env;
13875  const char* source =
13876      "var e = new Error();           \n"
13877      "throw e;                       \n";
13878  v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
13879  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13880  CompileRun(source);
13881  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13882  v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
13883}
13884
13885
13886static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
13887                                               v8::Handle<v8::Value> data) {
13888  // Use the frame where JavaScript is called from.
13889  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13890  CHECK(!stack_trace.IsEmpty());
13891  CHECK_EQ(1, stack_trace->GetFrameCount());
13892  CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
13893}
13894
13895
13896// Test that the stack trace is captured where the bogus Error object is thrown.
13897TEST(RethrowBogusErrorStackTrace) {
13898  v8::HandleScope scope;
13899  LocalContext env;
13900  const char* source =
13901      "var e = {__proto__: new Error()} \n"
13902      "throw e;                         \n";
13903  v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
13904  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13905  CompileRun(source);
13906  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13907  v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
13908}
13909
13910
13911v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13912  v8::HandleScope scope;
13913  v8::Handle<v8::StackTrace> stackTrace =
13914      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13915  CHECK_EQ(5, stackTrace->GetFrameCount());
13916  v8::Handle<v8::String> url = v8_str("eval_url");
13917  for (int i = 0; i < 3; i++) {
13918    v8::Handle<v8::String> name =
13919        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13920    CHECK(!name.IsEmpty());
13921    CHECK_EQ(url, name);
13922  }
13923  return v8::Undefined();
13924}
13925
13926
13927TEST(SourceURLInStackTrace) {
13928  v8::HandleScope scope;
13929  Local<ObjectTemplate> templ = ObjectTemplate::New();
13930  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13931             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13932  LocalContext context(0, templ);
13933
13934  const char *source =
13935    "function outer() {\n"
13936    "function bar() {\n"
13937    "  AnalyzeStackOfEvalWithSourceURL();\n"
13938    "}\n"
13939    "function foo() {\n"
13940    "\n"
13941    "  bar();\n"
13942    "}\n"
13943    "foo();\n"
13944    "}\n"
13945    "eval('(' + outer +')()//@ sourceURL=eval_url');";
13946  CHECK(CompileRun(source)->IsUndefined());
13947}
13948
13949
13950// Test that idle notification can be handled and eventually returns true.
13951// This just checks the contract of the IdleNotification() function,
13952// and does not verify that it does reasonable work.
13953THREADED_TEST(IdleNotification) {
13954  v8::HandleScope scope;
13955  LocalContext env;
13956  {
13957    // Create garbage in old-space to generate work for idle notification.
13958    i::AlwaysAllocateScope always_allocate;
13959    for (int i = 0; i < 100; i++) {
13960      FACTORY->NewFixedArray(1000, i::TENURED);
13961    }
13962  }
13963  bool finshed_idle_work = false;
13964  for (int i = 0; i < 100 && !finshed_idle_work; i++) {
13965    finshed_idle_work = v8::V8::IdleNotification();
13966  }
13967  CHECK(finshed_idle_work);
13968}
13969
13970// Test that idle notification can be handled and eventually returns true.
13971// This just checks the contract of the IdleNotification() function,
13972// and does not verify that it does reasonable work.
13973TEST(IdleNotificationWithSmallHint) {
13974  v8::HandleScope scope;
13975  LocalContext env;
13976  {
13977    // Create garbage in old-space to generate work for idle notification.
13978    i::AlwaysAllocateScope always_allocate;
13979    for (int i = 0; i < 100; i++) {
13980      FACTORY->NewFixedArray(1000, i::TENURED);
13981    }
13982  }
13983  intptr_t old_size = HEAP->SizeOfObjects();
13984  bool finshed_idle_work = false;
13985  bool no_idle_work = v8::V8::IdleNotification(10);
13986  for (int i = 0; i < 200 && !finshed_idle_work; i++) {
13987    finshed_idle_work = v8::V8::IdleNotification(10);
13988  }
13989  intptr_t new_size = HEAP->SizeOfObjects();
13990  CHECK(finshed_idle_work);
13991  CHECK(no_idle_work || new_size < old_size);
13992}
13993
13994
13995// This just checks the contract of the IdleNotification() function,
13996// and does not verify that it does reasonable work.
13997TEST(IdleNotificationWithLargeHint) {
13998  v8::HandleScope scope;
13999  LocalContext env;
14000  {
14001    // Create garbage in old-space to generate work for idle notification.
14002    i::AlwaysAllocateScope always_allocate;
14003    for (int i = 0; i < 100; i++) {
14004      FACTORY->NewFixedArray(1000, i::TENURED);
14005    }
14006  }
14007  intptr_t old_size = HEAP->SizeOfObjects();
14008  bool finshed_idle_work = false;
14009  bool no_idle_work = v8::V8::IdleNotification(900);
14010  for (int i = 0; i < 200 && !finshed_idle_work; i++) {
14011    finshed_idle_work = v8::V8::IdleNotification(900);
14012  }
14013  intptr_t new_size = HEAP->SizeOfObjects();
14014  CHECK(finshed_idle_work);
14015  CHECK(no_idle_work || new_size < old_size);
14016}
14017
14018
14019static uint32_t* stack_limit;
14020
14021static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
14022  stack_limit = reinterpret_cast<uint32_t*>(
14023      i::Isolate::Current()->stack_guard()->real_climit());
14024  return v8::Undefined();
14025}
14026
14027
14028// Uses the address of a local variable to determine the stack top now.
14029// Given a size, returns an address that is that far from the current
14030// top of stack.
14031static uint32_t* ComputeStackLimit(uint32_t size) {
14032  uint32_t* answer = &size - (size / sizeof(size));
14033  // If the size is very large and the stack is very near the bottom of
14034  // memory then the calculation above may wrap around and give an address
14035  // that is above the (downwards-growing) stack.  In that case we return
14036  // a very low address.
14037  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14038  return answer;
14039}
14040
14041
14042TEST(SetResourceConstraints) {
14043  static const int K = 1024;
14044  uint32_t* set_limit = ComputeStackLimit(128 * K);
14045
14046  // Set stack limit.
14047  v8::ResourceConstraints constraints;
14048  constraints.set_stack_limit(set_limit);
14049  CHECK(v8::SetResourceConstraints(&constraints));
14050
14051  // Execute a script.
14052  v8::HandleScope scope;
14053  LocalContext env;
14054  Local<v8::FunctionTemplate> fun_templ =
14055      v8::FunctionTemplate::New(GetStackLimitCallback);
14056  Local<Function> fun = fun_templ->GetFunction();
14057  env->Global()->Set(v8_str("get_stack_limit"), fun);
14058  CompileRun("get_stack_limit();");
14059
14060  CHECK(stack_limit == set_limit);
14061}
14062
14063
14064TEST(SetResourceConstraintsInThread) {
14065  uint32_t* set_limit;
14066  {
14067    v8::Locker locker;
14068    static const int K = 1024;
14069    set_limit = ComputeStackLimit(128 * K);
14070
14071    // Set stack limit.
14072    v8::ResourceConstraints constraints;
14073    constraints.set_stack_limit(set_limit);
14074    CHECK(v8::SetResourceConstraints(&constraints));
14075
14076    // Execute a script.
14077    v8::HandleScope scope;
14078    LocalContext env;
14079    Local<v8::FunctionTemplate> fun_templ =
14080        v8::FunctionTemplate::New(GetStackLimitCallback);
14081    Local<Function> fun = fun_templ->GetFunction();
14082    env->Global()->Set(v8_str("get_stack_limit"), fun);
14083    CompileRun("get_stack_limit();");
14084
14085    CHECK(stack_limit == set_limit);
14086  }
14087  {
14088    v8::Locker locker;
14089    CHECK(stack_limit == set_limit);
14090  }
14091}
14092
14093
14094THREADED_TEST(GetHeapStatistics) {
14095  v8::HandleScope scope;
14096  LocalContext c1;
14097  v8::HeapStatistics heap_statistics;
14098  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14099  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
14100  v8::V8::GetHeapStatistics(&heap_statistics);
14101  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14102  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
14103}
14104
14105
14106class VisitorImpl : public v8::ExternalResourceVisitor {
14107 public:
14108  VisitorImpl(TestResource* r1, TestResource* r2)
14109      : resource1_(r1),
14110        resource2_(r2),
14111        found_resource1_(false),
14112        found_resource2_(false) {}
14113  virtual ~VisitorImpl() {}
14114  virtual void VisitExternalString(v8::Handle<v8::String> string) {
14115    if (!string->IsExternal()) {
14116      CHECK(string->IsExternalAscii());
14117      return;
14118    }
14119    v8::String::ExternalStringResource* resource =
14120        string->GetExternalStringResource();
14121    CHECK(resource);
14122    if (resource1_ == resource) {
14123      CHECK(!found_resource1_);
14124      found_resource1_ = true;
14125    }
14126    if (resource2_ == resource) {
14127      CHECK(!found_resource2_);
14128      found_resource2_ = true;
14129    }
14130  }
14131  void CheckVisitedResources() {
14132    CHECK(found_resource1_);
14133    CHECK(found_resource2_);
14134  }
14135
14136 private:
14137  v8::String::ExternalStringResource* resource1_;
14138  v8::String::ExternalStringResource* resource2_;
14139  bool found_resource1_;
14140  bool found_resource2_;
14141};
14142
14143TEST(VisitExternalStrings) {
14144  v8::HandleScope scope;
14145  LocalContext env;
14146  const char* string = "Some string";
14147  uint16_t* two_byte_string = AsciiToTwoByteString(string);
14148  TestResource* resource1 = new TestResource(two_byte_string);
14149  v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
14150  TestResource* resource2 = new TestResource(two_byte_string);
14151  v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
14152
14153  // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
14154  CHECK(string1->IsExternal());
14155  CHECK(string2->IsExternal());
14156
14157  VisitorImpl visitor(resource1, resource2);
14158  v8::V8::VisitExternalResources(&visitor);
14159  visitor.CheckVisitedResources();
14160}
14161
14162
14163static double DoubleFromBits(uint64_t value) {
14164  double target;
14165  memcpy(&target, &value, sizeof(target));
14166  return target;
14167}
14168
14169
14170static uint64_t DoubleToBits(double value) {
14171  uint64_t target;
14172  memcpy(&target, &value, sizeof(target));
14173  return target;
14174}
14175
14176
14177static double DoubleToDateTime(double input) {
14178  double date_limit = 864e13;
14179  if (IsNaN(input) || input < -date_limit || input > date_limit) {
14180    return i::OS::nan_value();
14181  }
14182  return (input < 0) ? -(floor(-input)) : floor(input);
14183}
14184
14185// We don't have a consistent way to write 64-bit constants syntactically, so we
14186// split them into two 32-bit constants and combine them programmatically.
14187static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
14188  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
14189}
14190
14191
14192THREADED_TEST(QuietSignalingNaNs) {
14193  v8::HandleScope scope;
14194  LocalContext context;
14195  v8::TryCatch try_catch;
14196
14197  // Special double values.
14198  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
14199  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
14200  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
14201  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
14202  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
14203  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
14204  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
14205
14206  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
14207  // on either side of the epoch.
14208  double date_limit = 864e13;
14209
14210  double test_values[] = {
14211      snan,
14212      qnan,
14213      infinity,
14214      max_normal,
14215      date_limit + 1,
14216      date_limit,
14217      min_normal,
14218      max_denormal,
14219      min_denormal,
14220      0,
14221      -0,
14222      -min_denormal,
14223      -max_denormal,
14224      -min_normal,
14225      -date_limit,
14226      -date_limit - 1,
14227      -max_normal,
14228      -infinity,
14229      -qnan,
14230      -snan
14231  };
14232  int num_test_values = 20;
14233
14234  for (int i = 0; i < num_test_values; i++) {
14235    double test_value = test_values[i];
14236
14237    // Check that Number::New preserves non-NaNs and quiets SNaNs.
14238    v8::Handle<v8::Value> number = v8::Number::New(test_value);
14239    double stored_number = number->NumberValue();
14240    if (!IsNaN(test_value)) {
14241      CHECK_EQ(test_value, stored_number);
14242    } else {
14243      uint64_t stored_bits = DoubleToBits(stored_number);
14244      // Check if quiet nan (bits 51..62 all set).
14245#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14246      // Most significant fraction bit for quiet nan is set to 0
14247      // on MIPS architecture. Allowed by IEEE-754.
14248      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14249#else
14250      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14251#endif
14252    }
14253
14254    // Check that Date::New preserves non-NaNs in the date range and
14255    // quiets SNaNs.
14256    v8::Handle<v8::Value> date = v8::Date::New(test_value);
14257    double expected_stored_date = DoubleToDateTime(test_value);
14258    double stored_date = date->NumberValue();
14259    if (!IsNaN(expected_stored_date)) {
14260      CHECK_EQ(expected_stored_date, stored_date);
14261    } else {
14262      uint64_t stored_bits = DoubleToBits(stored_date);
14263      // Check if quiet nan (bits 51..62 all set).
14264#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14265      // Most significant fraction bit for quiet nan is set to 0
14266      // on MIPS architecture. Allowed by IEEE-754.
14267      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14268#else
14269      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14270#endif
14271    }
14272  }
14273}
14274
14275
14276static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14277  v8::HandleScope scope;
14278  v8::TryCatch tc;
14279  v8::Handle<v8::String> str(args[0]->ToString());
14280  USE(str);
14281  if (tc.HasCaught())
14282    return tc.ReThrow();
14283  return v8::Undefined();
14284}
14285
14286
14287// Test that an exception can be propagated down through a spaghetti
14288// stack using ReThrow.
14289THREADED_TEST(SpaghettiStackReThrow) {
14290  v8::HandleScope scope;
14291  LocalContext context;
14292  context->Global()->Set(
14293      v8::String::New("s"),
14294      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
14295  v8::TryCatch try_catch;
14296  CompileRun(
14297      "var i = 0;"
14298      "var o = {"
14299      "  toString: function () {"
14300      "    if (i == 10) {"
14301      "      throw 'Hey!';"
14302      "    } else {"
14303      "      i++;"
14304      "      return s(o);"
14305      "    }"
14306      "  }"
14307      "};"
14308      "s(o);");
14309  CHECK(try_catch.HasCaught());
14310  v8::String::Utf8Value value(try_catch.Exception());
14311  CHECK_EQ(0, strcmp(*value, "Hey!"));
14312}
14313
14314
14315TEST(Regress528) {
14316  v8::V8::Initialize();
14317
14318  v8::HandleScope scope;
14319  v8::Persistent<Context> context;
14320  v8::Persistent<Context> other_context;
14321  int gc_count;
14322
14323  // Create a context used to keep the code from aging in the compilation
14324  // cache.
14325  other_context = Context::New();
14326
14327  // Context-dependent context data creates reference from the compilation
14328  // cache to the global object.
14329  const char* source_simple = "1";
14330  context = Context::New();
14331  {
14332    v8::HandleScope scope;
14333
14334    context->Enter();
14335    Local<v8::String> obj = v8::String::New("");
14336    context->SetData(obj);
14337    CompileRun(source_simple);
14338    context->Exit();
14339  }
14340  context.Dispose();
14341  for (gc_count = 1; gc_count < 10; gc_count++) {
14342    other_context->Enter();
14343    CompileRun(source_simple);
14344    other_context->Exit();
14345    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14346    if (GetGlobalObjectsCount() == 1) break;
14347  }
14348  CHECK_GE(2, gc_count);
14349  CHECK_EQ(1, GetGlobalObjectsCount());
14350
14351  // Eval in a function creates reference from the compilation cache to the
14352  // global object.
14353  const char* source_eval = "function f(){eval('1')}; f()";
14354  context = Context::New();
14355  {
14356    v8::HandleScope scope;
14357
14358    context->Enter();
14359    CompileRun(source_eval);
14360    context->Exit();
14361  }
14362  context.Dispose();
14363  for (gc_count = 1; gc_count < 10; gc_count++) {
14364    other_context->Enter();
14365    CompileRun(source_eval);
14366    other_context->Exit();
14367    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14368    if (GetGlobalObjectsCount() == 1) break;
14369  }
14370  CHECK_GE(2, gc_count);
14371  CHECK_EQ(1, GetGlobalObjectsCount());
14372
14373  // Looking up the line number for an exception creates reference from the
14374  // compilation cache to the global object.
14375  const char* source_exception = "function f(){throw 1;} f()";
14376  context = Context::New();
14377  {
14378    v8::HandleScope scope;
14379
14380    context->Enter();
14381    v8::TryCatch try_catch;
14382    CompileRun(source_exception);
14383    CHECK(try_catch.HasCaught());
14384    v8::Handle<v8::Message> message = try_catch.Message();
14385    CHECK(!message.IsEmpty());
14386    CHECK_EQ(1, message->GetLineNumber());
14387    context->Exit();
14388  }
14389  context.Dispose();
14390  for (gc_count = 1; gc_count < 10; gc_count++) {
14391    other_context->Enter();
14392    CompileRun(source_exception);
14393    other_context->Exit();
14394    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14395    if (GetGlobalObjectsCount() == 1) break;
14396  }
14397  CHECK_GE(2, gc_count);
14398  CHECK_EQ(1, GetGlobalObjectsCount());
14399
14400  other_context.Dispose();
14401}
14402
14403
14404THREADED_TEST(ScriptOrigin) {
14405  v8::HandleScope scope;
14406  LocalContext env;
14407  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14408  v8::Handle<v8::String> script = v8::String::New(
14409      "function f() {}\n\nfunction g() {}");
14410  v8::Script::Compile(script, &origin)->Run();
14411  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14412      env->Global()->Get(v8::String::New("f")));
14413  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14414      env->Global()->Get(v8::String::New("g")));
14415
14416  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
14417  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
14418  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
14419
14420  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
14421  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
14422  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
14423}
14424
14425THREADED_TEST(FunctionGetInferredName) {
14426  v8::HandleScope scope;
14427  LocalContext env;
14428  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14429  v8::Handle<v8::String> script = v8::String::New(
14430      "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
14431  v8::Script::Compile(script, &origin)->Run();
14432  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14433      env->Global()->Get(v8::String::New("f")));
14434  CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
14435}
14436
14437THREADED_TEST(ScriptLineNumber) {
14438  v8::HandleScope scope;
14439  LocalContext env;
14440  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
14441  v8::Handle<v8::String> script = v8::String::New(
14442      "function f() {}\n\nfunction g() {}");
14443  v8::Script::Compile(script, &origin)->Run();
14444  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
14445      env->Global()->Get(v8::String::New("f")));
14446  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
14447      env->Global()->Get(v8::String::New("g")));
14448  CHECK_EQ(0, f->GetScriptLineNumber());
14449  CHECK_EQ(2, g->GetScriptLineNumber());
14450}
14451
14452
14453THREADED_TEST(ScriptColumnNumber) {
14454  v8::HandleScope scope;
14455  LocalContext env;
14456  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14457      v8::Integer::New(3), v8::Integer::New(2));
14458  v8::Handle<v8::String> script = v8::String::New(
14459      "function foo() {}\n\n     function bar() {}");
14460  v8::Script::Compile(script, &origin)->Run();
14461  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14462      env->Global()->Get(v8::String::New("foo")));
14463  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14464      env->Global()->Get(v8::String::New("bar")));
14465  CHECK_EQ(14, foo->GetScriptColumnNumber());
14466  CHECK_EQ(17, bar->GetScriptColumnNumber());
14467}
14468
14469
14470THREADED_TEST(FunctionGetScriptId) {
14471  v8::HandleScope scope;
14472  LocalContext env;
14473  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
14474      v8::Integer::New(3), v8::Integer::New(2));
14475  v8::Handle<v8::String> scriptSource = v8::String::New(
14476      "function foo() {}\n\n     function bar() {}");
14477  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
14478  script->Run();
14479  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
14480      env->Global()->Get(v8::String::New("foo")));
14481  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
14482      env->Global()->Get(v8::String::New("bar")));
14483  CHECK_EQ(script->Id(), foo->GetScriptId());
14484  CHECK_EQ(script->Id(), bar->GetScriptId());
14485}
14486
14487
14488static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
14489                                              const AccessorInfo& info) {
14490  return v8_num(42);
14491}
14492
14493
14494static void SetterWhichSetsYOnThisTo23(Local<String> name,
14495                                       Local<Value> value,
14496                                       const AccessorInfo& info) {
14497  info.This()->Set(v8_str("y"), v8_num(23));
14498}
14499
14500
14501TEST(SetterOnConstructorPrototype) {
14502  v8::HandleScope scope;
14503  Local<ObjectTemplate> templ = ObjectTemplate::New();
14504  templ->SetAccessor(v8_str("x"),
14505                     GetterWhichReturns42,
14506                     SetterWhichSetsYOnThisTo23);
14507  LocalContext context;
14508  context->Global()->Set(v8_str("P"), templ->NewInstance());
14509  CompileRun("function C1() {"
14510             "  this.x = 23;"
14511             "};"
14512             "C1.prototype = P;"
14513             "function C2() {"
14514             "  this.x = 23"
14515             "};"
14516             "C2.prototype = { };"
14517             "C2.prototype.__proto__ = P;");
14518
14519  v8::Local<v8::Script> script;
14520  script = v8::Script::Compile(v8_str("new C1();"));
14521  for (int i = 0; i < 10; i++) {
14522    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14523    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14524    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14525  }
14526
14527  script = v8::Script::Compile(v8_str("new C2();"));
14528  for (int i = 0; i < 10; i++) {
14529    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14530    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
14531    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
14532  }
14533}
14534
14535
14536static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
14537    Local<String> name, const AccessorInfo& info) {
14538  return v8_num(42);
14539}
14540
14541
14542static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
14543    Local<String> name, Local<Value> value, const AccessorInfo& info) {
14544  if (name->Equals(v8_str("x"))) {
14545    info.This()->Set(v8_str("y"), v8_num(23));
14546  }
14547  return v8::Handle<Value>();
14548}
14549
14550
14551THREADED_TEST(InterceptorOnConstructorPrototype) {
14552  v8::HandleScope scope;
14553  Local<ObjectTemplate> templ = ObjectTemplate::New();
14554  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
14555                                 NamedPropertySetterWhichSetsYOnThisTo23);
14556  LocalContext context;
14557  context->Global()->Set(v8_str("P"), templ->NewInstance());
14558  CompileRun("function C1() {"
14559             "  this.x = 23;"
14560             "};"
14561             "C1.prototype = P;"
14562             "function C2() {"
14563             "  this.x = 23"
14564             "};"
14565             "C2.prototype = { };"
14566             "C2.prototype.__proto__ = P;");
14567
14568  v8::Local<v8::Script> script;
14569  script = v8::Script::Compile(v8_str("new C1();"));
14570  for (int i = 0; i < 10; i++) {
14571    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14572    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14573    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14574  }
14575
14576  script = v8::Script::Compile(v8_str("new C2();"));
14577  for (int i = 0; i < 10; i++) {
14578    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
14579    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
14580    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
14581  }
14582}
14583
14584
14585TEST(Bug618) {
14586  const char* source = "function C1() {"
14587                       "  this.x = 23;"
14588                       "};"
14589                       "C1.prototype = P;";
14590
14591  v8::HandleScope scope;
14592  LocalContext context;
14593  v8::Local<v8::Script> script;
14594
14595  // Use a simple object as prototype.
14596  v8::Local<v8::Object> prototype = v8::Object::New();
14597  prototype->Set(v8_str("y"), v8_num(42));
14598  context->Global()->Set(v8_str("P"), prototype);
14599
14600  // This compile will add the code to the compilation cache.
14601  CompileRun(source);
14602
14603  script = v8::Script::Compile(v8_str("new C1();"));
14604  // Allow enough iterations for the inobject slack tracking logic
14605  // to finalize instance size and install the fast construct stub.
14606  for (int i = 0; i < 256; i++) {
14607    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14608    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
14609    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
14610  }
14611
14612  // Use an API object with accessors as prototype.
14613  Local<ObjectTemplate> templ = ObjectTemplate::New();
14614  templ->SetAccessor(v8_str("x"),
14615                     GetterWhichReturns42,
14616                     SetterWhichSetsYOnThisTo23);
14617  context->Global()->Set(v8_str("P"), templ->NewInstance());
14618
14619  // This compile will get the code from the compilation cache.
14620  CompileRun(source);
14621
14622  script = v8::Script::Compile(v8_str("new C1();"));
14623  for (int i = 0; i < 10; i++) {
14624    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
14625    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
14626    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
14627  }
14628}
14629
14630int prologue_call_count = 0;
14631int epilogue_call_count = 0;
14632int prologue_call_count_second = 0;
14633int epilogue_call_count_second = 0;
14634
14635void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14636  ++prologue_call_count;
14637}
14638
14639void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14640  ++epilogue_call_count;
14641}
14642
14643void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14644  ++prologue_call_count_second;
14645}
14646
14647void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14648  ++epilogue_call_count_second;
14649}
14650
14651TEST(GCCallbacks) {
14652  LocalContext context;
14653
14654  v8::V8::AddGCPrologueCallback(PrologueCallback);
14655  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14656  CHECK_EQ(0, prologue_call_count);
14657  CHECK_EQ(0, epilogue_call_count);
14658  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14659  CHECK_EQ(1, prologue_call_count);
14660  CHECK_EQ(1, epilogue_call_count);
14661  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14662  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
14663  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14664  CHECK_EQ(2, prologue_call_count);
14665  CHECK_EQ(2, epilogue_call_count);
14666  CHECK_EQ(1, prologue_call_count_second);
14667  CHECK_EQ(1, epilogue_call_count_second);
14668  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14669  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
14670  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14671  CHECK_EQ(2, prologue_call_count);
14672  CHECK_EQ(2, epilogue_call_count);
14673  CHECK_EQ(2, prologue_call_count_second);
14674  CHECK_EQ(2, epilogue_call_count_second);
14675  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14676  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
14677  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14678  CHECK_EQ(2, prologue_call_count);
14679  CHECK_EQ(2, epilogue_call_count);
14680  CHECK_EQ(2, prologue_call_count_second);
14681  CHECK_EQ(2, epilogue_call_count_second);
14682}
14683
14684
14685THREADED_TEST(AddToJSFunctionResultCache) {
14686  i::FLAG_allow_natives_syntax = true;
14687  v8::HandleScope scope;
14688
14689  LocalContext context;
14690
14691  const char* code =
14692      "(function() {"
14693      "  var key0 = 'a';"
14694      "  var key1 = 'b';"
14695      "  var r0 = %_GetFromCache(0, key0);"
14696      "  var r1 = %_GetFromCache(0, key1);"
14697      "  var r0_ = %_GetFromCache(0, key0);"
14698      "  if (r0 !== r0_)"
14699      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14700      "  var r1_ = %_GetFromCache(0, key1);"
14701      "  if (r1 !== r1_)"
14702      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14703      "  return 'PASSED';"
14704      "})()";
14705  HEAP->ClearJSFunctionResultCaches();
14706  ExpectString(code, "PASSED");
14707}
14708
14709
14710static const int k0CacheSize = 16;
14711
14712THREADED_TEST(FillJSFunctionResultCache) {
14713  i::FLAG_allow_natives_syntax = true;
14714  v8::HandleScope scope;
14715
14716  LocalContext context;
14717
14718  const char* code =
14719      "(function() {"
14720      "  var k = 'a';"
14721      "  var r = %_GetFromCache(0, k);"
14722      "  for (var i = 0; i < 16; i++) {"
14723      "    %_GetFromCache(0, 'a' + i);"
14724      "  };"
14725      "  if (r === %_GetFromCache(0, k))"
14726      "    return 'FAILED: k0CacheSize is too small';"
14727      "  return 'PASSED';"
14728      "})()";
14729  HEAP->ClearJSFunctionResultCaches();
14730  ExpectString(code, "PASSED");
14731}
14732
14733
14734THREADED_TEST(RoundRobinGetFromCache) {
14735  i::FLAG_allow_natives_syntax = true;
14736  v8::HandleScope scope;
14737
14738  LocalContext context;
14739
14740  const char* code =
14741      "(function() {"
14742      "  var keys = [];"
14743      "  for (var i = 0; i < 16; i++) keys.push(i);"
14744      "  var values = [];"
14745      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14746      "  for (var i = 0; i < 16; i++) {"
14747      "    var v = %_GetFromCache(0, keys[i]);"
14748      "    if (v.toString() !== values[i].toString())"
14749      "      return 'Wrong value for ' + "
14750      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14751      "  };"
14752      "  return 'PASSED';"
14753      "})()";
14754  HEAP->ClearJSFunctionResultCaches();
14755  ExpectString(code, "PASSED");
14756}
14757
14758
14759THREADED_TEST(ReverseGetFromCache) {
14760  i::FLAG_allow_natives_syntax = true;
14761  v8::HandleScope scope;
14762
14763  LocalContext context;
14764
14765  const char* code =
14766      "(function() {"
14767      "  var keys = [];"
14768      "  for (var i = 0; i < 16; i++) keys.push(i);"
14769      "  var values = [];"
14770      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14771      "  for (var i = 15; i >= 16; i--) {"
14772      "    var v = %_GetFromCache(0, keys[i]);"
14773      "    if (v !== values[i])"
14774      "      return 'Wrong value for ' + "
14775      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14776      "  };"
14777      "  return 'PASSED';"
14778      "})()";
14779  HEAP->ClearJSFunctionResultCaches();
14780  ExpectString(code, "PASSED");
14781}
14782
14783
14784THREADED_TEST(TestEviction) {
14785  i::FLAG_allow_natives_syntax = true;
14786  v8::HandleScope scope;
14787
14788  LocalContext context;
14789
14790  const char* code =
14791      "(function() {"
14792      "  for (var i = 0; i < 2*16; i++) {"
14793      "    %_GetFromCache(0, 'a' + i);"
14794      "  };"
14795      "  return 'PASSED';"
14796      "})()";
14797  HEAP->ClearJSFunctionResultCaches();
14798  ExpectString(code, "PASSED");
14799}
14800
14801
14802THREADED_TEST(TwoByteStringInAsciiCons) {
14803  // See Chromium issue 47824.
14804  v8::HandleScope scope;
14805
14806  LocalContext context;
14807  const char* init_code =
14808      "var str1 = 'abelspendabel';"
14809      "var str2 = str1 + str1 + str1;"
14810      "str2;";
14811  Local<Value> result = CompileRun(init_code);
14812
14813  Local<Value> indexof = CompileRun("str2.indexOf('els')");
14814  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14815
14816  CHECK(result->IsString());
14817  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14818  int length = string->length();
14819  CHECK(string->IsAsciiRepresentation());
14820
14821  FlattenString(string);
14822  i::Handle<i::String> flat_string = FlattenGetString(string);
14823
14824  CHECK(string->IsAsciiRepresentation());
14825  CHECK(flat_string->IsAsciiRepresentation());
14826
14827  // Create external resource.
14828  uint16_t* uc16_buffer = new uint16_t[length + 1];
14829
14830  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14831  uc16_buffer[length] = 0;
14832
14833  TestResource resource(uc16_buffer);
14834
14835  flat_string->MakeExternal(&resource);
14836
14837  CHECK(flat_string->IsTwoByteRepresentation());
14838
14839  // At this point, we should have a Cons string which is flat and ASCII,
14840  // with a first half that is a two-byte string (although it only contains
14841  // ASCII characters). This is a valid sequence of steps, and it can happen
14842  // in real pages.
14843
14844  CHECK(string->IsAsciiRepresentation());
14845  i::ConsString* cons = i::ConsString::cast(*string);
14846  CHECK_EQ(0, cons->second()->length());
14847  CHECK(cons->first()->IsTwoByteRepresentation());
14848
14849  // Check that some string operations work.
14850
14851  // Atom RegExp.
14852  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14853  CHECK_EQ(6, reresult->Int32Value());
14854
14855  // Nonatom RegExp.
14856  reresult = CompileRun("str2.match(/abe./g).length;");
14857  CHECK_EQ(6, reresult->Int32Value());
14858
14859  reresult = CompileRun("str2.search(/bel/g);");
14860  CHECK_EQ(1, reresult->Int32Value());
14861
14862  reresult = CompileRun("str2.search(/be./g);");
14863  CHECK_EQ(1, reresult->Int32Value());
14864
14865  ExpectTrue("/bel/g.test(str2);");
14866
14867  ExpectTrue("/be./g.test(str2);");
14868
14869  reresult = CompileRun("/bel/g.exec(str2);");
14870  CHECK(!reresult->IsNull());
14871
14872  reresult = CompileRun("/be./g.exec(str2);");
14873  CHECK(!reresult->IsNull());
14874
14875  ExpectString("str2.substring(2, 10);", "elspenda");
14876
14877  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14878
14879  ExpectString("str2.charAt(2);", "e");
14880
14881  ExpectObject("str2.indexOf('els');", indexof);
14882
14883  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14884
14885  reresult = CompileRun("str2.charCodeAt(2);");
14886  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14887}
14888
14889
14890// Failed access check callback that performs a GC on each invocation.
14891void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14892                                 v8::AccessType type,
14893                                 Local<v8::Value> data) {
14894  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14895}
14896
14897
14898TEST(GCInFailedAccessCheckCallback) {
14899  // Install a failed access check callback that performs a GC on each
14900  // invocation. Then force the callback to be called from va
14901
14902  v8::V8::Initialize();
14903  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14904
14905  v8::HandleScope scope;
14906
14907  // Create an ObjectTemplate for global objects and install access
14908  // check callbacks that will block access.
14909  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14910  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14911                                           IndexedGetAccessBlocker,
14912                                           v8::Handle<v8::Value>(),
14913                                           false);
14914
14915  // Create a context and set an x property on it's global object.
14916  LocalContext context0(NULL, global_template);
14917  context0->Global()->Set(v8_str("x"), v8_num(42));
14918  v8::Handle<v8::Object> global0 = context0->Global();
14919
14920  // Create a context with a different security token so that the
14921  // failed access check callback will be called on each access.
14922  LocalContext context1(NULL, global_template);
14923  context1->Global()->Set(v8_str("other"), global0);
14924
14925  // Get property with failed access check.
14926  ExpectUndefined("other.x");
14927
14928  // Get element with failed access check.
14929  ExpectUndefined("other[0]");
14930
14931  // Set property with failed access check.
14932  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14933  CHECK(result->IsObject());
14934
14935  // Set element with failed access check.
14936  result = CompileRun("other[0] = new Object()");
14937  CHECK(result->IsObject());
14938
14939  // Get property attribute with failed access check.
14940  ExpectFalse("\'x\' in other");
14941
14942  // Get property attribute for element with failed access check.
14943  ExpectFalse("0 in other");
14944
14945  // Delete property.
14946  ExpectFalse("delete other.x");
14947
14948  // Delete element.
14949  CHECK_EQ(false, global0->Delete(0));
14950
14951  // DefineAccessor.
14952  CHECK_EQ(false,
14953           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14954
14955  // Define JavaScript accessor.
14956  ExpectUndefined("Object.prototype.__defineGetter__.call("
14957                  "    other, \'x\', function() { return 42; })");
14958
14959  // LookupAccessor.
14960  ExpectUndefined("Object.prototype.__lookupGetter__.call("
14961                  "    other, \'x\')");
14962
14963  // HasLocalElement.
14964  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14965
14966  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14967  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14968  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14969
14970  // Reset the failed access check callback so it does not influence
14971  // the other tests.
14972  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14973}
14974
14975TEST(DefaultIsolateGetCurrent) {
14976  CHECK(v8::Isolate::GetCurrent() != NULL);
14977  v8::Isolate* isolate = v8::Isolate::GetCurrent();
14978  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14979  printf("*** %s\n", "DefaultIsolateGetCurrent success");
14980}
14981
14982TEST(IsolateNewDispose) {
14983  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14984  v8::Isolate* isolate = v8::Isolate::New();
14985  CHECK(isolate != NULL);
14986  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14987  CHECK(current_isolate != isolate);
14988  CHECK(current_isolate == v8::Isolate::GetCurrent());
14989
14990  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14991  last_location = last_message = NULL;
14992  isolate->Dispose();
14993  CHECK_EQ(last_location, NULL);
14994  CHECK_EQ(last_message, NULL);
14995}
14996
14997TEST(IsolateEnterExitDefault) {
14998  v8::HandleScope scope;
14999  LocalContext context;
15000  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15001  CHECK(current_isolate != NULL);  // Default isolate.
15002  ExpectString("'hello'", "hello");
15003  current_isolate->Enter();
15004  ExpectString("'still working'", "still working");
15005  current_isolate->Exit();
15006  ExpectString("'still working 2'", "still working 2");
15007  current_isolate->Exit();
15008  // Default isolate is always, well, 'default current'.
15009  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15010  // Still working since default isolate is auto-entering any thread
15011  // that has no isolate and attempts to execute V8 APIs.
15012  ExpectString("'still working 3'", "still working 3");
15013}
15014
15015TEST(DisposeDefaultIsolate) {
15016  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15017
15018  // Run some V8 code to trigger default isolate to become 'current'.
15019  v8::HandleScope scope;
15020  LocalContext context;
15021  ExpectString("'run some V8'", "run some V8");
15022
15023  v8::Isolate* isolate = v8::Isolate::GetCurrent();
15024  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15025  last_location = last_message = NULL;
15026  isolate->Dispose();
15027  // It is not possible to dispose default isolate via Isolate API.
15028  CHECK_NE(last_location, NULL);
15029  CHECK_NE(last_message, NULL);
15030}
15031
15032TEST(RunDefaultAndAnotherIsolate) {
15033  v8::HandleScope scope;
15034  LocalContext context;
15035
15036  // Enter new isolate.
15037  v8::Isolate* isolate = v8::Isolate::New();
15038  CHECK(isolate);
15039  isolate->Enter();
15040  { // Need this block because subsequent Exit() will deallocate Heap,
15041    // so we need all scope objects to be deconstructed when it happens.
15042    v8::HandleScope scope_new;
15043    LocalContext context_new;
15044
15045    // Run something in new isolate.
15046    CompileRun("var foo = 153;");
15047    ExpectTrue("function f() { return foo == 153; }; f()");
15048  }
15049  isolate->Exit();
15050
15051  // This runs automatically in default isolate.
15052  // Variables in another isolate should be not available.
15053  ExpectTrue("function f() {"
15054             "  try {"
15055             "    foo;"
15056             "    return false;"
15057             "  } catch(e) {"
15058             "    return true;"
15059             "  }"
15060             "};"
15061             "var bar = 371;"
15062             "f()");
15063
15064  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15065  last_location = last_message = NULL;
15066  isolate->Dispose();
15067  CHECK_EQ(last_location, NULL);
15068  CHECK_EQ(last_message, NULL);
15069
15070  // Check that default isolate still runs.
15071  ExpectTrue("function f() { return bar == 371; }; f()");
15072}
15073
15074TEST(DisposeIsolateWhenInUse) {
15075  v8::Isolate* isolate = v8::Isolate::New();
15076  CHECK(isolate);
15077  isolate->Enter();
15078  v8::HandleScope scope;
15079  LocalContext context;
15080  // Run something in this isolate.
15081  ExpectTrue("true");
15082  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15083  last_location = last_message = NULL;
15084  // Still entered, should fail.
15085  isolate->Dispose();
15086  CHECK_NE(last_location, NULL);
15087  CHECK_NE(last_message, NULL);
15088}
15089
15090TEST(RunTwoIsolatesOnSingleThread) {
15091  // Run isolate 1.
15092  v8::Isolate* isolate1 = v8::Isolate::New();
15093  isolate1->Enter();
15094  v8::Persistent<v8::Context> context1 = v8::Context::New();
15095
15096  {
15097    v8::Context::Scope cscope(context1);
15098    v8::HandleScope scope;
15099    // Run something in new isolate.
15100    CompileRun("var foo = 'isolate 1';");
15101    ExpectString("function f() { return foo; }; f()", "isolate 1");
15102  }
15103
15104  // Run isolate 2.
15105  v8::Isolate* isolate2 = v8::Isolate::New();
15106  v8::Persistent<v8::Context> context2;
15107
15108  {
15109    v8::Isolate::Scope iscope(isolate2);
15110    context2 = v8::Context::New();
15111    v8::Context::Scope cscope(context2);
15112    v8::HandleScope scope;
15113
15114    // Run something in new isolate.
15115    CompileRun("var foo = 'isolate 2';");
15116    ExpectString("function f() { return foo; }; f()", "isolate 2");
15117  }
15118
15119  {
15120    v8::Context::Scope cscope(context1);
15121    v8::HandleScope scope;
15122    // Now again in isolate 1
15123    ExpectString("function f() { return foo; }; f()", "isolate 1");
15124  }
15125
15126  isolate1->Exit();
15127
15128  // Run some stuff in default isolate.
15129  v8::Persistent<v8::Context> context_default = v8::Context::New();
15130
15131  {
15132    v8::Context::Scope cscope(context_default);
15133    v8::HandleScope scope;
15134    // Variables in other isolates should be not available, verify there
15135    // is an exception.
15136    ExpectTrue("function f() {"
15137               "  try {"
15138               "    foo;"
15139               "    return false;"
15140               "  } catch(e) {"
15141               "    return true;"
15142               "  }"
15143               "};"
15144               "var isDefaultIsolate = true;"
15145               "f()");
15146  }
15147
15148  isolate1->Enter();
15149
15150  {
15151    v8::Isolate::Scope iscope(isolate2);
15152    v8::Context::Scope cscope(context2);
15153    v8::HandleScope scope;
15154    ExpectString("function f() { return foo; }; f()", "isolate 2");
15155  }
15156
15157  {
15158    v8::Context::Scope cscope(context1);
15159    v8::HandleScope scope;
15160    ExpectString("function f() { return foo; }; f()", "isolate 1");
15161  }
15162
15163  {
15164    v8::Isolate::Scope iscope(isolate2);
15165    context2.Dispose();
15166  }
15167
15168  context1.Dispose();
15169  isolate1->Exit();
15170
15171  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15172  last_location = last_message = NULL;
15173
15174  isolate1->Dispose();
15175  CHECK_EQ(last_location, NULL);
15176  CHECK_EQ(last_message, NULL);
15177
15178  isolate2->Dispose();
15179  CHECK_EQ(last_location, NULL);
15180  CHECK_EQ(last_message, NULL);
15181
15182  // Check that default isolate still runs.
15183  {
15184    v8::Context::Scope cscope(context_default);
15185    v8::HandleScope scope;
15186    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
15187  }
15188}
15189
15190static int CalcFibonacci(v8::Isolate* isolate, int limit) {
15191  v8::Isolate::Scope isolate_scope(isolate);
15192  v8::HandleScope scope;
15193  LocalContext context;
15194  i::ScopedVector<char> code(1024);
15195  i::OS::SNPrintF(code, "function fib(n) {"
15196                        "  if (n <= 2) return 1;"
15197                        "  return fib(n-1) + fib(n-2);"
15198                        "}"
15199                        "fib(%d)", limit);
15200  Local<Value> value = CompileRun(code.start());
15201  CHECK(value->IsNumber());
15202  return static_cast<int>(value->NumberValue());
15203}
15204
15205class IsolateThread : public v8::internal::Thread {
15206 public:
15207  IsolateThread(v8::Isolate* isolate, int fib_limit)
15208      : Thread("IsolateThread"),
15209        isolate_(isolate),
15210        fib_limit_(fib_limit),
15211        result_(0) { }
15212
15213  void Run() {
15214    result_ = CalcFibonacci(isolate_, fib_limit_);
15215  }
15216
15217  int result() { return result_; }
15218
15219 private:
15220  v8::Isolate* isolate_;
15221  int fib_limit_;
15222  int result_;
15223};
15224
15225TEST(MultipleIsolatesOnIndividualThreads) {
15226  v8::Isolate* isolate1 = v8::Isolate::New();
15227  v8::Isolate* isolate2 = v8::Isolate::New();
15228
15229  IsolateThread thread1(isolate1, 21);
15230  IsolateThread thread2(isolate2, 12);
15231
15232  // Compute some fibonacci numbers on 3 threads in 3 isolates.
15233  thread1.Start();
15234  thread2.Start();
15235
15236  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15237  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
15238
15239  thread1.Join();
15240  thread2.Join();
15241
15242  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
15243  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
15244  CHECK_EQ(result1, 10946);
15245  CHECK_EQ(result2, 144);
15246  CHECK_EQ(result1, thread1.result());
15247  CHECK_EQ(result2, thread2.result());
15248
15249  isolate1->Dispose();
15250  isolate2->Dispose();
15251}
15252
15253TEST(IsolateDifferentContexts) {
15254  v8::Isolate* isolate = v8::Isolate::New();
15255  Persistent<v8::Context> context;
15256  {
15257    v8::Isolate::Scope isolate_scope(isolate);
15258    v8::HandleScope handle_scope;
15259    context = v8::Context::New();
15260    v8::Context::Scope context_scope(context);
15261    Local<Value> v = CompileRun("2");
15262    CHECK(v->IsNumber());
15263    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
15264  }
15265  {
15266    v8::Isolate::Scope isolate_scope(isolate);
15267    v8::HandleScope handle_scope;
15268    context = v8::Context::New();
15269    v8::Context::Scope context_scope(context);
15270    Local<Value> v = CompileRun("22");
15271    CHECK(v->IsNumber());
15272    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
15273  }
15274}
15275
15276class InitDefaultIsolateThread : public v8::internal::Thread {
15277 public:
15278  enum TestCase {
15279    IgnoreOOM,
15280    SetResourceConstraints,
15281    SetFatalHandler,
15282    SetCounterFunction,
15283    SetCreateHistogramFunction,
15284    SetAddHistogramSampleFunction
15285  };
15286
15287  explicit InitDefaultIsolateThread(TestCase testCase)
15288      : Thread("InitDefaultIsolateThread"),
15289        testCase_(testCase),
15290        result_(false) { }
15291
15292  void Run() {
15293    switch (testCase_) {
15294    case IgnoreOOM:
15295      v8::V8::IgnoreOutOfMemoryException();
15296      break;
15297
15298    case SetResourceConstraints: {
15299      static const int K = 1024;
15300      v8::ResourceConstraints constraints;
15301      constraints.set_max_young_space_size(256 * K);
15302      constraints.set_max_old_space_size(4 * K * K);
15303      v8::SetResourceConstraints(&constraints);
15304      break;
15305    }
15306
15307    case SetFatalHandler:
15308      v8::V8::SetFatalErrorHandler(NULL);
15309      break;
15310
15311    case SetCounterFunction:
15312      v8::V8::SetCounterFunction(NULL);
15313      break;
15314
15315    case SetCreateHistogramFunction:
15316      v8::V8::SetCreateHistogramFunction(NULL);
15317      break;
15318
15319    case SetAddHistogramSampleFunction:
15320      v8::V8::SetAddHistogramSampleFunction(NULL);
15321      break;
15322    }
15323    result_ = true;
15324  }
15325
15326  bool result() { return result_; }
15327
15328 private:
15329  TestCase testCase_;
15330  bool result_;
15331};
15332
15333
15334static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
15335  InitDefaultIsolateThread thread(testCase);
15336  thread.Start();
15337  thread.Join();
15338  CHECK_EQ(thread.result(), true);
15339}
15340
15341TEST(InitializeDefaultIsolateOnSecondaryThread1) {
15342  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
15343}
15344
15345TEST(InitializeDefaultIsolateOnSecondaryThread2) {
15346  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
15347}
15348
15349TEST(InitializeDefaultIsolateOnSecondaryThread3) {
15350  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
15351}
15352
15353TEST(InitializeDefaultIsolateOnSecondaryThread4) {
15354  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
15355}
15356
15357TEST(InitializeDefaultIsolateOnSecondaryThread5) {
15358  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
15359}
15360
15361TEST(InitializeDefaultIsolateOnSecondaryThread6) {
15362  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
15363}
15364
15365
15366TEST(StringCheckMultipleContexts) {
15367  const char* code =
15368      "(function() { return \"a\".charAt(0); })()";
15369
15370  {
15371    // Run the code twice in the first context to initialize the call IC.
15372    v8::HandleScope scope;
15373    LocalContext context1;
15374    ExpectString(code, "a");
15375    ExpectString(code, "a");
15376  }
15377
15378  {
15379    // Change the String.prototype in the second context and check
15380    // that the right function gets called.
15381    v8::HandleScope scope;
15382    LocalContext context2;
15383    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
15384    ExpectString(code, "not a");
15385  }
15386}
15387
15388
15389TEST(NumberCheckMultipleContexts) {
15390  const char* code =
15391      "(function() { return (42).toString(); })()";
15392
15393  {
15394    // Run the code twice in the first context to initialize the call IC.
15395    v8::HandleScope scope;
15396    LocalContext context1;
15397    ExpectString(code, "42");
15398    ExpectString(code, "42");
15399  }
15400
15401  {
15402    // Change the Number.prototype in the second context and check
15403    // that the right function gets called.
15404    v8::HandleScope scope;
15405    LocalContext context2;
15406    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
15407    ExpectString(code, "not 42");
15408  }
15409}
15410
15411
15412TEST(BooleanCheckMultipleContexts) {
15413  const char* code =
15414      "(function() { return true.toString(); })()";
15415
15416  {
15417    // Run the code twice in the first context to initialize the call IC.
15418    v8::HandleScope scope;
15419    LocalContext context1;
15420    ExpectString(code, "true");
15421    ExpectString(code, "true");
15422  }
15423
15424  {
15425    // Change the Boolean.prototype in the second context and check
15426    // that the right function gets called.
15427    v8::HandleScope scope;
15428    LocalContext context2;
15429    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
15430    ExpectString(code, "");
15431  }
15432}
15433
15434
15435TEST(DontDeleteCellLoadIC) {
15436  const char* function_code =
15437      "function readCell() { while (true) { return cell; } }";
15438
15439  {
15440    // Run the code twice in the first context to initialize the load
15441    // IC for a don't delete cell.
15442    v8::HandleScope scope;
15443    LocalContext context1;
15444    CompileRun("var cell = \"first\";");
15445    ExpectBoolean("delete cell", false);
15446    CompileRun(function_code);
15447    ExpectString("readCell()", "first");
15448    ExpectString("readCell()", "first");
15449  }
15450
15451  {
15452    // Use a deletable cell in the second context.
15453    v8::HandleScope scope;
15454    LocalContext context2;
15455    CompileRun("cell = \"second\";");
15456    CompileRun(function_code);
15457    ExpectString("readCell()", "second");
15458    ExpectBoolean("delete cell", true);
15459    ExpectString("(function() {"
15460                 "  try {"
15461                 "    return readCell();"
15462                 "  } catch(e) {"
15463                 "    return e.toString();"
15464                 "  }"
15465                 "})()",
15466                 "ReferenceError: cell is not defined");
15467    CompileRun("cell = \"new_second\";");
15468    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15469    ExpectString("readCell()", "new_second");
15470    ExpectString("readCell()", "new_second");
15471  }
15472}
15473
15474
15475TEST(DontDeleteCellLoadICForceDelete) {
15476  const char* function_code =
15477      "function readCell() { while (true) { return cell; } }";
15478
15479  // Run the code twice to initialize the load IC for a don't delete
15480  // cell.
15481  v8::HandleScope scope;
15482  LocalContext context;
15483  CompileRun("var cell = \"value\";");
15484  ExpectBoolean("delete cell", false);
15485  CompileRun(function_code);
15486  ExpectString("readCell()", "value");
15487  ExpectString("readCell()", "value");
15488
15489  // Delete the cell using the API and check the inlined code works
15490  // correctly.
15491  CHECK(context->Global()->ForceDelete(v8_str("cell")));
15492  ExpectString("(function() {"
15493               "  try {"
15494               "    return readCell();"
15495               "  } catch(e) {"
15496               "    return e.toString();"
15497               "  }"
15498               "})()",
15499               "ReferenceError: cell is not defined");
15500}
15501
15502
15503TEST(DontDeleteCellLoadICAPI) {
15504  const char* function_code =
15505      "function readCell() { while (true) { return cell; } }";
15506
15507  // Run the code twice to initialize the load IC for a don't delete
15508  // cell created using the API.
15509  v8::HandleScope scope;
15510  LocalContext context;
15511  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
15512  ExpectBoolean("delete cell", false);
15513  CompileRun(function_code);
15514  ExpectString("readCell()", "value");
15515  ExpectString("readCell()", "value");
15516
15517  // Delete the cell using the API and check the inlined code works
15518  // correctly.
15519  CHECK(context->Global()->ForceDelete(v8_str("cell")));
15520  ExpectString("(function() {"
15521               "  try {"
15522               "    return readCell();"
15523               "  } catch(e) {"
15524               "    return e.toString();"
15525               "  }"
15526               "})()",
15527               "ReferenceError: cell is not defined");
15528}
15529
15530
15531TEST(RegExp) {
15532  v8::HandleScope scope;
15533  LocalContext context;
15534
15535  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
15536  CHECK(re->IsRegExp());
15537  CHECK(re->GetSource()->Equals(v8_str("foo")));
15538  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
15539
15540  re = v8::RegExp::New(v8_str("bar"),
15541                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15542                                                      v8::RegExp::kGlobal));
15543  CHECK(re->IsRegExp());
15544  CHECK(re->GetSource()->Equals(v8_str("bar")));
15545  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
15546           static_cast<int>(re->GetFlags()));
15547
15548  re = v8::RegExp::New(v8_str("baz"),
15549                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15550                                                      v8::RegExp::kMultiline));
15551  CHECK(re->IsRegExp());
15552  CHECK(re->GetSource()->Equals(v8_str("baz")));
15553  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15554           static_cast<int>(re->GetFlags()));
15555
15556  re = CompileRun("/quux/").As<v8::RegExp>();
15557  CHECK(re->IsRegExp());
15558  CHECK(re->GetSource()->Equals(v8_str("quux")));
15559  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
15560
15561  re = CompileRun("/quux/gm").As<v8::RegExp>();
15562  CHECK(re->IsRegExp());
15563  CHECK(re->GetSource()->Equals(v8_str("quux")));
15564  CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
15565           static_cast<int>(re->GetFlags()));
15566
15567  // Override the RegExp constructor and check the API constructor
15568  // still works.
15569  CompileRun("RegExp = function() {}");
15570
15571  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
15572  CHECK(re->IsRegExp());
15573  CHECK(re->GetSource()->Equals(v8_str("foobar")));
15574  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
15575
15576  re = v8::RegExp::New(v8_str("foobarbaz"),
15577                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
15578                                                      v8::RegExp::kMultiline));
15579  CHECK(re->IsRegExp());
15580  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
15581  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
15582           static_cast<int>(re->GetFlags()));
15583
15584  context->Global()->Set(v8_str("re"), re);
15585  ExpectTrue("re.test('FoobarbaZ')");
15586
15587  // RegExps are objects on which you can set properties.
15588  re->Set(v8_str("property"), v8::Integer::New(32));
15589  v8::Handle<v8::Value> value(CompileRun("re.property"));
15590  CHECK_EQ(32, value->Int32Value());
15591
15592  v8::TryCatch try_catch;
15593  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
15594  CHECK(re.IsEmpty());
15595  CHECK(try_catch.HasCaught());
15596  context->Global()->Set(v8_str("ex"), try_catch.Exception());
15597  ExpectTrue("ex instanceof SyntaxError");
15598}
15599
15600
15601THREADED_TEST(Equals) {
15602  v8::HandleScope handleScope;
15603  LocalContext localContext;
15604
15605  v8::Handle<v8::Object> globalProxy = localContext->Global();
15606  v8::Handle<Value> global = globalProxy->GetPrototype();
15607
15608  CHECK(global->StrictEquals(global));
15609  CHECK(!global->StrictEquals(globalProxy));
15610  CHECK(!globalProxy->StrictEquals(global));
15611  CHECK(globalProxy->StrictEquals(globalProxy));
15612
15613  CHECK(global->Equals(global));
15614  CHECK(!global->Equals(globalProxy));
15615  CHECK(!globalProxy->Equals(global));
15616  CHECK(globalProxy->Equals(globalProxy));
15617}
15618
15619
15620static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
15621                                    const v8::AccessorInfo& info ) {
15622  return v8_str("42!");
15623}
15624
15625
15626static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
15627  v8::Handle<v8::Array> result = v8::Array::New();
15628  result->Set(0, v8_str("universalAnswer"));
15629  return result;
15630}
15631
15632
15633TEST(NamedEnumeratorAndForIn) {
15634  v8::HandleScope handle_scope;
15635  LocalContext context;
15636  v8::Context::Scope context_scope(context.local());
15637
15638  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15639  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15640  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15641  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15642        "var result = []; for (var k in o) result.push(k); result"));
15643  CHECK_EQ(1, result->Length());
15644  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15645}
15646
15647
15648TEST(DefinePropertyPostDetach) {
15649  v8::HandleScope scope;
15650  LocalContext context;
15651  v8::Handle<v8::Object> proxy = context->Global();
15652  v8::Handle<v8::Function> define_property =
15653      CompileRun("(function() {"
15654                 "  Object.defineProperty("
15655                 "    this,"
15656                 "    1,"
15657                 "    { configurable: true, enumerable: true, value: 3 });"
15658                 "})").As<Function>();
15659  context->DetachGlobal();
15660  define_property->Call(proxy, 0, NULL);
15661}
15662
15663
15664static void InstallContextId(v8::Handle<Context> context, int id) {
15665  Context::Scope scope(context);
15666  CompileRun("Object.prototype").As<Object>()->
15667      Set(v8_str("context_id"), v8::Integer::New(id));
15668}
15669
15670
15671static void CheckContextId(v8::Handle<Object> object, int expected) {
15672  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15673}
15674
15675
15676THREADED_TEST(CreationContext) {
15677  HandleScope handle_scope;
15678  Persistent<Context> context1 = Context::New();
15679  InstallContextId(context1, 1);
15680  Persistent<Context> context2 = Context::New();
15681  InstallContextId(context2, 2);
15682  Persistent<Context> context3 = Context::New();
15683  InstallContextId(context3, 3);
15684
15685  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15686
15687  Local<Object> object1;
15688  Local<Function> func1;
15689  {
15690    Context::Scope scope(context1);
15691    object1 = Object::New();
15692    func1 = tmpl->GetFunction();
15693  }
15694
15695  Local<Object> object2;
15696  Local<Function> func2;
15697  {
15698    Context::Scope scope(context2);
15699    object2 = Object::New();
15700    func2 = tmpl->GetFunction();
15701  }
15702
15703  Local<Object> instance1;
15704  Local<Object> instance2;
15705
15706  {
15707    Context::Scope scope(context3);
15708    instance1 = func1->NewInstance();
15709    instance2 = func2->NewInstance();
15710  }
15711
15712  CHECK(object1->CreationContext() == context1);
15713  CheckContextId(object1, 1);
15714  CHECK(func1->CreationContext() == context1);
15715  CheckContextId(func1, 1);
15716  CHECK(instance1->CreationContext() == context1);
15717  CheckContextId(instance1, 1);
15718  CHECK(object2->CreationContext() == context2);
15719  CheckContextId(object2, 2);
15720  CHECK(func2->CreationContext() == context2);
15721  CheckContextId(func2, 2);
15722  CHECK(instance2->CreationContext() == context2);
15723  CheckContextId(instance2, 2);
15724
15725  {
15726    Context::Scope scope(context1);
15727    CHECK(object1->CreationContext() == context1);
15728    CheckContextId(object1, 1);
15729    CHECK(func1->CreationContext() == context1);
15730    CheckContextId(func1, 1);
15731    CHECK(instance1->CreationContext() == context1);
15732    CheckContextId(instance1, 1);
15733    CHECK(object2->CreationContext() == context2);
15734    CheckContextId(object2, 2);
15735    CHECK(func2->CreationContext() == context2);
15736    CheckContextId(func2, 2);
15737    CHECK(instance2->CreationContext() == context2);
15738    CheckContextId(instance2, 2);
15739  }
15740
15741  {
15742    Context::Scope scope(context2);
15743    CHECK(object1->CreationContext() == context1);
15744    CheckContextId(object1, 1);
15745    CHECK(func1->CreationContext() == context1);
15746    CheckContextId(func1, 1);
15747    CHECK(instance1->CreationContext() == context1);
15748    CheckContextId(instance1, 1);
15749    CHECK(object2->CreationContext() == context2);
15750    CheckContextId(object2, 2);
15751    CHECK(func2->CreationContext() == context2);
15752    CheckContextId(func2, 2);
15753    CHECK(instance2->CreationContext() == context2);
15754    CheckContextId(instance2, 2);
15755  }
15756
15757  context1.Dispose();
15758  context2.Dispose();
15759  context3.Dispose();
15760}
15761
15762
15763THREADED_TEST(CreationContextOfJsFunction) {
15764  HandleScope handle_scope;
15765  Persistent<Context> context = Context::New();
15766  InstallContextId(context, 1);
15767
15768  Local<Object> function;
15769  {
15770    Context::Scope scope(context);
15771    function = CompileRun("function foo() {}; foo").As<Object>();
15772  }
15773
15774  CHECK(function->CreationContext() == context);
15775  CheckContextId(function, 1);
15776
15777  context.Dispose();
15778}
15779
15780
15781Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15782                                                  const AccessorInfo& info) {
15783  if (index == 42) return v8_str("yes");
15784  return Handle<v8::Integer>();
15785}
15786
15787
15788Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15789                                                const AccessorInfo& info) {
15790  if (property->Equals(v8_str("foo"))) return v8_str("yes");
15791  return Handle<Value>();
15792}
15793
15794
15795Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15796    uint32_t index, const AccessorInfo& info) {
15797  if (index == 42) return v8_num(1).As<v8::Integer>();
15798  return Handle<v8::Integer>();
15799}
15800
15801
15802Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15803    Local<String> property, const AccessorInfo& info) {
15804  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15805  return Handle<v8::Integer>();
15806}
15807
15808
15809Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15810    Local<String> property, const AccessorInfo& info) {
15811  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15812  return Handle<v8::Integer>();
15813}
15814
15815
15816Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15817                                           const AccessorInfo& info) {
15818  return v8_str("yes");
15819}
15820
15821
15822TEST(HasOwnProperty) {
15823  v8::HandleScope scope;
15824  LocalContext env;
15825  { // Check normal properties and defined getters.
15826    Handle<Value> value = CompileRun(
15827        "function Foo() {"
15828        "    this.foo = 11;"
15829        "    this.__defineGetter__('baz', function() { return 1; });"
15830        "};"
15831        "function Bar() { "
15832        "    this.bar = 13;"
15833        "    this.__defineGetter__('bla', function() { return 2; });"
15834        "};"
15835        "Bar.prototype = new Foo();"
15836        "new Bar();");
15837    CHECK(value->IsObject());
15838    Handle<Object> object = value->ToObject();
15839    CHECK(object->Has(v8_str("foo")));
15840    CHECK(!object->HasOwnProperty(v8_str("foo")));
15841    CHECK(object->HasOwnProperty(v8_str("bar")));
15842    CHECK(object->Has(v8_str("baz")));
15843    CHECK(!object->HasOwnProperty(v8_str("baz")));
15844    CHECK(object->HasOwnProperty(v8_str("bla")));
15845  }
15846  { // Check named getter interceptors.
15847    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15848    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15849    Handle<Object> instance = templ->NewInstance();
15850    CHECK(!instance->HasOwnProperty(v8_str("42")));
15851    CHECK(instance->HasOwnProperty(v8_str("foo")));
15852    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15853  }
15854  { // Check indexed getter interceptors.
15855    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15856    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15857    Handle<Object> instance = templ->NewInstance();
15858    CHECK(instance->HasOwnProperty(v8_str("42")));
15859    CHECK(!instance->HasOwnProperty(v8_str("43")));
15860    CHECK(!instance->HasOwnProperty(v8_str("foo")));
15861  }
15862  { // Check named query interceptors.
15863    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15864    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15865    Handle<Object> instance = templ->NewInstance();
15866    CHECK(instance->HasOwnProperty(v8_str("foo")));
15867    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15868  }
15869  { // Check indexed query interceptors.
15870    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15871    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15872    Handle<Object> instance = templ->NewInstance();
15873    CHECK(instance->HasOwnProperty(v8_str("42")));
15874    CHECK(!instance->HasOwnProperty(v8_str("41")));
15875  }
15876  { // Check callbacks.
15877    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15878    templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15879    Handle<Object> instance = templ->NewInstance();
15880    CHECK(instance->HasOwnProperty(v8_str("foo")));
15881    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15882  }
15883  { // Check that query wins on disagreement.
15884    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15885    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15886                                   0,
15887                                   HasOwnPropertyNamedPropertyQuery2);
15888    Handle<Object> instance = templ->NewInstance();
15889    CHECK(!instance->HasOwnProperty(v8_str("foo")));
15890    CHECK(instance->HasOwnProperty(v8_str("bar")));
15891  }
15892}
15893
15894
15895void CheckCodeGenerationAllowed() {
15896  Handle<Value> result = CompileRun("eval('42')");
15897  CHECK_EQ(42, result->Int32Value());
15898  result = CompileRun("(function(e) { return e('42'); })(eval)");
15899  CHECK_EQ(42, result->Int32Value());
15900  result = CompileRun("var f = new Function('return 42'); f()");
15901  CHECK_EQ(42, result->Int32Value());
15902}
15903
15904
15905void CheckCodeGenerationDisallowed() {
15906  TryCatch try_catch;
15907
15908  Handle<Value> result = CompileRun("eval('42')");
15909  CHECK(result.IsEmpty());
15910  CHECK(try_catch.HasCaught());
15911  try_catch.Reset();
15912
15913  result = CompileRun("(function(e) { return e('42'); })(eval)");
15914  CHECK(result.IsEmpty());
15915  CHECK(try_catch.HasCaught());
15916  try_catch.Reset();
15917
15918  result = CompileRun("var f = new Function('return 42'); f()");
15919  CHECK(result.IsEmpty());
15920  CHECK(try_catch.HasCaught());
15921}
15922
15923
15924bool CodeGenerationAllowed(Local<Context> context) {
15925  ApiTestFuzzer::Fuzz();
15926  return true;
15927}
15928
15929
15930bool CodeGenerationDisallowed(Local<Context> context) {
15931  ApiTestFuzzer::Fuzz();
15932  return false;
15933}
15934
15935
15936THREADED_TEST(AllowCodeGenFromStrings) {
15937  v8::HandleScope scope;
15938  LocalContext context;
15939
15940  // eval and the Function constructor allowed by default.
15941  CHECK(context->IsCodeGenerationFromStringsAllowed());
15942  CheckCodeGenerationAllowed();
15943
15944  // Disallow eval and the Function constructor.
15945  context->AllowCodeGenerationFromStrings(false);
15946  CHECK(!context->IsCodeGenerationFromStringsAllowed());
15947  CheckCodeGenerationDisallowed();
15948
15949  // Allow again.
15950  context->AllowCodeGenerationFromStrings(true);
15951  CheckCodeGenerationAllowed();
15952
15953  // Disallow but setting a global callback that will allow the calls.
15954  context->AllowCodeGenerationFromStrings(false);
15955  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15956  CHECK(!context->IsCodeGenerationFromStringsAllowed());
15957  CheckCodeGenerationAllowed();
15958
15959  // Set a callback that disallows the code generation.
15960  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15961  CHECK(!context->IsCodeGenerationFromStringsAllowed());
15962  CheckCodeGenerationDisallowed();
15963}
15964
15965
15966static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15967  return v8::Undefined();
15968}
15969
15970
15971THREADED_TEST(CallAPIFunctionOnNonObject) {
15972  v8::HandleScope scope;
15973  LocalContext context;
15974  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15975  Handle<Function> function = templ->GetFunction();
15976  context->Global()->Set(v8_str("f"), function);
15977  TryCatch try_catch;
15978  CompileRun("f.call(2)");
15979}
15980
15981
15982// Regression test for issue 1470.
15983THREADED_TEST(ReadOnlyIndexedProperties) {
15984  v8::HandleScope scope;
15985  Local<ObjectTemplate> templ = ObjectTemplate::New();
15986
15987  LocalContext context;
15988  Local<v8::Object> obj = templ->NewInstance();
15989  context->Global()->Set(v8_str("obj"), obj);
15990  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15991  obj->Set(v8_str("1"), v8_str("foobar"));
15992  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15993  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15994  obj->Set(v8_num(2), v8_str("foobar"));
15995  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15996
15997  // Test non-smi case.
15998  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15999  obj->Set(v8_str("2000000000"), v8_str("foobar"));
16000  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16001}
16002
16003
16004THREADED_TEST(Regress1516) {
16005  v8::HandleScope scope;
16006
16007  LocalContext context;
16008  { v8::HandleScope temp_scope;
16009    CompileRun("({'a': 0})");
16010  }
16011
16012  int elements;
16013  { i::MapCache* map_cache =
16014        i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16015    elements = map_cache->NumberOfElements();
16016    CHECK_LE(1, elements);
16017  }
16018
16019  i::Isolate::Current()->heap()->CollectAllGarbage(true);
16020  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16021    if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16022      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16023      CHECK_GT(elements, map_cache->NumberOfElements());
16024    }
16025  }
16026}
16027
16028
16029static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16030                                                Local<Value> name,
16031                                                v8::AccessType type,
16032                                                Local<Value> data) {
16033  // Only block read access to __proto__.
16034  if (type == v8::ACCESS_GET &&
16035      name->IsString() &&
16036      name->ToString()->Length() == 9 &&
16037      name->ToString()->Utf8Length() == 9) {
16038    char buffer[10];
16039    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16040    return strncmp(buffer, "__proto__", 9) != 0;
16041  }
16042
16043  return true;
16044}
16045
16046
16047THREADED_TEST(Regress93759) {
16048  HandleScope scope;
16049
16050  // Template for object with security check.
16051  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16052  // We don't do indexing, so any callback can be used for that.
16053  no_proto_template->SetAccessCheckCallbacks(
16054      BlockProtoNamedSecurityTestCallback,
16055      IndexedSecurityTestCallback);
16056
16057  // Templates for objects with hidden prototypes and possibly security check.
16058  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16059  hidden_proto_template->SetHiddenPrototype(true);
16060
16061  Local<FunctionTemplate> protected_hidden_proto_template =
16062      v8::FunctionTemplate::New();
16063  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16064      BlockProtoNamedSecurityTestCallback,
16065      IndexedSecurityTestCallback);
16066  protected_hidden_proto_template->SetHiddenPrototype(true);
16067
16068  // Context for "foreign" objects used in test.
16069  Persistent<Context> context = v8::Context::New();
16070  context->Enter();
16071
16072  // Plain object, no security check.
16073  Local<Object> simple_object = Object::New();
16074
16075  // Object with explicit security check.
16076  Local<Object> protected_object =
16077      no_proto_template->NewInstance();
16078
16079  // JSGlobalProxy object, always have security check.
16080  Local<Object> proxy_object =
16081      context->Global();
16082
16083  // Global object, the  prototype of proxy_object. No security checks.
16084  Local<Object> global_object =
16085      proxy_object->GetPrototype()->ToObject();
16086
16087  // Hidden prototype without security check.
16088  Local<Object> hidden_prototype =
16089      hidden_proto_template->GetFunction()->NewInstance();
16090  Local<Object> object_with_hidden =
16091    Object::New();
16092  object_with_hidden->SetPrototype(hidden_prototype);
16093
16094  // Hidden prototype with security check on the hidden prototype.
16095  Local<Object> protected_hidden_prototype =
16096      protected_hidden_proto_template->GetFunction()->NewInstance();
16097  Local<Object> object_with_protected_hidden =
16098    Object::New();
16099  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16100
16101  context->Exit();
16102
16103  // Template for object for second context. Values to test are put on it as
16104  // properties.
16105  Local<ObjectTemplate> global_template = ObjectTemplate::New();
16106  global_template->Set(v8_str("simple"), simple_object);
16107  global_template->Set(v8_str("protected"), protected_object);
16108  global_template->Set(v8_str("global"), global_object);
16109  global_template->Set(v8_str("proxy"), proxy_object);
16110  global_template->Set(v8_str("hidden"), object_with_hidden);
16111  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
16112
16113  LocalContext context2(NULL, global_template);
16114
16115  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16116  CHECK(result1->Equals(simple_object->GetPrototype()));
16117
16118  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16119  CHECK(result2->Equals(Undefined()));
16120
16121  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16122  CHECK(result3->Equals(global_object->GetPrototype()));
16123
16124  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16125  CHECK(result4->Equals(Undefined()));
16126
16127  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16128  CHECK(result5->Equals(
16129      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16130
16131  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16132  CHECK(result6->Equals(Undefined()));
16133
16134  context.Dispose();
16135}
16136
16137
16138THREADED_TEST(Regress125988) {
16139  v8::HandleScope scope;
16140  Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16141  AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
16142  LocalContext env;
16143  env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
16144  CompileRun("var a = new Object();"
16145             "var b = new Intercept();"
16146             "var c = new Object();"
16147             "c.__proto__ = b;"
16148             "b.__proto__ = a;"
16149             "a.x = 23;"
16150             "for (var i = 0; i < 3; i++) c.x;");
16151  ExpectBoolean("c.hasOwnProperty('x')", false);
16152  ExpectInt32("c.x", 23);
16153  CompileRun("a.y = 42;"
16154             "for (var i = 0; i < 3; i++) c.x;");
16155  ExpectBoolean("c.hasOwnProperty('x')", false);
16156  ExpectInt32("c.x", 23);
16157  ExpectBoolean("c.hasOwnProperty('y')", false);
16158  ExpectInt32("c.y", 42);
16159}
16160
16161
16162static void TestReceiver(Local<Value> expected_result,
16163                         Local<Value> expected_receiver,
16164                         const char* code) {
16165  Local<Value> result = CompileRun(code);
16166  CHECK(result->IsObject());
16167  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
16168  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
16169}
16170
16171
16172THREADED_TEST(ForeignFunctionReceiver) {
16173  HandleScope scope;
16174
16175  // Create two contexts with different "id" properties ('i' and 'o').
16176  // Call a function both from its own context and from a the foreign
16177  // context, and see what "this" is bound to (returning both "this"
16178  // and "this.id" for comparison).
16179
16180  Persistent<Context> foreign_context = v8::Context::New();
16181  foreign_context->Enter();
16182  Local<Value> foreign_function =
16183    CompileRun("function func() { return { 0: this.id, "
16184               "                           1: this, "
16185               "                           toString: function() { "
16186               "                               return this[0];"
16187               "                           }"
16188               "                         };"
16189               "}"
16190               "var id = 'i';"
16191               "func;");
16192  CHECK(foreign_function->IsFunction());
16193  foreign_context->Exit();
16194
16195  LocalContext context;
16196
16197  Local<String> password = v8_str("Password");
16198  // Don't get hit by security checks when accessing foreign_context's
16199  // global receiver (aka. global proxy).
16200  context->SetSecurityToken(password);
16201  foreign_context->SetSecurityToken(password);
16202
16203  Local<String> i = v8_str("i");
16204  Local<String> o = v8_str("o");
16205  Local<String> id = v8_str("id");
16206
16207  CompileRun("function ownfunc() { return { 0: this.id, "
16208             "                              1: this, "
16209             "                              toString: function() { "
16210             "                                  return this[0];"
16211             "                              }"
16212             "                             };"
16213             "}"
16214             "var id = 'o';"
16215             "ownfunc");
16216  context->Global()->Set(v8_str("func"), foreign_function);
16217
16218  // Sanity check the contexts.
16219  CHECK(i->Equals(foreign_context->Global()->Get(id)));
16220  CHECK(o->Equals(context->Global()->Get(id)));
16221
16222  // Checking local function's receiver.
16223  // Calling function using its call/apply methods.
16224  TestReceiver(o, context->Global(), "ownfunc.call()");
16225  TestReceiver(o, context->Global(), "ownfunc.apply()");
16226  // Making calls through built-in functions.
16227  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
16228  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
16229  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
16230  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
16231  // Calling with environment record as base.
16232  TestReceiver(o, context->Global(), "ownfunc()");
16233  // Calling with no base.
16234  TestReceiver(o, context->Global(), "(1,ownfunc)()");
16235
16236  // Checking foreign function return value.
16237  // Calling function using its call/apply methods.
16238  TestReceiver(i, foreign_context->Global(), "func.call()");
16239  TestReceiver(i, foreign_context->Global(), "func.apply()");
16240  // Calling function using another context's call/apply methods.
16241  TestReceiver(i, foreign_context->Global(),
16242               "Function.prototype.call.call(func)");
16243  TestReceiver(i, foreign_context->Global(),
16244               "Function.prototype.call.apply(func)");
16245  TestReceiver(i, foreign_context->Global(),
16246               "Function.prototype.apply.call(func)");
16247  TestReceiver(i, foreign_context->Global(),
16248               "Function.prototype.apply.apply(func)");
16249  // Making calls through built-in functions.
16250  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
16251  // ToString(func()) is func()[0], i.e., the returned this.id.
16252  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
16253  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
16254  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
16255
16256  // TODO(1547): Make the following also return "i".
16257  // Calling with environment record as base.
16258  TestReceiver(o, context->Global(), "func()");
16259  // Calling with no base.
16260  TestReceiver(o, context->Global(), "(1,func)()");
16261
16262  foreign_context.Dispose();
16263}
16264
16265
16266uint8_t callback_fired = 0;
16267
16268
16269void CallCompletedCallback1() {
16270  i::OS::Print("Firing callback 1.\n");
16271  callback_fired ^= 1;  // Toggle first bit.
16272}
16273
16274
16275void CallCompletedCallback2() {
16276  i::OS::Print("Firing callback 2.\n");
16277  callback_fired ^= 2;  // Toggle second bit.
16278}
16279
16280
16281Handle<Value> RecursiveCall(const Arguments& args) {
16282  int32_t level = args[0]->Int32Value();
16283  if (level < 3) {
16284    level++;
16285    i::OS::Print("Entering recursion level %d.\n", level);
16286    char script[64];
16287    i::Vector<char> script_vector(script, sizeof(script));
16288    i::OS::SNPrintF(script_vector, "recursion(%d)", level);
16289    CompileRun(script_vector.start());
16290    i::OS::Print("Leaving recursion level %d.\n", level);
16291    CHECK_EQ(0, callback_fired);
16292  } else {
16293    i::OS::Print("Recursion ends.\n");
16294    CHECK_EQ(0, callback_fired);
16295  }
16296  return Undefined();
16297}
16298
16299
16300TEST(CallCompletedCallback) {
16301  v8::HandleScope scope;
16302  LocalContext env;
16303  v8::Handle<v8::FunctionTemplate> recursive_runtime =
16304      v8::FunctionTemplate::New(RecursiveCall);
16305  env->Global()->Set(v8_str("recursion"),
16306                     recursive_runtime->GetFunction());
16307  // Adding the same callback a second time has no effect.
16308  v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
16309  v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
16310  v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
16311  i::OS::Print("--- Script (1) ---\n");
16312  Local<Script> script =
16313      v8::Script::Compile(v8::String::New("recursion(0)"));
16314  script->Run();
16315  CHECK_EQ(3, callback_fired);
16316
16317  i::OS::Print("\n--- Script (2) ---\n");
16318  callback_fired = 0;
16319  v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
16320  script->Run();
16321  CHECK_EQ(2, callback_fired);
16322
16323  i::OS::Print("\n--- Function ---\n");
16324  callback_fired = 0;
16325  Local<Function> recursive_function =
16326      Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
16327  v8::Handle<Value> args[] = { v8_num(0) };
16328  recursive_function->Call(env->Global(), 1, args);
16329  CHECK_EQ(2, callback_fired);
16330}
16331
16332
16333void CallCompletedCallbackNoException() {
16334  v8::HandleScope scope;
16335  CompileRun("1+1;");
16336}
16337
16338
16339void CallCompletedCallbackException() {
16340  v8::HandleScope scope;
16341  CompileRun("throw 'second exception';");
16342}
16343
16344
16345TEST(CallCompletedCallbackOneException) {
16346  v8::HandleScope scope;
16347  LocalContext env;
16348  v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
16349  CompileRun("throw 'exception';");
16350}
16351
16352
16353TEST(CallCompletedCallbackTwoExceptions) {
16354  v8::HandleScope scope;
16355  LocalContext env;
16356  v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
16357  CompileRun("throw 'first exception';");
16358}
16359
16360
16361static int probes_counter = 0;
16362static int misses_counter = 0;
16363static int updates_counter = 0;
16364
16365
16366static int* LookupCounter(const char* name) {
16367  if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
16368    return &probes_counter;
16369  } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
16370    return &misses_counter;
16371  } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
16372    return &updates_counter;
16373  }
16374  return NULL;
16375}
16376
16377
16378static const char* kMegamorphicTestProgram =
16379    "function ClassA() { };"
16380    "function ClassB() { };"
16381    "ClassA.prototype.foo = function() { };"
16382    "ClassB.prototype.foo = function() { };"
16383    "function fooify(obj) { obj.foo(); };"
16384    "var a = new ClassA();"
16385    "var b = new ClassB();"
16386    "for (var i = 0; i < 10000; i++) {"
16387    "  fooify(a);"
16388    "  fooify(b);"
16389    "}";
16390
16391
16392static void StubCacheHelper(bool primary) {
16393  V8::SetCounterFunction(LookupCounter);
16394  USE(kMegamorphicTestProgram);
16395#ifdef DEBUG
16396  i::FLAG_native_code_counters = true;
16397  if (primary) {
16398    i::FLAG_test_primary_stub_cache = true;
16399  } else {
16400    i::FLAG_test_secondary_stub_cache = true;
16401  }
16402  i::FLAG_crankshaft = false;
16403  v8::HandleScope scope;
16404  LocalContext env;
16405  int initial_probes = probes_counter;
16406  int initial_misses = misses_counter;
16407  int initial_updates = updates_counter;
16408  CompileRun(kMegamorphicTestProgram);
16409  int probes = probes_counter - initial_probes;
16410  int misses = misses_counter - initial_misses;
16411  int updates = updates_counter - initial_updates;
16412  CHECK_LT(updates, 10);
16413  CHECK_LT(misses, 10);
16414  CHECK_GE(probes, 10000);
16415#endif
16416}
16417
16418
16419TEST(SecondaryStubCache) {
16420  StubCacheHelper(true);
16421}
16422
16423
16424TEST(PrimaryStubCache) {
16425  StubCacheHelper(false);
16426}
16427
16428