test-api.cc revision 592a9fc1d8ea420377a2e7efd0600e20b058be2b
1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <limits.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "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  // TODO(1608): This should use kAbortIncrementalMarking.
454  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
455  CHECK_EQ(1, dispose_count);
456}
457
458
459THREADED_TEST(ScriptMakingExternalAsciiString) {
460  int dispose_count = 0;
461  const char* c_source = "1 + 2 * 3";
462  {
463    v8::HandleScope scope;
464    LocalContext env;
465    Local<String> source = v8_str(c_source);
466    // Trigger GCs so that the newly allocated string moves to old gen.
467    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
468    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
469    bool success = source->MakeExternal(
470        new TestAsciiResource(i::StrDup(c_source), &dispose_count));
471    CHECK(success);
472    Local<Script> script = Script::Compile(source);
473    Local<Value> value = script->Run();
474    CHECK(value->IsNumber());
475    CHECK_EQ(7, value->Int32Value());
476    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
477    CHECK_EQ(0, dispose_count);
478  }
479  i::Isolate::Current()->compilation_cache()->Clear();
480  // TODO(1608): This should use kAbortIncrementalMarking.
481  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
482  CHECK_EQ(1, dispose_count);
483}
484
485
486TEST(MakingExternalStringConditions) {
487  v8::HandleScope scope;
488  LocalContext env;
489
490  // Free some space in the new space so that we can check freshness.
491  HEAP->CollectGarbage(i::NEW_SPACE);
492  HEAP->CollectGarbage(i::NEW_SPACE);
493
494  uint16_t* two_byte_string = AsciiToTwoByteString("s1");
495  Local<String> small_string = String::New(two_byte_string);
496  i::DeleteArray(two_byte_string);
497
498  // We should refuse to externalize newly created small string.
499  CHECK(!small_string->CanMakeExternal());
500  // Trigger GCs so that the newly allocated string moves to old gen.
501  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
502  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
503  // Old space strings should be accepted.
504  CHECK(small_string->CanMakeExternal());
505
506  two_byte_string = AsciiToTwoByteString("small string 2");
507  small_string = String::New(two_byte_string);
508  i::DeleteArray(two_byte_string);
509
510  // We should refuse externalizing newly created small string.
511  CHECK(!small_string->CanMakeExternal());
512  for (int i = 0; i < 100; i++) {
513    String::Value value(small_string);
514  }
515  // Frequently used strings should be accepted.
516  CHECK(small_string->CanMakeExternal());
517
518  const int buf_size = 10 * 1024;
519  char* buf = i::NewArray<char>(buf_size);
520  memset(buf, 'a', buf_size);
521  buf[buf_size - 1] = '\0';
522
523  two_byte_string = AsciiToTwoByteString(buf);
524  Local<String> large_string = String::New(two_byte_string);
525  i::DeleteArray(buf);
526  i::DeleteArray(two_byte_string);
527  // Large strings should be immediately accepted.
528  CHECK(large_string->CanMakeExternal());
529}
530
531
532TEST(MakingExternalAsciiStringConditions) {
533  v8::HandleScope scope;
534  LocalContext env;
535
536  // Free some space in the new space so that we can check freshness.
537  HEAP->CollectGarbage(i::NEW_SPACE);
538  HEAP->CollectGarbage(i::NEW_SPACE);
539
540  Local<String> small_string = String::New("s1");
541  // We should refuse to externalize newly created small string.
542  CHECK(!small_string->CanMakeExternal());
543  // Trigger GCs so that the newly allocated string moves to old gen.
544  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
545  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
546  // Old space strings should be accepted.
547  CHECK(small_string->CanMakeExternal());
548
549  small_string = String::New("small string 2");
550  // We should refuse externalizing newly created small string.
551  CHECK(!small_string->CanMakeExternal());
552  for (int i = 0; i < 100; i++) {
553    String::Value value(small_string);
554  }
555  // Frequently used strings should be accepted.
556  CHECK(small_string->CanMakeExternal());
557
558  const int buf_size = 10 * 1024;
559  char* buf = i::NewArray<char>(buf_size);
560  memset(buf, 'a', buf_size);
561  buf[buf_size - 1] = '\0';
562  Local<String> large_string = String::New(buf);
563  i::DeleteArray(buf);
564  // Large strings should be immediately accepted.
565  CHECK(large_string->CanMakeExternal());
566}
567
568
569THREADED_TEST(UsingExternalString) {
570  {
571    v8::HandleScope scope;
572    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
573    Local<String> string =
574        String::NewExternal(new TestResource(two_byte_string));
575    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
576    // Trigger GCs so that the newly allocated string moves to old gen.
577    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
578    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
579    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
580    CHECK(isymbol->IsSymbol());
581  }
582  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
583  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
584}
585
586
587THREADED_TEST(UsingExternalAsciiString) {
588  {
589    v8::HandleScope scope;
590    const char* one_byte_string = "test string";
591    Local<String> string = String::NewExternal(
592        new TestAsciiResource(i::StrDup(one_byte_string)));
593    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
594    // Trigger GCs so that the newly allocated string moves to old gen.
595    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
596    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
597    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
598    CHECK(isymbol->IsSymbol());
599  }
600  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
601  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
602}
603
604
605THREADED_TEST(ScavengeExternalString) {
606  int dispose_count = 0;
607  bool in_new_space = false;
608  {
609    v8::HandleScope scope;
610    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
611    Local<String> string =
612      String::NewExternal(new TestResource(two_byte_string,
613                                           &dispose_count));
614    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
615    HEAP->CollectGarbage(i::NEW_SPACE);
616    in_new_space = HEAP->InNewSpace(*istring);
617    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
618    CHECK_EQ(0, dispose_count);
619  }
620  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
621  CHECK_EQ(1, dispose_count);
622}
623
624
625THREADED_TEST(ScavengeExternalAsciiString) {
626  int dispose_count = 0;
627  bool in_new_space = false;
628  {
629    v8::HandleScope scope;
630    const char* one_byte_string = "test string";
631    Local<String> string = String::NewExternal(
632        new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
633    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
634    HEAP->CollectGarbage(i::NEW_SPACE);
635    in_new_space = HEAP->InNewSpace(*istring);
636    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
637    CHECK_EQ(0, dispose_count);
638  }
639  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
640  CHECK_EQ(1, dispose_count);
641}
642
643
644class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
645 public:
646  // Only used by non-threaded tests, so it can use static fields.
647  static int dispose_calls;
648  static int dispose_count;
649
650  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651      : TestAsciiResource(data, &dispose_count),
652        dispose_(dispose) { }
653
654  void Dispose() {
655    ++dispose_calls;
656    if (dispose_) delete this;
657  }
658 private:
659  bool dispose_;
660};
661
662
663int TestAsciiResourceWithDisposeControl::dispose_count = 0;
664int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
665
666
667TEST(ExternalStringWithDisposeHandling) {
668  const char* c_source = "1 + 2 * 3";
669
670  // Use a stack allocated external string resource allocated object.
671  TestAsciiResourceWithDisposeControl::dispose_count = 0;
672  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
673  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
674  {
675    v8::HandleScope scope;
676    LocalContext env;
677    Local<String> source =  String::NewExternal(&res_stack);
678    Local<Script> script = Script::Compile(source);
679    Local<Value> value = script->Run();
680    CHECK(value->IsNumber());
681    CHECK_EQ(7, value->Int32Value());
682    HEAP->CollectAllAvailableGarbage();
683    CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
684  }
685  i::Isolate::Current()->compilation_cache()->Clear();
686  HEAP->CollectAllAvailableGarbage();
687  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
688  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
689
690  // Use a heap allocated external string resource allocated object.
691  TestAsciiResourceWithDisposeControl::dispose_count = 0;
692  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693  TestAsciiResource* res_heap =
694      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
695  {
696    v8::HandleScope scope;
697    LocalContext env;
698    Local<String> source =  String::NewExternal(res_heap);
699    Local<Script> script = Script::Compile(source);
700    Local<Value> value = script->Run();
701    CHECK(value->IsNumber());
702    CHECK_EQ(7, value->Int32Value());
703    HEAP->CollectAllAvailableGarbage();
704    CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
705  }
706  i::Isolate::Current()->compilation_cache()->Clear();
707  HEAP->CollectAllAvailableGarbage();
708  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
709  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
710}
711
712
713THREADED_TEST(StringConcat) {
714  {
715    v8::HandleScope scope;
716    LocalContext env;
717    const char* one_byte_string_1 = "function a_times_t";
718    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
719    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
720    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
721    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
723    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
724    Local<String> left = v8_str(one_byte_string_1);
725
726    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
727    Local<String> right = String::New(two_byte_source);
728    i::DeleteArray(two_byte_source);
729
730    Local<String> source = String::Concat(left, right);
731    right = String::NewExternal(
732        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
733    source = String::Concat(source, right);
734    right = String::NewExternal(
735        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
736    source = String::Concat(source, right);
737    right = v8_str(one_byte_string_2);
738    source = String::Concat(source, right);
739
740    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
741    right = String::New(two_byte_source);
742    i::DeleteArray(two_byte_source);
743
744    source = String::Concat(source, right);
745    right = String::NewExternal(
746        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
747    source = String::Concat(source, right);
748    Local<Script> script = Script::Compile(source);
749    Local<Value> value = script->Run();
750    CHECK(value->IsNumber());
751    CHECK_EQ(68, value->Int32Value());
752  }
753  i::Isolate::Current()->compilation_cache()->Clear();
754  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
755  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
756}
757
758
759THREADED_TEST(GlobalProperties) {
760  v8::HandleScope scope;
761  LocalContext env;
762  v8::Handle<v8::Object> global = env->Global();
763  global->Set(v8_str("pi"), v8_num(3.1415926));
764  Local<Value> pi = global->Get(v8_str("pi"));
765  CHECK_EQ(3.1415926, pi->NumberValue());
766}
767
768
769static v8::Handle<Value> handle_call(const v8::Arguments& args) {
770  ApiTestFuzzer::Fuzz();
771  return v8_num(102);
772}
773
774
775static v8::Handle<Value> construct_call(const v8::Arguments& args) {
776  ApiTestFuzzer::Fuzz();
777  args.This()->Set(v8_str("x"), v8_num(1));
778  args.This()->Set(v8_str("y"), v8_num(2));
779  return args.This();
780}
781
782static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
783  ApiTestFuzzer::Fuzz();
784  return v8_num(239);
785}
786
787
788THREADED_TEST(FunctionTemplate) {
789  v8::HandleScope scope;
790  LocalContext env;
791  {
792    Local<v8::FunctionTemplate> fun_templ =
793        v8::FunctionTemplate::New(handle_call);
794    Local<Function> fun = fun_templ->GetFunction();
795    env->Global()->Set(v8_str("obj"), fun);
796    Local<Script> script = v8_compile("obj()");
797    CHECK_EQ(102, script->Run()->Int32Value());
798  }
799  // Use SetCallHandler to initialize a function template, should work like the
800  // previous one.
801  {
802    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
803    fun_templ->SetCallHandler(handle_call);
804    Local<Function> fun = fun_templ->GetFunction();
805    env->Global()->Set(v8_str("obj"), fun);
806    Local<Script> script = v8_compile("obj()");
807    CHECK_EQ(102, script->Run()->Int32Value());
808  }
809  // Test constructor calls.
810  {
811    Local<v8::FunctionTemplate> fun_templ =
812        v8::FunctionTemplate::New(construct_call);
813    fun_templ->SetClassName(v8_str("funky"));
814    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
815    Local<Function> fun = fun_templ->GetFunction();
816    env->Global()->Set(v8_str("obj"), fun);
817    Local<Script> script = v8_compile("var s = new obj(); s.x");
818    CHECK_EQ(1, script->Run()->Int32Value());
819
820    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
821    CHECK_EQ(v8_str("[object funky]"), result);
822
823    result = v8_compile("(new obj()).m")->Run();
824    CHECK_EQ(239, result->Int32Value());
825  }
826}
827
828
829static void* expected_ptr;
830static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
831  void* ptr = v8::External::Unwrap(args.Data());
832  CHECK_EQ(expected_ptr, ptr);
833  return v8::True();
834}
835
836
837static void TestExternalPointerWrapping() {
838  v8::HandleScope scope;
839  LocalContext env;
840
841  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
842
843  v8::Handle<v8::Object> obj = v8::Object::New();
844  obj->Set(v8_str("func"),
845           v8::FunctionTemplate::New(callback, data)->GetFunction());
846  env->Global()->Set(v8_str("obj"), obj);
847
848  CHECK(CompileRun(
849        "function foo() {\n"
850        "  for (var i = 0; i < 13; i++) obj.func();\n"
851        "}\n"
852        "foo(), true")->BooleanValue());
853}
854
855
856THREADED_TEST(ExternalWrap) {
857  // Check heap allocated object.
858  int* ptr = new int;
859  expected_ptr = ptr;
860  TestExternalPointerWrapping();
861  delete ptr;
862
863  // Check stack allocated object.
864  int foo;
865  expected_ptr = &foo;
866  TestExternalPointerWrapping();
867
868  // Check not aligned addresses.
869  const int n = 100;
870  char* s = new char[n];
871  for (int i = 0; i < n; i++) {
872    expected_ptr = s + i;
873    TestExternalPointerWrapping();
874  }
875
876  delete[] s;
877
878  // Check several invalid addresses.
879  expected_ptr = reinterpret_cast<void*>(1);
880  TestExternalPointerWrapping();
881
882  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
883  TestExternalPointerWrapping();
884
885  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
886  TestExternalPointerWrapping();
887
888#if defined(V8_HOST_ARCH_X64)
889  // Check a value with a leading 1 bit in x64 Smi encoding.
890  expected_ptr = reinterpret_cast<void*>(0x400000000);
891  TestExternalPointerWrapping();
892
893  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
894  TestExternalPointerWrapping();
895
896  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
897  TestExternalPointerWrapping();
898#endif
899}
900
901
902THREADED_TEST(FindInstanceInPrototypeChain) {
903  v8::HandleScope scope;
904  LocalContext env;
905
906  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
907  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
908  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
909  derived->Inherit(base);
910
911  Local<v8::Function> base_function = base->GetFunction();
912  Local<v8::Function> derived_function = derived->GetFunction();
913  Local<v8::Function> other_function = other->GetFunction();
914
915  Local<v8::Object> base_instance = base_function->NewInstance();
916  Local<v8::Object> derived_instance = derived_function->NewInstance();
917  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
918  Local<v8::Object> other_instance = other_function->NewInstance();
919  derived_instance2->Set(v8_str("__proto__"), derived_instance);
920  other_instance->Set(v8_str("__proto__"), derived_instance2);
921
922  // base_instance is only an instance of base.
923  CHECK_EQ(base_instance,
924           base_instance->FindInstanceInPrototypeChain(base));
925  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
926  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
927
928  // derived_instance is an instance of base and derived.
929  CHECK_EQ(derived_instance,
930           derived_instance->FindInstanceInPrototypeChain(base));
931  CHECK_EQ(derived_instance,
932           derived_instance->FindInstanceInPrototypeChain(derived));
933  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
934
935  // other_instance is an instance of other and its immediate
936  // prototype derived_instance2 is an instance of base and derived.
937  // Note, derived_instance is an instance of base and derived too,
938  // but it comes after derived_instance2 in the prototype chain of
939  // other_instance.
940  CHECK_EQ(derived_instance2,
941           other_instance->FindInstanceInPrototypeChain(base));
942  CHECK_EQ(derived_instance2,
943           other_instance->FindInstanceInPrototypeChain(derived));
944  CHECK_EQ(other_instance,
945           other_instance->FindInstanceInPrototypeChain(other));
946}
947
948
949THREADED_TEST(TinyInteger) {
950  v8::HandleScope scope;
951  LocalContext env;
952  int32_t value = 239;
953  Local<v8::Integer> value_obj = v8::Integer::New(value);
954  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
955}
956
957
958THREADED_TEST(BigSmiInteger) {
959  v8::HandleScope scope;
960  LocalContext env;
961  int32_t value = i::Smi::kMaxValue;
962  // We cannot add one to a Smi::kMaxValue without wrapping.
963  if (i::kSmiValueSize < 32) {
964    CHECK(i::Smi::IsValid(value));
965    CHECK(!i::Smi::IsValid(value + 1));
966    Local<v8::Integer> value_obj = v8::Integer::New(value);
967    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
968  }
969}
970
971
972THREADED_TEST(BigInteger) {
973  v8::HandleScope scope;
974  LocalContext env;
975  // We cannot add one to a Smi::kMaxValue without wrapping.
976  if (i::kSmiValueSize < 32) {
977    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
978    // The code will not be run in that case, due to the "if" guard.
979    int32_t value =
980        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
981    CHECK(value > i::Smi::kMaxValue);
982    CHECK(!i::Smi::IsValid(value));
983    Local<v8::Integer> value_obj = v8::Integer::New(value);
984    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
985  }
986}
987
988
989THREADED_TEST(TinyUnsignedInteger) {
990  v8::HandleScope scope;
991  LocalContext env;
992  uint32_t value = 239;
993  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
994  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
995}
996
997
998THREADED_TEST(BigUnsignedSmiInteger) {
999  v8::HandleScope scope;
1000  LocalContext env;
1001  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1002  CHECK(i::Smi::IsValid(value));
1003  CHECK(!i::Smi::IsValid(value + 1));
1004  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1005  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1006}
1007
1008
1009THREADED_TEST(BigUnsignedInteger) {
1010  v8::HandleScope scope;
1011  LocalContext env;
1012  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1013  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1014  CHECK(!i::Smi::IsValid(value));
1015  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1016  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1017}
1018
1019
1020THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1021  v8::HandleScope scope;
1022  LocalContext env;
1023  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1024  uint32_t value = INT32_MAX_AS_UINT + 1;
1025  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1026  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1027  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1028}
1029
1030
1031THREADED_TEST(IsNativeError) {
1032  v8::HandleScope scope;
1033  LocalContext env;
1034  v8::Handle<Value> syntax_error = CompileRun(
1035      "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1036  CHECK(syntax_error->IsNativeError());
1037  v8::Handle<Value> not_error = CompileRun("{a:42}");
1038  CHECK(!not_error->IsNativeError());
1039  v8::Handle<Value> not_object = CompileRun("42");
1040  CHECK(!not_object->IsNativeError());
1041}
1042
1043
1044THREADED_TEST(StringObject) {
1045  v8::HandleScope scope;
1046  LocalContext env;
1047  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1048  CHECK(boxed_string->IsStringObject());
1049  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1050  CHECK(!unboxed_string->IsStringObject());
1051  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1052  CHECK(!boxed_not_string->IsStringObject());
1053  v8::Handle<Value> not_object = CompileRun("0");
1054  CHECK(!not_object->IsStringObject());
1055  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1056  CHECK(!as_boxed.IsEmpty());
1057  Local<v8::String> the_string = as_boxed->StringValue();
1058  CHECK(!the_string.IsEmpty());
1059  ExpectObject("\"test\"", the_string);
1060  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1061  CHECK(new_boxed_string->IsStringObject());
1062  as_boxed = new_boxed_string.As<v8::StringObject>();
1063  the_string = as_boxed->StringValue();
1064  CHECK(!the_string.IsEmpty());
1065  ExpectObject("\"test\"", the_string);
1066}
1067
1068
1069THREADED_TEST(NumberObject) {
1070  v8::HandleScope scope;
1071  LocalContext env;
1072  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1073  CHECK(boxed_number->IsNumberObject());
1074  v8::Handle<Value> unboxed_number = CompileRun("42");
1075  CHECK(!unboxed_number->IsNumberObject());
1076  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1077  CHECK(!boxed_not_number->IsNumberObject());
1078  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1079  CHECK(!as_boxed.IsEmpty());
1080  double the_number = as_boxed->NumberValue();
1081  CHECK_EQ(42.0, the_number);
1082  v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1083  CHECK(new_boxed_number->IsNumberObject());
1084  as_boxed = new_boxed_number.As<v8::NumberObject>();
1085  the_number = as_boxed->NumberValue();
1086  CHECK_EQ(43.0, the_number);
1087}
1088
1089
1090THREADED_TEST(BooleanObject) {
1091  v8::HandleScope scope;
1092  LocalContext env;
1093  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1094  CHECK(boxed_boolean->IsBooleanObject());
1095  v8::Handle<Value> unboxed_boolean = CompileRun("true");
1096  CHECK(!unboxed_boolean->IsBooleanObject());
1097  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1098  CHECK(!boxed_not_boolean->IsBooleanObject());
1099  v8::Handle<v8::BooleanObject> as_boxed =
1100      boxed_boolean.As<v8::BooleanObject>();
1101  CHECK(!as_boxed.IsEmpty());
1102  bool the_boolean = as_boxed->BooleanValue();
1103  CHECK_EQ(true, the_boolean);
1104  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1105  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1106  CHECK(boxed_true->IsBooleanObject());
1107  CHECK(boxed_false->IsBooleanObject());
1108  as_boxed = boxed_true.As<v8::BooleanObject>();
1109  CHECK_EQ(true, as_boxed->BooleanValue());
1110  as_boxed = boxed_false.As<v8::BooleanObject>();
1111  CHECK_EQ(false, as_boxed->BooleanValue());
1112}
1113
1114
1115THREADED_TEST(Number) {
1116  v8::HandleScope scope;
1117  LocalContext env;
1118  double PI = 3.1415926;
1119  Local<v8::Number> pi_obj = v8::Number::New(PI);
1120  CHECK_EQ(PI, pi_obj->NumberValue());
1121}
1122
1123
1124THREADED_TEST(ToNumber) {
1125  v8::HandleScope scope;
1126  LocalContext env;
1127  Local<String> str = v8_str("3.1415926");
1128  CHECK_EQ(3.1415926, str->NumberValue());
1129  v8::Handle<v8::Boolean> t = v8::True();
1130  CHECK_EQ(1.0, t->NumberValue());
1131  v8::Handle<v8::Boolean> f = v8::False();
1132  CHECK_EQ(0.0, f->NumberValue());
1133}
1134
1135
1136THREADED_TEST(Date) {
1137  v8::HandleScope scope;
1138  LocalContext env;
1139  double PI = 3.1415926;
1140  Local<Value> date = v8::Date::New(PI);
1141  CHECK_EQ(3.0, date->NumberValue());
1142  date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1143  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1144}
1145
1146
1147THREADED_TEST(Boolean) {
1148  v8::HandleScope scope;
1149  LocalContext env;
1150  v8::Handle<v8::Boolean> t = v8::True();
1151  CHECK(t->Value());
1152  v8::Handle<v8::Boolean> f = v8::False();
1153  CHECK(!f->Value());
1154  v8::Handle<v8::Primitive> u = v8::Undefined();
1155  CHECK(!u->BooleanValue());
1156  v8::Handle<v8::Primitive> n = v8::Null();
1157  CHECK(!n->BooleanValue());
1158  v8::Handle<String> str1 = v8_str("");
1159  CHECK(!str1->BooleanValue());
1160  v8::Handle<String> str2 = v8_str("x");
1161  CHECK(str2->BooleanValue());
1162  CHECK(!v8::Number::New(0)->BooleanValue());
1163  CHECK(v8::Number::New(-1)->BooleanValue());
1164  CHECK(v8::Number::New(1)->BooleanValue());
1165  CHECK(v8::Number::New(42)->BooleanValue());
1166  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1167}
1168
1169
1170static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1171  ApiTestFuzzer::Fuzz();
1172  return v8_num(13.4);
1173}
1174
1175
1176static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1177  ApiTestFuzzer::Fuzz();
1178  return v8_num(876);
1179}
1180
1181
1182THREADED_TEST(GlobalPrototype) {
1183  v8::HandleScope scope;
1184  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1185  func_templ->PrototypeTemplate()->Set(
1186      "dummy",
1187      v8::FunctionTemplate::New(DummyCallHandler));
1188  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1189  templ->Set("x", v8_num(200));
1190  templ->SetAccessor(v8_str("m"), GetM);
1191  LocalContext env(0, templ);
1192  v8::Handle<v8::Object> obj(env->Global());
1193  v8::Handle<Script> script(v8_compile("dummy()"));
1194  v8::Handle<Value> result(script->Run());
1195  CHECK_EQ(13.4, result->NumberValue());
1196  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1197  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1198}
1199
1200
1201THREADED_TEST(ObjectTemplate) {
1202  v8::HandleScope scope;
1203  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1204  templ1->Set("x", v8_num(10));
1205  templ1->Set("y", v8_num(13));
1206  LocalContext env;
1207  Local<v8::Object> instance1 = templ1->NewInstance();
1208  env->Global()->Set(v8_str("p"), instance1);
1209  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1210  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1211  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1212  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1213  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1214  templ2->Set("a", v8_num(12));
1215  templ2->Set("b", templ1);
1216  Local<v8::Object> instance2 = templ2->NewInstance();
1217  env->Global()->Set(v8_str("q"), instance2);
1218  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1219  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1220  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1221  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1222}
1223
1224
1225static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1226  ApiTestFuzzer::Fuzz();
1227  return v8_num(17.2);
1228}
1229
1230
1231static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1232  ApiTestFuzzer::Fuzz();
1233  return v8_num(15.2);
1234}
1235
1236
1237THREADED_TEST(DescriptorInheritance) {
1238  v8::HandleScope scope;
1239  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1240  super->PrototypeTemplate()->Set("flabby",
1241                                  v8::FunctionTemplate::New(GetFlabby));
1242  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1243
1244  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1245
1246  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1247  base1->Inherit(super);
1248  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1249
1250  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1251  base2->Inherit(super);
1252  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1253
1254  LocalContext env;
1255
1256  env->Global()->Set(v8_str("s"), super->GetFunction());
1257  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1258  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1259
1260  // Checks right __proto__ chain.
1261  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1262  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1263
1264  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1265
1266  // Instance accessor should not be visible on function object or its prototype
1267  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1268  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1269  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1270
1271  env->Global()->Set(v8_str("obj"),
1272                     base1->GetFunction()->NewInstance());
1273  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1274  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1275  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1276  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1277  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1278
1279  env->Global()->Set(v8_str("obj2"),
1280                     base2->GetFunction()->NewInstance());
1281  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1282  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1283  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1284  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1285  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1286
1287  // base1 and base2 cannot cross reference to each's prototype
1288  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1289  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1290}
1291
1292
1293int echo_named_call_count;
1294
1295
1296static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1297                                           const AccessorInfo& info) {
1298  ApiTestFuzzer::Fuzz();
1299  CHECK_EQ(v8_str("data"), info.Data());
1300  echo_named_call_count++;
1301  return name;
1302}
1303
1304// Helper functions for Interceptor/Accessor interaction tests
1305
1306Handle<Value> SimpleAccessorGetter(Local<String> name,
1307                                   const AccessorInfo& info) {
1308  Handle<Object> self = info.This();
1309  return self->Get(String::Concat(v8_str("accessor_"), name));
1310}
1311
1312void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1313                          const AccessorInfo& info) {
1314  Handle<Object> self = info.This();
1315  self->Set(String::Concat(v8_str("accessor_"), name), value);
1316}
1317
1318Handle<Value> EmptyInterceptorGetter(Local<String> name,
1319                                     const AccessorInfo& info) {
1320  return Handle<Value>();
1321}
1322
1323Handle<Value> EmptyInterceptorSetter(Local<String> name,
1324                                     Local<Value> value,
1325                                     const AccessorInfo& info) {
1326  return Handle<Value>();
1327}
1328
1329Handle<Value> InterceptorGetter(Local<String> name,
1330                                const AccessorInfo& info) {
1331  // Intercept names that start with 'interceptor_'.
1332  String::AsciiValue ascii(name);
1333  char* name_str = *ascii;
1334  char prefix[] = "interceptor_";
1335  int i;
1336  for (i = 0; name_str[i] && prefix[i]; ++i) {
1337    if (name_str[i] != prefix[i]) return Handle<Value>();
1338  }
1339  Handle<Object> self = info.This();
1340  return self->GetHiddenValue(v8_str(name_str + i));
1341}
1342
1343Handle<Value> InterceptorSetter(Local<String> name,
1344                                Local<Value> value,
1345                                const AccessorInfo& info) {
1346  // Intercept accesses that set certain integer values.
1347  if (value->IsInt32() && value->Int32Value() < 10000) {
1348    Handle<Object> self = info.This();
1349    self->SetHiddenValue(name, value);
1350    return value;
1351  }
1352  return Handle<Value>();
1353}
1354
1355void AddAccessor(Handle<FunctionTemplate> templ,
1356                 Handle<String> name,
1357                 v8::AccessorGetter getter,
1358                 v8::AccessorSetter setter) {
1359  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1360}
1361
1362void AddInterceptor(Handle<FunctionTemplate> templ,
1363                    v8::NamedPropertyGetter getter,
1364                    v8::NamedPropertySetter setter) {
1365  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1366}
1367
1368THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1369  v8::HandleScope scope;
1370  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1371  Handle<FunctionTemplate> child = FunctionTemplate::New();
1372  child->Inherit(parent);
1373  AddAccessor(parent, v8_str("age"),
1374              SimpleAccessorGetter, SimpleAccessorSetter);
1375  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1376  LocalContext env;
1377  env->Global()->Set(v8_str("Child"), child->GetFunction());
1378  CompileRun("var child = new Child;"
1379             "child.age = 10;");
1380  ExpectBoolean("child.hasOwnProperty('age')", false);
1381  ExpectInt32("child.age", 10);
1382  ExpectInt32("child.accessor_age", 10);
1383}
1384
1385THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1386  v8::HandleScope scope;
1387  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1388  Handle<FunctionTemplate> child = FunctionTemplate::New();
1389  child->Inherit(parent);
1390  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1391  LocalContext env;
1392  env->Global()->Set(v8_str("Child"), child->GetFunction());
1393  CompileRun("var child = new Child;"
1394             "var parent = child.__proto__;"
1395             "Object.defineProperty(parent, 'age', "
1396             "  {get: function(){ return this.accessor_age; }, "
1397             "   set: function(v){ this.accessor_age = v; }, "
1398             "   enumerable: true, configurable: true});"
1399             "child.age = 10;");
1400  ExpectBoolean("child.hasOwnProperty('age')", false);
1401  ExpectInt32("child.age", 10);
1402  ExpectInt32("child.accessor_age", 10);
1403}
1404
1405THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1406  v8::HandleScope scope;
1407  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1408  Handle<FunctionTemplate> child = FunctionTemplate::New();
1409  child->Inherit(parent);
1410  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1411  LocalContext env;
1412  env->Global()->Set(v8_str("Child"), child->GetFunction());
1413  CompileRun("var child = new Child;"
1414             "var parent = child.__proto__;"
1415             "parent.name = 'Alice';");
1416  ExpectBoolean("child.hasOwnProperty('name')", false);
1417  ExpectString("child.name", "Alice");
1418  CompileRun("child.name = 'Bob';");
1419  ExpectString("child.name", "Bob");
1420  ExpectBoolean("child.hasOwnProperty('name')", true);
1421  ExpectString("parent.name", "Alice");
1422}
1423
1424THREADED_TEST(SwitchFromInterceptorToAccessor) {
1425  v8::HandleScope scope;
1426  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1427  Handle<FunctionTemplate> child = FunctionTemplate::New();
1428  child->Inherit(parent);
1429  AddAccessor(parent, v8_str("age"),
1430              SimpleAccessorGetter, SimpleAccessorSetter);
1431  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1432  LocalContext env;
1433  env->Global()->Set(v8_str("Child"), child->GetFunction());
1434  CompileRun("var child = new Child;"
1435             "function setAge(i){ child.age = i; };"
1436             "for(var i = 0; i <= 10000; i++) setAge(i);");
1437  // All i < 10000 go to the interceptor.
1438  ExpectInt32("child.interceptor_age", 9999);
1439  // The last i goes to the accessor.
1440  ExpectInt32("child.accessor_age", 10000);
1441}
1442
1443THREADED_TEST(SwitchFromAccessorToInterceptor) {
1444  v8::HandleScope scope;
1445  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1446  Handle<FunctionTemplate> child = FunctionTemplate::New();
1447  child->Inherit(parent);
1448  AddAccessor(parent, v8_str("age"),
1449              SimpleAccessorGetter, SimpleAccessorSetter);
1450  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1451  LocalContext env;
1452  env->Global()->Set(v8_str("Child"), child->GetFunction());
1453  CompileRun("var child = new Child;"
1454             "function setAge(i){ child.age = i; };"
1455             "for(var i = 20000; i >= 9999; i--) setAge(i);");
1456  // All i >= 10000 go to the accessor.
1457  ExpectInt32("child.accessor_age", 10000);
1458  // The last i goes to the interceptor.
1459  ExpectInt32("child.interceptor_age", 9999);
1460}
1461
1462THREADED_TEST(SwitchFromInterceptorToProperty) {
1463  v8::HandleScope scope;
1464  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1465  Handle<FunctionTemplate> child = FunctionTemplate::New();
1466  child->Inherit(parent);
1467  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1468  LocalContext env;
1469  env->Global()->Set(v8_str("Child"), child->GetFunction());
1470  CompileRun("var child = new Child;"
1471             "function setAge(i){ child.age = i; };"
1472             "for(var i = 0; i <= 10000; i++) setAge(i);");
1473  // All i < 10000 go to the interceptor.
1474  ExpectInt32("child.interceptor_age", 9999);
1475  // The last i goes to child's own property.
1476  ExpectInt32("child.age", 10000);
1477}
1478
1479THREADED_TEST(SwitchFromPropertyToInterceptor) {
1480  v8::HandleScope scope;
1481  Handle<FunctionTemplate> parent = FunctionTemplate::New();
1482  Handle<FunctionTemplate> child = FunctionTemplate::New();
1483  child->Inherit(parent);
1484  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1485  LocalContext env;
1486  env->Global()->Set(v8_str("Child"), child->GetFunction());
1487  CompileRun("var child = new Child;"
1488             "function setAge(i){ child.age = i; };"
1489             "for(var i = 20000; i >= 9999; i--) setAge(i);");
1490  // All i >= 10000 go to child's own property.
1491  ExpectInt32("child.age", 10000);
1492  // The last i goes to the interceptor.
1493  ExpectInt32("child.interceptor_age", 9999);
1494}
1495
1496THREADED_TEST(NamedPropertyHandlerGetter) {
1497  echo_named_call_count = 0;
1498  v8::HandleScope scope;
1499  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1500  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1501                                                     0, 0, 0, 0,
1502                                                     v8_str("data"));
1503  LocalContext env;
1504  env->Global()->Set(v8_str("obj"),
1505                     templ->GetFunction()->NewInstance());
1506  CHECK_EQ(echo_named_call_count, 0);
1507  v8_compile("obj.x")->Run();
1508  CHECK_EQ(echo_named_call_count, 1);
1509  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1510  v8::Handle<Value> str = CompileRun(code);
1511  String::AsciiValue value(str);
1512  CHECK_EQ(*value, "oddlepoddle");
1513  // Check default behavior
1514  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1515  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1516  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1517}
1518
1519
1520int echo_indexed_call_count = 0;
1521
1522
1523static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1524                                             const AccessorInfo& info) {
1525  ApiTestFuzzer::Fuzz();
1526  CHECK_EQ(v8_num(637), info.Data());
1527  echo_indexed_call_count++;
1528  return v8_num(index);
1529}
1530
1531
1532THREADED_TEST(IndexedPropertyHandlerGetter) {
1533  v8::HandleScope scope;
1534  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1535  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1536                                                       0, 0, 0, 0,
1537                                                       v8_num(637));
1538  LocalContext env;
1539  env->Global()->Set(v8_str("obj"),
1540                     templ->GetFunction()->NewInstance());
1541  Local<Script> script = v8_compile("obj[900]");
1542  CHECK_EQ(script->Run()->Int32Value(), 900);
1543}
1544
1545
1546v8::Handle<v8::Object> bottom;
1547
1548static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1549    uint32_t index,
1550    const AccessorInfo& info) {
1551  ApiTestFuzzer::Fuzz();
1552  CHECK(info.This()->Equals(bottom));
1553  return v8::Handle<Value>();
1554}
1555
1556static v8::Handle<Value> CheckThisNamedPropertyHandler(
1557    Local<String> name,
1558    const AccessorInfo& info) {
1559  ApiTestFuzzer::Fuzz();
1560  CHECK(info.This()->Equals(bottom));
1561  return v8::Handle<Value>();
1562}
1563
1564
1565v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1566                                                 Local<Value> value,
1567                                                 const AccessorInfo& info) {
1568  ApiTestFuzzer::Fuzz();
1569  CHECK(info.This()->Equals(bottom));
1570  return v8::Handle<Value>();
1571}
1572
1573
1574v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1575                                               Local<Value> value,
1576                                               const AccessorInfo& info) {
1577  ApiTestFuzzer::Fuzz();
1578  CHECK(info.This()->Equals(bottom));
1579  return v8::Handle<Value>();
1580}
1581
1582v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1583    uint32_t index,
1584    const AccessorInfo& info) {
1585  ApiTestFuzzer::Fuzz();
1586  CHECK(info.This()->Equals(bottom));
1587  return v8::Handle<v8::Integer>();
1588}
1589
1590
1591v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1592                                                    const AccessorInfo& info) {
1593  ApiTestFuzzer::Fuzz();
1594  CHECK(info.This()->Equals(bottom));
1595  return v8::Handle<v8::Integer>();
1596}
1597
1598
1599v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1600    uint32_t index,
1601    const AccessorInfo& info) {
1602  ApiTestFuzzer::Fuzz();
1603  CHECK(info.This()->Equals(bottom));
1604  return v8::Handle<v8::Boolean>();
1605}
1606
1607
1608v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1609    Local<String> property,
1610    const AccessorInfo& info) {
1611  ApiTestFuzzer::Fuzz();
1612  CHECK(info.This()->Equals(bottom));
1613  return v8::Handle<v8::Boolean>();
1614}
1615
1616
1617v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1618    const AccessorInfo& info) {
1619  ApiTestFuzzer::Fuzz();
1620  CHECK(info.This()->Equals(bottom));
1621  return v8::Handle<v8::Array>();
1622}
1623
1624
1625v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1626    const AccessorInfo& info) {
1627  ApiTestFuzzer::Fuzz();
1628  CHECK(info.This()->Equals(bottom));
1629  return v8::Handle<v8::Array>();
1630}
1631
1632
1633THREADED_TEST(PropertyHandlerInPrototype) {
1634  v8::HandleScope scope;
1635  LocalContext env;
1636
1637  // Set up a prototype chain with three interceptors.
1638  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1639  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1640      CheckThisIndexedPropertyHandler,
1641      CheckThisIndexedPropertySetter,
1642      CheckThisIndexedPropertyQuery,
1643      CheckThisIndexedPropertyDeleter,
1644      CheckThisIndexedPropertyEnumerator);
1645
1646  templ->InstanceTemplate()->SetNamedPropertyHandler(
1647      CheckThisNamedPropertyHandler,
1648      CheckThisNamedPropertySetter,
1649      CheckThisNamedPropertyQuery,
1650      CheckThisNamedPropertyDeleter,
1651      CheckThisNamedPropertyEnumerator);
1652
1653  bottom = templ->GetFunction()->NewInstance();
1654  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1655  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1656
1657  bottom->Set(v8_str("__proto__"), middle);
1658  middle->Set(v8_str("__proto__"), top);
1659  env->Global()->Set(v8_str("obj"), bottom);
1660
1661  // Indexed and named get.
1662  Script::Compile(v8_str("obj[0]"))->Run();
1663  Script::Compile(v8_str("obj.x"))->Run();
1664
1665  // Indexed and named set.
1666  Script::Compile(v8_str("obj[1] = 42"))->Run();
1667  Script::Compile(v8_str("obj.y = 42"))->Run();
1668
1669  // Indexed and named query.
1670  Script::Compile(v8_str("0 in obj"))->Run();
1671  Script::Compile(v8_str("'x' in obj"))->Run();
1672
1673  // Indexed and named deleter.
1674  Script::Compile(v8_str("delete obj[0]"))->Run();
1675  Script::Compile(v8_str("delete obj.x"))->Run();
1676
1677  // Enumerators.
1678  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1679}
1680
1681
1682static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1683                                               const AccessorInfo& info) {
1684  ApiTestFuzzer::Fuzz();
1685  if (v8_str("pre")->Equals(key)) {
1686    return v8_str("PrePropertyHandler: pre");
1687  }
1688  return v8::Handle<String>();
1689}
1690
1691
1692static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1693                                                       const AccessorInfo&) {
1694  if (v8_str("pre")->Equals(key)) {
1695    return v8::Integer::New(v8::None);
1696  }
1697
1698  return v8::Handle<v8::Integer>();  // do not intercept the call
1699}
1700
1701
1702THREADED_TEST(PrePropertyHandler) {
1703  v8::HandleScope scope;
1704  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1705  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1706                                                    0,
1707                                                    PrePropertyHandlerQuery);
1708  LocalContext env(NULL, desc->InstanceTemplate());
1709  Script::Compile(v8_str(
1710      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1711  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1712  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1713  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1714  CHECK_EQ(v8_str("Object: on"), result_on);
1715  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1716  CHECK(result_post.IsEmpty());
1717}
1718
1719
1720THREADED_TEST(UndefinedIsNotEnumerable) {
1721  v8::HandleScope scope;
1722  LocalContext env;
1723  v8::Handle<Value> result = Script::Compile(v8_str(
1724      "this.propertyIsEnumerable(undefined)"))->Run();
1725  CHECK(result->IsFalse());
1726}
1727
1728
1729v8::Handle<Script> call_recursively_script;
1730static const int kTargetRecursionDepth = 200;  // near maximum
1731
1732
1733static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1734  ApiTestFuzzer::Fuzz();
1735  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1736  if (depth == kTargetRecursionDepth) return v8::Undefined();
1737  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1738  return call_recursively_script->Run();
1739}
1740
1741
1742static v8::Handle<Value> CallFunctionRecursivelyCall(
1743    const v8::Arguments& args) {
1744  ApiTestFuzzer::Fuzz();
1745  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1746  if (depth == kTargetRecursionDepth) {
1747    printf("[depth = %d]\n", depth);
1748    return v8::Undefined();
1749  }
1750  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1751  v8::Handle<Value> function =
1752      args.This()->Get(v8_str("callFunctionRecursively"));
1753  return function.As<Function>()->Call(args.This(), 0, NULL);
1754}
1755
1756
1757THREADED_TEST(DeepCrossLanguageRecursion) {
1758  v8::HandleScope scope;
1759  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1760  global->Set(v8_str("callScriptRecursively"),
1761              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1762  global->Set(v8_str("callFunctionRecursively"),
1763              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1764  LocalContext env(NULL, global);
1765
1766  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1767  call_recursively_script = v8_compile("callScriptRecursively()");
1768  v8::Handle<Value> result(call_recursively_script->Run());
1769  call_recursively_script = v8::Handle<Script>();
1770
1771  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1772  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1773}
1774
1775
1776static v8::Handle<Value>
1777    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1778  ApiTestFuzzer::Fuzz();
1779  return v8::ThrowException(key);
1780}
1781
1782
1783static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1784                                                    Local<Value>,
1785                                                    const AccessorInfo&) {
1786  v8::ThrowException(key);
1787  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1788}
1789
1790
1791THREADED_TEST(CallbackExceptionRegression) {
1792  v8::HandleScope scope;
1793  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1794  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1795                               ThrowingPropertyHandlerSet);
1796  LocalContext env;
1797  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1798  v8::Handle<Value> otto = Script::Compile(v8_str(
1799      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1800  CHECK_EQ(v8_str("otto"), otto);
1801  v8::Handle<Value> netto = Script::Compile(v8_str(
1802      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1803  CHECK_EQ(v8_str("netto"), netto);
1804}
1805
1806
1807THREADED_TEST(FunctionPrototype) {
1808  v8::HandleScope scope;
1809  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1810  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1811  LocalContext env;
1812  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1813  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1814  CHECK_EQ(script->Run()->Int32Value(), 321);
1815}
1816
1817
1818THREADED_TEST(InternalFields) {
1819  v8::HandleScope scope;
1820  LocalContext env;
1821
1822  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1823  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1824  instance_templ->SetInternalFieldCount(1);
1825  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1826  CHECK_EQ(1, obj->InternalFieldCount());
1827  CHECK(obj->GetInternalField(0)->IsUndefined());
1828  obj->SetInternalField(0, v8_num(17));
1829  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1830}
1831
1832
1833THREADED_TEST(GlobalObjectInternalFields) {
1834  v8::HandleScope scope;
1835  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1836  global_template->SetInternalFieldCount(1);
1837  LocalContext env(NULL, global_template);
1838  v8::Handle<v8::Object> global_proxy = env->Global();
1839  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1840  CHECK_EQ(1, global->InternalFieldCount());
1841  CHECK(global->GetInternalField(0)->IsUndefined());
1842  global->SetInternalField(0, v8_num(17));
1843  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1844}
1845
1846
1847THREADED_TEST(InternalFieldsNativePointers) {
1848  v8::HandleScope scope;
1849  LocalContext env;
1850
1851  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1852  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1853  instance_templ->SetInternalFieldCount(1);
1854  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1855  CHECK_EQ(1, obj->InternalFieldCount());
1856  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1857
1858  char* data = new char[100];
1859
1860  void* aligned = data;
1861  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1862  void* unaligned = data + 1;
1863  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1864
1865  // Check reading and writing aligned pointers.
1866  obj->SetPointerInInternalField(0, aligned);
1867  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1868  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1869
1870  // Check reading and writing unaligned pointers.
1871  obj->SetPointerInInternalField(0, unaligned);
1872  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1873  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1874
1875  delete[] data;
1876}
1877
1878
1879THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1880  v8::HandleScope scope;
1881  LocalContext env;
1882
1883  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1884  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1885  instance_templ->SetInternalFieldCount(1);
1886  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1887  CHECK_EQ(1, obj->InternalFieldCount());
1888  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1889
1890  char* data = new char[100];
1891
1892  void* aligned = data;
1893  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1894  void* unaligned = data + 1;
1895  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1896
1897  obj->SetPointerInInternalField(0, aligned);
1898  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1899  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1900
1901  obj->SetPointerInInternalField(0, unaligned);
1902  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1903  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1904
1905  obj->SetInternalField(0, v8::External::Wrap(aligned));
1906  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1907  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1908
1909  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1910  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1911  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1912
1913  delete[] data;
1914}
1915
1916
1917THREADED_TEST(IdentityHash) {
1918  v8::HandleScope scope;
1919  LocalContext env;
1920
1921  // Ensure that the test starts with an fresh heap to test whether the hash
1922  // code is based on the address.
1923  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1924  Local<v8::Object> obj = v8::Object::New();
1925  int hash = obj->GetIdentityHash();
1926  int hash1 = obj->GetIdentityHash();
1927  CHECK_EQ(hash, hash1);
1928  int hash2 = v8::Object::New()->GetIdentityHash();
1929  // Since the identity hash is essentially a random number two consecutive
1930  // objects should not be assigned the same hash code. If the test below fails
1931  // the random number generator should be evaluated.
1932  CHECK_NE(hash, hash2);
1933  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1934  int hash3 = v8::Object::New()->GetIdentityHash();
1935  // Make sure that the identity hash is not based on the initial address of
1936  // the object alone. If the test below fails the random number generator
1937  // should be evaluated.
1938  CHECK_NE(hash, hash3);
1939  int hash4 = obj->GetIdentityHash();
1940  CHECK_EQ(hash, hash4);
1941
1942  // Check identity hashes behaviour in the presence of JS accessors.
1943  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1944  {
1945    CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1946    Local<v8::Object> o1 = v8::Object::New();
1947    Local<v8::Object> o2 = v8::Object::New();
1948    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1949  }
1950  {
1951    CompileRun(
1952        "function cnst() { return 42; };\n"
1953        "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1954    Local<v8::Object> o1 = v8::Object::New();
1955    Local<v8::Object> o2 = v8::Object::New();
1956    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1957  }
1958}
1959
1960
1961THREADED_TEST(HiddenProperties) {
1962  v8::HandleScope scope;
1963  LocalContext env;
1964
1965  v8::Local<v8::Object> obj = v8::Object::New();
1966  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1967  v8::Local<v8::String> empty = v8_str("");
1968  v8::Local<v8::String> prop_name = v8_str("prop_name");
1969
1970  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1971
1972  // Make sure delete of a non-existent hidden value works
1973  CHECK(obj->DeleteHiddenValue(key));
1974
1975  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1976  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1977  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1978  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1979
1980  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1981
1982  // Make sure we do not find the hidden property.
1983  CHECK(!obj->Has(empty));
1984  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1985  CHECK(obj->Get(empty)->IsUndefined());
1986  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1987  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1988  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1989  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1990
1991  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1992
1993  // Add another property and delete it afterwards to force the object in
1994  // slow case.
1995  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1996  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1997  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1998  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1999  CHECK(obj->Delete(prop_name));
2000  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2001
2002  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2003
2004  CHECK(obj->DeleteHiddenValue(key));
2005  CHECK(obj->GetHiddenValue(key).IsEmpty());
2006}
2007
2008
2009THREADED_TEST(Regress97784) {
2010  // Regression test for crbug.com/97784
2011  // Messing with the Object.prototype should not have effect on
2012  // hidden properties.
2013  v8::HandleScope scope;
2014  LocalContext env;
2015
2016  v8::Local<v8::Object> obj = v8::Object::New();
2017  v8::Local<v8::String> key = v8_str("hidden");
2018
2019  CompileRun(
2020      "set_called = false;"
2021      "Object.defineProperty("
2022      "    Object.prototype,"
2023      "    'hidden',"
2024      "    {get: function() { return 45; },"
2025      "     set: function() { set_called = true; }})");
2026
2027  CHECK(obj->GetHiddenValue(key).IsEmpty());
2028  // Make sure that the getter and setter from Object.prototype is not invoked.
2029  // If it did we would have full access to the hidden properties in
2030  // the accessor.
2031  CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2032  ExpectFalse("set_called");
2033  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2034}
2035
2036
2037static bool interceptor_for_hidden_properties_called;
2038static v8::Handle<Value> InterceptorForHiddenProperties(
2039    Local<String> name, const AccessorInfo& info) {
2040  interceptor_for_hidden_properties_called = true;
2041  return v8::Handle<Value>();
2042}
2043
2044
2045THREADED_TEST(HiddenPropertiesWithInterceptors) {
2046  v8::HandleScope scope;
2047  LocalContext context;
2048
2049  interceptor_for_hidden_properties_called = false;
2050
2051  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2052
2053  // Associate an interceptor with an object and start setting hidden values.
2054  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2055  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2056  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2057  Local<v8::Function> function = fun_templ->GetFunction();
2058  Local<v8::Object> obj = function->NewInstance();
2059  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2060  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2061  CHECK(!interceptor_for_hidden_properties_called);
2062}
2063
2064
2065THREADED_TEST(External) {
2066  v8::HandleScope scope;
2067  int x = 3;
2068  Local<v8::External> ext = v8::External::New(&x);
2069  LocalContext env;
2070  env->Global()->Set(v8_str("ext"), ext);
2071  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2072  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2073  int* ptr = static_cast<int*>(reext->Value());
2074  CHECK_EQ(x, 3);
2075  *ptr = 10;
2076  CHECK_EQ(x, 10);
2077
2078  // Make sure unaligned pointers are wrapped properly.
2079  char* data = i::StrDup("0123456789");
2080  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2081  Local<v8::Value> one = v8::External::Wrap(&data[1]);
2082  Local<v8::Value> two = v8::External::Wrap(&data[2]);
2083  Local<v8::Value> three = v8::External::Wrap(&data[3]);
2084
2085  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2086  CHECK_EQ('0', *char_ptr);
2087  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2088  CHECK_EQ('1', *char_ptr);
2089  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2090  CHECK_EQ('2', *char_ptr);
2091  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2092  CHECK_EQ('3', *char_ptr);
2093  i::DeleteArray(data);
2094}
2095
2096
2097THREADED_TEST(GlobalHandle) {
2098  v8::Persistent<String> global;
2099  {
2100    v8::HandleScope scope;
2101    Local<String> str = v8_str("str");
2102    global = v8::Persistent<String>::New(str);
2103  }
2104  CHECK_EQ(global->Length(), 3);
2105  global.Dispose();
2106}
2107
2108
2109class WeakCallCounter {
2110 public:
2111  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2112  int id() { return id_; }
2113  void increment() { number_of_weak_calls_++; }
2114  int NumberOfWeakCalls() { return number_of_weak_calls_; }
2115 private:
2116  int id_;
2117  int number_of_weak_calls_;
2118};
2119
2120
2121static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2122  WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2123  CHECK_EQ(1234, counter->id());
2124  counter->increment();
2125  handle.Dispose();
2126}
2127
2128
2129THREADED_TEST(ApiObjectGroups) {
2130  HandleScope scope;
2131  LocalContext env;
2132
2133  Persistent<Object> g1s1;
2134  Persistent<Object> g1s2;
2135  Persistent<Object> g1c1;
2136  Persistent<Object> g2s1;
2137  Persistent<Object> g2s2;
2138  Persistent<Object> g2c1;
2139
2140  WeakCallCounter counter(1234);
2141
2142  {
2143    HandleScope scope;
2144    g1s1 = Persistent<Object>::New(Object::New());
2145    g1s2 = Persistent<Object>::New(Object::New());
2146    g1c1 = Persistent<Object>::New(Object::New());
2147    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2148    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2149    g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2150
2151    g2s1 = Persistent<Object>::New(Object::New());
2152    g2s2 = Persistent<Object>::New(Object::New());
2153    g2c1 = Persistent<Object>::New(Object::New());
2154    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2155    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2156    g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2157  }
2158
2159  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
2160
2161  // Connect group 1 and 2, make a cycle.
2162  CHECK(g1s2->Set(0, g2s2));
2163  CHECK(g2s1->Set(0, g1s1));
2164
2165  {
2166    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2167    Persistent<Value> g1_children[] = { g1c1 };
2168    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2169    Persistent<Value> g2_children[] = { g2c1 };
2170    V8::AddObjectGroup(g1_objects, 2);
2171    V8::AddImplicitReferences(g1s1, g1_children, 1);
2172    V8::AddObjectGroup(g2_objects, 2);
2173    V8::AddImplicitReferences(g2s2, g2_children, 1);
2174  }
2175  // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2176  // incremental garbage collection is stopped.
2177  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2178
2179  // All object should be alive.
2180  CHECK_EQ(0, counter.NumberOfWeakCalls());
2181
2182  // Weaken the root.
2183  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2184  // But make children strong roots---all the objects (except for children)
2185  // should be collectable now.
2186  g1c1.ClearWeak();
2187  g2c1.ClearWeak();
2188
2189  // Groups are deleted, rebuild groups.
2190  {
2191    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2192    Persistent<Value> g1_children[] = { g1c1 };
2193    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2194    Persistent<Value> g2_children[] = { g2c1 };
2195    V8::AddObjectGroup(g1_objects, 2);
2196    V8::AddImplicitReferences(g1s1, g1_children, 1);
2197    V8::AddObjectGroup(g2_objects, 2);
2198    V8::AddImplicitReferences(g2s2, g2_children, 1);
2199  }
2200
2201  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2202
2203  // All objects should be gone. 5 global handles in total.
2204  CHECK_EQ(5, counter.NumberOfWeakCalls());
2205
2206  // And now make children weak again and collect them.
2207  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2208  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2209
2210  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2211  CHECK_EQ(7, counter.NumberOfWeakCalls());
2212}
2213
2214
2215THREADED_TEST(ApiObjectGroupsCycle) {
2216  HandleScope scope;
2217  LocalContext env;
2218
2219  WeakCallCounter counter(1234);
2220
2221  Persistent<Object> g1s1;
2222  Persistent<Object> g1s2;
2223  Persistent<Object> g2s1;
2224  Persistent<Object> g2s2;
2225  Persistent<Object> g3s1;
2226  Persistent<Object> g3s2;
2227
2228  {
2229    HandleScope scope;
2230    g1s1 = Persistent<Object>::New(Object::New());
2231    g1s2 = Persistent<Object>::New(Object::New());
2232    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2233    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2234
2235    g2s1 = Persistent<Object>::New(Object::New());
2236    g2s2 = Persistent<Object>::New(Object::New());
2237    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2238    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2239
2240    g3s1 = Persistent<Object>::New(Object::New());
2241    g3s2 = Persistent<Object>::New(Object::New());
2242    g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2243    g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2244  }
2245
2246  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
2247
2248  // Connect groups.  We're building the following cycle:
2249  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2250  // groups.
2251  {
2252    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2253    Persistent<Value> g1_children[] = { g2s1 };
2254    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2255    Persistent<Value> g2_children[] = { g3s1 };
2256    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2257    Persistent<Value> g3_children[] = { g1s1 };
2258    V8::AddObjectGroup(g1_objects, 2);
2259    V8::AddImplicitReferences(g1s1, g1_children, 1);
2260    V8::AddObjectGroup(g2_objects, 2);
2261    V8::AddImplicitReferences(g2s1, g2_children, 1);
2262    V8::AddObjectGroup(g3_objects, 2);
2263    V8::AddImplicitReferences(g3s1, g3_children, 1);
2264  }
2265  // Do a single full GC
2266  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2267
2268  // All object should be alive.
2269  CHECK_EQ(0, counter.NumberOfWeakCalls());
2270
2271  // Weaken the root.
2272  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2273
2274  // Groups are deleted, rebuild groups.
2275  {
2276    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2277    Persistent<Value> g1_children[] = { g2s1 };
2278    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2279    Persistent<Value> g2_children[] = { g3s1 };
2280    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2281    Persistent<Value> g3_children[] = { g1s1 };
2282    V8::AddObjectGroup(g1_objects, 2);
2283    V8::AddImplicitReferences(g1s1, g1_children, 1);
2284    V8::AddObjectGroup(g2_objects, 2);
2285    V8::AddImplicitReferences(g2s1, g2_children, 1);
2286    V8::AddObjectGroup(g3_objects, 2);
2287    V8::AddImplicitReferences(g3s1, g3_children, 1);
2288  }
2289
2290  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2291
2292  // All objects should be gone. 7 global handles in total.
2293  CHECK_EQ(7, counter.NumberOfWeakCalls());
2294}
2295
2296
2297THREADED_TEST(ScriptException) {
2298  v8::HandleScope scope;
2299  LocalContext env;
2300  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2301  v8::TryCatch try_catch;
2302  Local<Value> result = script->Run();
2303  CHECK(result.IsEmpty());
2304  CHECK(try_catch.HasCaught());
2305  String::AsciiValue exception_value(try_catch.Exception());
2306  CHECK_EQ(*exception_value, "panama!");
2307}
2308
2309
2310bool message_received;
2311
2312
2313static void check_message(v8::Handle<v8::Message> message,
2314                          v8::Handle<Value> data) {
2315  CHECK_EQ(5.76, data->NumberValue());
2316  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2317  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2318  message_received = true;
2319}
2320
2321
2322THREADED_TEST(MessageHandlerData) {
2323  message_received = false;
2324  v8::HandleScope scope;
2325  CHECK(!message_received);
2326  v8::V8::AddMessageListener(check_message, v8_num(5.76));
2327  LocalContext context;
2328  v8::ScriptOrigin origin =
2329      v8::ScriptOrigin(v8_str("6.75"));
2330  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2331                                                  &origin);
2332  script->SetData(v8_str("7.56"));
2333  script->Run();
2334  CHECK(message_received);
2335  // clear out the message listener
2336  v8::V8::RemoveMessageListeners(check_message);
2337}
2338
2339
2340THREADED_TEST(GetSetProperty) {
2341  v8::HandleScope scope;
2342  LocalContext context;
2343  context->Global()->Set(v8_str("foo"), v8_num(14));
2344  context->Global()->Set(v8_str("12"), v8_num(92));
2345  context->Global()->Set(v8::Integer::New(16), v8_num(32));
2346  context->Global()->Set(v8_num(13), v8_num(56));
2347  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2348  CHECK_EQ(14, foo->Int32Value());
2349  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2350  CHECK_EQ(92, twelve->Int32Value());
2351  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2352  CHECK_EQ(32, sixteen->Int32Value());
2353  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2354  CHECK_EQ(56, thirteen->Int32Value());
2355  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2356  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2357  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2358  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2359  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2360  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2361  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2362  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2363  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2364}
2365
2366
2367THREADED_TEST(PropertyAttributes) {
2368  v8::HandleScope scope;
2369  LocalContext context;
2370  // none
2371  Local<String> prop = v8_str("none");
2372  context->Global()->Set(prop, v8_num(7));
2373  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2374  // read-only
2375  prop = v8_str("read_only");
2376  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2377  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2378  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2379  Script::Compile(v8_str("read_only = 9"))->Run();
2380  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2381  context->Global()->Set(prop, v8_num(10));
2382  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2383  // dont-delete
2384  prop = v8_str("dont_delete");
2385  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2386  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2387  Script::Compile(v8_str("delete dont_delete"))->Run();
2388  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2389  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2390  // dont-enum
2391  prop = v8_str("dont_enum");
2392  context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2393  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2394  // absent
2395  prop = v8_str("absent");
2396  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2397  Local<Value> fake_prop = v8_num(1);
2398  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2399  // exception
2400  TryCatch try_catch;
2401  Local<Value> exception =
2402      CompileRun("({ toString: function() { throw 'exception';} })");
2403  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2404  CHECK(try_catch.HasCaught());
2405  String::AsciiValue exception_value(try_catch.Exception());
2406  CHECK_EQ("exception", *exception_value);
2407  try_catch.Reset();
2408}
2409
2410
2411THREADED_TEST(Array) {
2412  v8::HandleScope scope;
2413  LocalContext context;
2414  Local<v8::Array> array = v8::Array::New();
2415  CHECK_EQ(0, array->Length());
2416  CHECK(array->Get(0)->IsUndefined());
2417  CHECK(!array->Has(0));
2418  CHECK(array->Get(100)->IsUndefined());
2419  CHECK(!array->Has(100));
2420  array->Set(2, v8_num(7));
2421  CHECK_EQ(3, array->Length());
2422  CHECK(!array->Has(0));
2423  CHECK(!array->Has(1));
2424  CHECK(array->Has(2));
2425  CHECK_EQ(7, array->Get(2)->Int32Value());
2426  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2427  Local<v8::Array> arr = obj.As<v8::Array>();
2428  CHECK_EQ(3, arr->Length());
2429  CHECK_EQ(1, arr->Get(0)->Int32Value());
2430  CHECK_EQ(2, arr->Get(1)->Int32Value());
2431  CHECK_EQ(3, arr->Get(2)->Int32Value());
2432  array = v8::Array::New(27);
2433  CHECK_EQ(27, array->Length());
2434  array = v8::Array::New(-27);
2435  CHECK_EQ(0, array->Length());
2436}
2437
2438
2439v8::Handle<Value> HandleF(const v8::Arguments& args) {
2440  v8::HandleScope scope;
2441  ApiTestFuzzer::Fuzz();
2442  Local<v8::Array> result = v8::Array::New(args.Length());
2443  for (int i = 0; i < args.Length(); i++)
2444    result->Set(i, args[i]);
2445  return scope.Close(result);
2446}
2447
2448
2449THREADED_TEST(Vector) {
2450  v8::HandleScope scope;
2451  Local<ObjectTemplate> global = ObjectTemplate::New();
2452  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2453  LocalContext context(0, global);
2454
2455  const char* fun = "f()";
2456  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2457  CHECK_EQ(0, a0->Length());
2458
2459  const char* fun2 = "f(11)";
2460  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2461  CHECK_EQ(1, a1->Length());
2462  CHECK_EQ(11, a1->Get(0)->Int32Value());
2463
2464  const char* fun3 = "f(12, 13)";
2465  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2466  CHECK_EQ(2, a2->Length());
2467  CHECK_EQ(12, a2->Get(0)->Int32Value());
2468  CHECK_EQ(13, a2->Get(1)->Int32Value());
2469
2470  const char* fun4 = "f(14, 15, 16)";
2471  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2472  CHECK_EQ(3, a3->Length());
2473  CHECK_EQ(14, a3->Get(0)->Int32Value());
2474  CHECK_EQ(15, a3->Get(1)->Int32Value());
2475  CHECK_EQ(16, a3->Get(2)->Int32Value());
2476
2477  const char* fun5 = "f(17, 18, 19, 20)";
2478  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2479  CHECK_EQ(4, a4->Length());
2480  CHECK_EQ(17, a4->Get(0)->Int32Value());
2481  CHECK_EQ(18, a4->Get(1)->Int32Value());
2482  CHECK_EQ(19, a4->Get(2)->Int32Value());
2483  CHECK_EQ(20, a4->Get(3)->Int32Value());
2484}
2485
2486
2487THREADED_TEST(FunctionCall) {
2488  v8::HandleScope scope;
2489  LocalContext context;
2490  CompileRun(
2491    "function Foo() {"
2492    "  var result = [];"
2493    "  for (var i = 0; i < arguments.length; i++) {"
2494    "    result.push(arguments[i]);"
2495    "  }"
2496    "  return result;"
2497    "}");
2498  Local<Function> Foo =
2499      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2500
2501  v8::Handle<Value>* args0 = NULL;
2502  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2503  CHECK_EQ(0, a0->Length());
2504
2505  v8::Handle<Value> args1[] = { v8_num(1.1) };
2506  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2507  CHECK_EQ(1, a1->Length());
2508  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2509
2510  v8::Handle<Value> args2[] = { v8_num(2.2),
2511                                v8_num(3.3) };
2512  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2513  CHECK_EQ(2, a2->Length());
2514  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2515  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2516
2517  v8::Handle<Value> args3[] = { v8_num(4.4),
2518                                v8_num(5.5),
2519                                v8_num(6.6) };
2520  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2521  CHECK_EQ(3, a3->Length());
2522  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2523  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2524  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2525
2526  v8::Handle<Value> args4[] = { v8_num(7.7),
2527                                v8_num(8.8),
2528                                v8_num(9.9),
2529                                v8_num(10.11) };
2530  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2531  CHECK_EQ(4, a4->Length());
2532  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2533  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2534  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2535  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2536}
2537
2538
2539static const char* js_code_causing_out_of_memory =
2540    "var a = new Array(); while(true) a.push(a);";
2541
2542
2543// These tests run for a long time and prevent us from running tests
2544// that come after them so they cannot run in parallel.
2545TEST(OutOfMemory) {
2546  // It's not possible to read a snapshot into a heap with different dimensions.
2547  if (i::Snapshot::IsEnabled()) return;
2548  // Set heap limits.
2549  static const int K = 1024;
2550  v8::ResourceConstraints constraints;
2551  constraints.set_max_young_space_size(256 * K);
2552  constraints.set_max_old_space_size(4 * K * K);
2553  v8::SetResourceConstraints(&constraints);
2554
2555  // Execute a script that causes out of memory.
2556  v8::HandleScope scope;
2557  LocalContext context;
2558  v8::V8::IgnoreOutOfMemoryException();
2559  Local<Script> script =
2560      Script::Compile(String::New(js_code_causing_out_of_memory));
2561  Local<Value> result = script->Run();
2562
2563  // Check for out of memory state.
2564  CHECK(result.IsEmpty());
2565  CHECK(context->HasOutOfMemoryException());
2566}
2567
2568
2569v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2570  ApiTestFuzzer::Fuzz();
2571
2572  v8::HandleScope scope;
2573  LocalContext context;
2574  Local<Script> script =
2575      Script::Compile(String::New(js_code_causing_out_of_memory));
2576  Local<Value> result = script->Run();
2577
2578  // Check for out of memory state.
2579  CHECK(result.IsEmpty());
2580  CHECK(context->HasOutOfMemoryException());
2581
2582  return result;
2583}
2584
2585
2586TEST(OutOfMemoryNested) {
2587  // It's not possible to read a snapshot into a heap with different dimensions.
2588  if (i::Snapshot::IsEnabled()) return;
2589  // Set heap limits.
2590  static const int K = 1024;
2591  v8::ResourceConstraints constraints;
2592  constraints.set_max_young_space_size(256 * K);
2593  constraints.set_max_old_space_size(4 * K * K);
2594  v8::SetResourceConstraints(&constraints);
2595
2596  v8::HandleScope scope;
2597  Local<ObjectTemplate> templ = ObjectTemplate::New();
2598  templ->Set(v8_str("ProvokeOutOfMemory"),
2599             v8::FunctionTemplate::New(ProvokeOutOfMemory));
2600  LocalContext context(0, templ);
2601  v8::V8::IgnoreOutOfMemoryException();
2602  Local<Value> result = CompileRun(
2603    "var thrown = false;"
2604    "try {"
2605    "  ProvokeOutOfMemory();"
2606    "} catch (e) {"
2607    "  thrown = true;"
2608    "}");
2609  // Check for out of memory state.
2610  CHECK(result.IsEmpty());
2611  CHECK(context->HasOutOfMemoryException());
2612}
2613
2614
2615TEST(HugeConsStringOutOfMemory) {
2616  // It's not possible to read a snapshot into a heap with different dimensions.
2617  if (i::Snapshot::IsEnabled()) return;
2618  // Set heap limits.
2619  static const int K = 1024;
2620  v8::ResourceConstraints constraints;
2621  constraints.set_max_young_space_size(256 * K);
2622  constraints.set_max_old_space_size(2 * K * K);
2623  v8::SetResourceConstraints(&constraints);
2624
2625  // Execute a script that causes out of memory.
2626  v8::V8::IgnoreOutOfMemoryException();
2627
2628  v8::HandleScope scope;
2629  LocalContext context;
2630
2631  // Build huge string. This should fail with out of memory exception.
2632  Local<Value> result = CompileRun(
2633    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2634    "for (var i = 0; i < 22; i++) { str = str + str; }");
2635
2636  // Check for out of memory state.
2637  CHECK(result.IsEmpty());
2638  CHECK(context->HasOutOfMemoryException());
2639}
2640
2641
2642THREADED_TEST(ConstructCall) {
2643  v8::HandleScope scope;
2644  LocalContext context;
2645  CompileRun(
2646    "function Foo() {"
2647    "  var result = [];"
2648    "  for (var i = 0; i < arguments.length; i++) {"
2649    "    result.push(arguments[i]);"
2650    "  }"
2651    "  return result;"
2652    "}");
2653  Local<Function> Foo =
2654      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2655
2656  v8::Handle<Value>* args0 = NULL;
2657  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2658  CHECK_EQ(0, a0->Length());
2659
2660  v8::Handle<Value> args1[] = { v8_num(1.1) };
2661  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2662  CHECK_EQ(1, a1->Length());
2663  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2664
2665  v8::Handle<Value> args2[] = { v8_num(2.2),
2666                                v8_num(3.3) };
2667  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2668  CHECK_EQ(2, a2->Length());
2669  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2670  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2671
2672  v8::Handle<Value> args3[] = { v8_num(4.4),
2673                                v8_num(5.5),
2674                                v8_num(6.6) };
2675  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2676  CHECK_EQ(3, a3->Length());
2677  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2678  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2679  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2680
2681  v8::Handle<Value> args4[] = { v8_num(7.7),
2682                                v8_num(8.8),
2683                                v8_num(9.9),
2684                                v8_num(10.11) };
2685  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2686  CHECK_EQ(4, a4->Length());
2687  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2688  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2689  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2690  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2691}
2692
2693
2694static void CheckUncle(v8::TryCatch* try_catch) {
2695  CHECK(try_catch->HasCaught());
2696  String::AsciiValue str_value(try_catch->Exception());
2697  CHECK_EQ(*str_value, "uncle?");
2698  try_catch->Reset();
2699}
2700
2701
2702THREADED_TEST(ConversionNumber) {
2703  v8::HandleScope scope;
2704  LocalContext env;
2705  // Very large number.
2706  CompileRun("var obj = Math.pow(2,32) * 1237;");
2707  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2708  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2709  CHECK_EQ(0, obj->ToInt32()->Value());
2710  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2711  // Large number.
2712  CompileRun("var obj = -1234567890123;");
2713  obj = env->Global()->Get(v8_str("obj"));
2714  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2715  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2716  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2717  // Small positive integer.
2718  CompileRun("var obj = 42;");
2719  obj = env->Global()->Get(v8_str("obj"));
2720  CHECK_EQ(42.0, obj->ToNumber()->Value());
2721  CHECK_EQ(42, obj->ToInt32()->Value());
2722  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2723  // Negative integer.
2724  CompileRun("var obj = -37;");
2725  obj = env->Global()->Get(v8_str("obj"));
2726  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2727  CHECK_EQ(-37, obj->ToInt32()->Value());
2728  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2729  // Positive non-int32 integer.
2730  CompileRun("var obj = 0x81234567;");
2731  obj = env->Global()->Get(v8_str("obj"));
2732  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2733  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2734  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2735  // Fraction.
2736  CompileRun("var obj = 42.3;");
2737  obj = env->Global()->Get(v8_str("obj"));
2738  CHECK_EQ(42.3, obj->ToNumber()->Value());
2739  CHECK_EQ(42, obj->ToInt32()->Value());
2740  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2741  // Large negative fraction.
2742  CompileRun("var obj = -5726623061.75;");
2743  obj = env->Global()->Get(v8_str("obj"));
2744  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2745  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2746  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2747}
2748
2749
2750THREADED_TEST(isNumberType) {
2751  v8::HandleScope scope;
2752  LocalContext env;
2753  // Very large number.
2754  CompileRun("var obj = Math.pow(2,32) * 1237;");
2755  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2756  CHECK(!obj->IsInt32());
2757  CHECK(!obj->IsUint32());
2758  // Large negative number.
2759  CompileRun("var obj = -1234567890123;");
2760  obj = env->Global()->Get(v8_str("obj"));
2761  CHECK(!obj->IsInt32());
2762  CHECK(!obj->IsUint32());
2763  // Small positive integer.
2764  CompileRun("var obj = 42;");
2765  obj = env->Global()->Get(v8_str("obj"));
2766  CHECK(obj->IsInt32());
2767  CHECK(obj->IsUint32());
2768  // Negative integer.
2769  CompileRun("var obj = -37;");
2770  obj = env->Global()->Get(v8_str("obj"));
2771  CHECK(obj->IsInt32());
2772  CHECK(!obj->IsUint32());
2773  // Positive non-int32 integer.
2774  CompileRun("var obj = 0x81234567;");
2775  obj = env->Global()->Get(v8_str("obj"));
2776  CHECK(!obj->IsInt32());
2777  CHECK(obj->IsUint32());
2778  // Fraction.
2779  CompileRun("var obj = 42.3;");
2780  obj = env->Global()->Get(v8_str("obj"));
2781  CHECK(!obj->IsInt32());
2782  CHECK(!obj->IsUint32());
2783  // Large negative fraction.
2784  CompileRun("var obj = -5726623061.75;");
2785  obj = env->Global()->Get(v8_str("obj"));
2786  CHECK(!obj->IsInt32());
2787  CHECK(!obj->IsUint32());
2788}
2789
2790
2791THREADED_TEST(ConversionException) {
2792  v8::HandleScope scope;
2793  LocalContext env;
2794  CompileRun(
2795    "function TestClass() { };"
2796    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2797    "var obj = new TestClass();");
2798  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2799
2800  v8::TryCatch try_catch;
2801
2802  Local<Value> to_string_result = obj->ToString();
2803  CHECK(to_string_result.IsEmpty());
2804  CheckUncle(&try_catch);
2805
2806  Local<Value> to_number_result = obj->ToNumber();
2807  CHECK(to_number_result.IsEmpty());
2808  CheckUncle(&try_catch);
2809
2810  Local<Value> to_integer_result = obj->ToInteger();
2811  CHECK(to_integer_result.IsEmpty());
2812  CheckUncle(&try_catch);
2813
2814  Local<Value> to_uint32_result = obj->ToUint32();
2815  CHECK(to_uint32_result.IsEmpty());
2816  CheckUncle(&try_catch);
2817
2818  Local<Value> to_int32_result = obj->ToInt32();
2819  CHECK(to_int32_result.IsEmpty());
2820  CheckUncle(&try_catch);
2821
2822  Local<Value> to_object_result = v8::Undefined()->ToObject();
2823  CHECK(to_object_result.IsEmpty());
2824  CHECK(try_catch.HasCaught());
2825  try_catch.Reset();
2826
2827  int32_t int32_value = obj->Int32Value();
2828  CHECK_EQ(0, int32_value);
2829  CheckUncle(&try_catch);
2830
2831  uint32_t uint32_value = obj->Uint32Value();
2832  CHECK_EQ(0, uint32_value);
2833  CheckUncle(&try_catch);
2834
2835  double number_value = obj->NumberValue();
2836  CHECK_NE(0, IsNaN(number_value));
2837  CheckUncle(&try_catch);
2838
2839  int64_t integer_value = obj->IntegerValue();
2840  CHECK_EQ(0.0, static_cast<double>(integer_value));
2841  CheckUncle(&try_catch);
2842}
2843
2844
2845v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2846  ApiTestFuzzer::Fuzz();
2847  return v8::ThrowException(v8_str("konto"));
2848}
2849
2850
2851v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2852  if (args.Length() < 1) return v8::False();
2853  v8::HandleScope scope;
2854  v8::TryCatch try_catch;
2855  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2856  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2857  return v8::Boolean::New(try_catch.HasCaught());
2858}
2859
2860
2861THREADED_TEST(APICatch) {
2862  v8::HandleScope scope;
2863  Local<ObjectTemplate> templ = ObjectTemplate::New();
2864  templ->Set(v8_str("ThrowFromC"),
2865             v8::FunctionTemplate::New(ThrowFromC));
2866  LocalContext context(0, templ);
2867  CompileRun(
2868    "var thrown = false;"
2869    "try {"
2870    "  ThrowFromC();"
2871    "} catch (e) {"
2872    "  thrown = true;"
2873    "}");
2874  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2875  CHECK(thrown->BooleanValue());
2876}
2877
2878
2879THREADED_TEST(APIThrowTryCatch) {
2880  v8::HandleScope scope;
2881  Local<ObjectTemplate> templ = ObjectTemplate::New();
2882  templ->Set(v8_str("ThrowFromC"),
2883             v8::FunctionTemplate::New(ThrowFromC));
2884  LocalContext context(0, templ);
2885  v8::TryCatch try_catch;
2886  CompileRun("ThrowFromC();");
2887  CHECK(try_catch.HasCaught());
2888}
2889
2890
2891// Test that a try-finally block doesn't shadow a try-catch block
2892// when setting up an external handler.
2893//
2894// BUG(271): Some of the exception propagation does not work on the
2895// ARM simulator because the simulator separates the C++ stack and the
2896// JS stack.  This test therefore fails on the simulator.  The test is
2897// not threaded to allow the threading tests to run on the simulator.
2898TEST(TryCatchInTryFinally) {
2899  v8::HandleScope scope;
2900  Local<ObjectTemplate> templ = ObjectTemplate::New();
2901  templ->Set(v8_str("CCatcher"),
2902             v8::FunctionTemplate::New(CCatcher));
2903  LocalContext context(0, templ);
2904  Local<Value> result = CompileRun("try {"
2905                                   "  try {"
2906                                   "    CCatcher('throw 7;');"
2907                                   "  } finally {"
2908                                   "  }"
2909                                   "} catch (e) {"
2910                                   "}");
2911  CHECK(result->IsTrue());
2912}
2913
2914
2915static void check_reference_error_message(
2916    v8::Handle<v8::Message> message,
2917    v8::Handle<v8::Value> data) {
2918  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2919  CHECK(message->Get()->Equals(v8_str(reference_error)));
2920}
2921
2922
2923static v8::Handle<Value> Fail(const v8::Arguments& args) {
2924  ApiTestFuzzer::Fuzz();
2925  CHECK(false);
2926  return v8::Undefined();
2927}
2928
2929
2930// Test that overwritten methods are not invoked on uncaught exception
2931// formatting. However, they are invoked when performing normal error
2932// string conversions.
2933TEST(APIThrowMessageOverwrittenToString) {
2934  v8::HandleScope scope;
2935  v8::V8::AddMessageListener(check_reference_error_message);
2936  Local<ObjectTemplate> templ = ObjectTemplate::New();
2937  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2938  LocalContext context(NULL, templ);
2939  CompileRun("asdf;");
2940  CompileRun("var limit = {};"
2941             "limit.valueOf = fail;"
2942             "Error.stackTraceLimit = limit;");
2943  CompileRun("asdf");
2944  CompileRun("Array.prototype.pop = fail;");
2945  CompileRun("Object.prototype.hasOwnProperty = fail;");
2946  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2947  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2948  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2949  CompileRun("ReferenceError.prototype.toString ="
2950             "  function() { return 'Whoops' }");
2951  CompileRun("asdf;");
2952  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2953  CompileRun("asdf;");
2954  CompileRun("ReferenceError.prototype.constructor = void 0;");
2955  CompileRun("asdf;");
2956  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2957  CompileRun("asdf;");
2958  CompileRun("ReferenceError.prototype = new Object();");
2959  CompileRun("asdf;");
2960  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2961  CHECK(string->Equals(v8_str("Whoops")));
2962  CompileRun("ReferenceError.prototype.constructor = new Object();"
2963             "ReferenceError.prototype.constructor.name = 1;"
2964             "Number.prototype.toString = function() { return 'Whoops'; };"
2965             "ReferenceError.prototype.toString = Object.prototype.toString;");
2966  CompileRun("asdf;");
2967  v8::V8::RemoveMessageListeners(check_message);
2968}
2969
2970
2971static void receive_message(v8::Handle<v8::Message> message,
2972                            v8::Handle<v8::Value> data) {
2973  message->Get();
2974  message_received = true;
2975}
2976
2977
2978TEST(APIThrowMessage) {
2979  message_received = false;
2980  v8::HandleScope scope;
2981  v8::V8::AddMessageListener(receive_message);
2982  Local<ObjectTemplate> templ = ObjectTemplate::New();
2983  templ->Set(v8_str("ThrowFromC"),
2984             v8::FunctionTemplate::New(ThrowFromC));
2985  LocalContext context(0, templ);
2986  CompileRun("ThrowFromC();");
2987  CHECK(message_received);
2988  v8::V8::RemoveMessageListeners(check_message);
2989}
2990
2991
2992TEST(APIThrowMessageAndVerboseTryCatch) {
2993  message_received = false;
2994  v8::HandleScope scope;
2995  v8::V8::AddMessageListener(receive_message);
2996  Local<ObjectTemplate> templ = ObjectTemplate::New();
2997  templ->Set(v8_str("ThrowFromC"),
2998             v8::FunctionTemplate::New(ThrowFromC));
2999  LocalContext context(0, templ);
3000  v8::TryCatch try_catch;
3001  try_catch.SetVerbose(true);
3002  Local<Value> result = CompileRun("ThrowFromC();");
3003  CHECK(try_catch.HasCaught());
3004  CHECK(result.IsEmpty());
3005  CHECK(message_received);
3006  v8::V8::RemoveMessageListeners(check_message);
3007}
3008
3009
3010TEST(APIStackOverflowAndVerboseTryCatch) {
3011  message_received = false;
3012  v8::HandleScope scope;
3013  v8::V8::AddMessageListener(receive_message);
3014  LocalContext context;
3015  v8::TryCatch try_catch;
3016  try_catch.SetVerbose(true);
3017  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3018  CHECK(try_catch.HasCaught());
3019  CHECK(result.IsEmpty());
3020  CHECK(message_received);
3021  v8::V8::RemoveMessageListeners(receive_message);
3022}
3023
3024
3025THREADED_TEST(ExternalScriptException) {
3026  v8::HandleScope scope;
3027  Local<ObjectTemplate> templ = ObjectTemplate::New();
3028  templ->Set(v8_str("ThrowFromC"),
3029             v8::FunctionTemplate::New(ThrowFromC));
3030  LocalContext context(0, templ);
3031
3032  v8::TryCatch try_catch;
3033  Local<Script> script
3034      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3035  Local<Value> result = script->Run();
3036  CHECK(result.IsEmpty());
3037  CHECK(try_catch.HasCaught());
3038  String::AsciiValue exception_value(try_catch.Exception());
3039  CHECK_EQ("konto", *exception_value);
3040}
3041
3042
3043
3044v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3045  ApiTestFuzzer::Fuzz();
3046  CHECK_EQ(4, args.Length());
3047  int count = args[0]->Int32Value();
3048  int cInterval = args[2]->Int32Value();
3049  if (count == 0) {
3050    return v8::ThrowException(v8_str("FromC"));
3051  } else {
3052    Local<v8::Object> global = Context::GetCurrent()->Global();
3053    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3054    v8::Handle<Value> argv[] = { v8_num(count - 1),
3055                                 args[1],
3056                                 args[2],
3057                                 args[3] };
3058    if (count % cInterval == 0) {
3059      v8::TryCatch try_catch;
3060      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3061      int expected = args[3]->Int32Value();
3062      if (try_catch.HasCaught()) {
3063        CHECK_EQ(expected, count);
3064        CHECK(result.IsEmpty());
3065        CHECK(!i::Isolate::Current()->has_scheduled_exception());
3066      } else {
3067        CHECK_NE(expected, count);
3068      }
3069      return result;
3070    } else {
3071      return fun.As<Function>()->Call(global, 4, argv);
3072    }
3073  }
3074}
3075
3076
3077v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3078  ApiTestFuzzer::Fuzz();
3079  CHECK_EQ(3, args.Length());
3080  bool equality = args[0]->BooleanValue();
3081  int count = args[1]->Int32Value();
3082  int expected = args[2]->Int32Value();
3083  if (equality) {
3084    CHECK_EQ(count, expected);
3085  } else {
3086    CHECK_NE(count, expected);
3087  }
3088  return v8::Undefined();
3089}
3090
3091
3092THREADED_TEST(EvalInTryFinally) {
3093  v8::HandleScope scope;
3094  LocalContext context;
3095  v8::TryCatch try_catch;
3096  CompileRun("(function() {"
3097             "  try {"
3098             "    eval('asldkf (*&^&*^');"
3099             "  } finally {"
3100             "    return;"
3101             "  }"
3102             "})()");
3103  CHECK(!try_catch.HasCaught());
3104}
3105
3106
3107// This test works by making a stack of alternating JavaScript and C
3108// activations.  These activations set up exception handlers with regular
3109// intervals, one interval for C activations and another for JavaScript
3110// activations.  When enough activations have been created an exception is
3111// thrown and we check that the right activation catches the exception and that
3112// no other activations do.  The right activation is always the topmost one with
3113// a handler, regardless of whether it is in JavaScript or C.
3114//
3115// The notation used to describe a test case looks like this:
3116//
3117//    *JS[4] *C[3] @JS[2] C[1] JS[0]
3118//
3119// Each entry is an activation, either JS or C.  The index is the count at that
3120// level.  Stars identify activations with exception handlers, the @ identifies
3121// the exception handler that should catch the exception.
3122//
3123// BUG(271): Some of the exception propagation does not work on the
3124// ARM simulator because the simulator separates the C++ stack and the
3125// JS stack.  This test therefore fails on the simulator.  The test is
3126// not threaded to allow the threading tests to run on the simulator.
3127TEST(ExceptionOrder) {
3128  v8::HandleScope scope;
3129  Local<ObjectTemplate> templ = ObjectTemplate::New();
3130  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3131  templ->Set(v8_str("CThrowCountDown"),
3132             v8::FunctionTemplate::New(CThrowCountDown));
3133  LocalContext context(0, templ);
3134  CompileRun(
3135    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3136    "  if (count == 0) throw 'FromJS';"
3137    "  if (count % jsInterval == 0) {"
3138    "    try {"
3139    "      var value = CThrowCountDown(count - 1,"
3140    "                                  jsInterval,"
3141    "                                  cInterval,"
3142    "                                  expected);"
3143    "      check(false, count, expected);"
3144    "      return value;"
3145    "    } catch (e) {"
3146    "      check(true, count, expected);"
3147    "    }"
3148    "  } else {"
3149    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3150    "  }"
3151    "}");
3152  Local<Function> fun =
3153      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3154
3155  const int argc = 4;
3156  //                             count      jsInterval cInterval  expected
3157
3158  // *JS[4] *C[3] @JS[2] C[1] JS[0]
3159  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3160  fun->Call(fun, argc, a0);
3161
3162  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3163  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3164  fun->Call(fun, argc, a1);
3165
3166  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3167  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3168  fun->Call(fun, argc, a2);
3169
3170  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3171  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3172  fun->Call(fun, argc, a3);
3173
3174  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3175  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3176  fun->Call(fun, argc, a4);
3177
3178  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3179  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3180  fun->Call(fun, argc, a5);
3181}
3182
3183
3184v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3185  ApiTestFuzzer::Fuzz();
3186  CHECK_EQ(1, args.Length());
3187  return v8::ThrowException(args[0]);
3188}
3189
3190
3191THREADED_TEST(ThrowValues) {
3192  v8::HandleScope scope;
3193  Local<ObjectTemplate> templ = ObjectTemplate::New();
3194  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3195  LocalContext context(0, templ);
3196  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3197    "function Run(obj) {"
3198    "  try {"
3199    "    Throw(obj);"
3200    "  } catch (e) {"
3201    "    return e;"
3202    "  }"
3203    "  return 'no exception';"
3204    "}"
3205    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3206  CHECK_EQ(5, result->Length());
3207  CHECK(result->Get(v8::Integer::New(0))->IsString());
3208  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3209  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3210  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3211  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3212  CHECK(result->Get(v8::Integer::New(3))->IsNull());
3213  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3214}
3215
3216
3217THREADED_TEST(CatchZero) {
3218  v8::HandleScope scope;
3219  LocalContext context;
3220  v8::TryCatch try_catch;
3221  CHECK(!try_catch.HasCaught());
3222  Script::Compile(v8_str("throw 10"))->Run();
3223  CHECK(try_catch.HasCaught());
3224  CHECK_EQ(10, try_catch.Exception()->Int32Value());
3225  try_catch.Reset();
3226  CHECK(!try_catch.HasCaught());
3227  Script::Compile(v8_str("throw 0"))->Run();
3228  CHECK(try_catch.HasCaught());
3229  CHECK_EQ(0, try_catch.Exception()->Int32Value());
3230}
3231
3232
3233THREADED_TEST(CatchExceptionFromWith) {
3234  v8::HandleScope scope;
3235  LocalContext context;
3236  v8::TryCatch try_catch;
3237  CHECK(!try_catch.HasCaught());
3238  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3239  CHECK(try_catch.HasCaught());
3240}
3241
3242
3243THREADED_TEST(TryCatchAndFinallyHidingException) {
3244  v8::HandleScope scope;
3245  LocalContext context;
3246  v8::TryCatch try_catch;
3247  CHECK(!try_catch.HasCaught());
3248  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3249  CompileRun("f({toString: function() { throw 42; }});");
3250  CHECK(!try_catch.HasCaught());
3251}
3252
3253
3254v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3255  v8::TryCatch try_catch;
3256  return v8::Undefined();
3257}
3258
3259
3260THREADED_TEST(TryCatchAndFinally) {
3261  v8::HandleScope scope;
3262  LocalContext context;
3263  context->Global()->Set(
3264      v8_str("native_with_try_catch"),
3265      v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3266  v8::TryCatch try_catch;
3267  CHECK(!try_catch.HasCaught());
3268  CompileRun(
3269      "try {\n"
3270      "  throw new Error('a');\n"
3271      "} finally {\n"
3272      "  native_with_try_catch();\n"
3273      "}\n");
3274  CHECK(try_catch.HasCaught());
3275}
3276
3277
3278THREADED_TEST(Equality) {
3279  v8::HandleScope scope;
3280  LocalContext context;
3281  // Check that equality works at all before relying on CHECK_EQ
3282  CHECK(v8_str("a")->Equals(v8_str("a")));
3283  CHECK(!v8_str("a")->Equals(v8_str("b")));
3284
3285  CHECK_EQ(v8_str("a"), v8_str("a"));
3286  CHECK_NE(v8_str("a"), v8_str("b"));
3287  CHECK_EQ(v8_num(1), v8_num(1));
3288  CHECK_EQ(v8_num(1.00), v8_num(1));
3289  CHECK_NE(v8_num(1), v8_num(2));
3290
3291  // Assume String is not symbol.
3292  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3293  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3294  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3295  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3296  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3297  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3298  Local<Value> not_a_number = v8_num(i::OS::nan_value());
3299  CHECK(!not_a_number->StrictEquals(not_a_number));
3300  CHECK(v8::False()->StrictEquals(v8::False()));
3301  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3302
3303  v8::Handle<v8::Object> obj = v8::Object::New();
3304  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3305  CHECK(alias->StrictEquals(obj));
3306  alias.Dispose();
3307}
3308
3309
3310THREADED_TEST(MultiRun) {
3311  v8::HandleScope scope;
3312  LocalContext context;
3313  Local<Script> script = Script::Compile(v8_str("x"));
3314  for (int i = 0; i < 10; i++)
3315    script->Run();
3316}
3317
3318
3319static v8::Handle<Value> GetXValue(Local<String> name,
3320                                   const AccessorInfo& info) {
3321  ApiTestFuzzer::Fuzz();
3322  CHECK_EQ(info.Data(), v8_str("donut"));
3323  CHECK_EQ(name, v8_str("x"));
3324  return name;
3325}
3326
3327
3328THREADED_TEST(SimplePropertyRead) {
3329  v8::HandleScope scope;
3330  Local<ObjectTemplate> templ = ObjectTemplate::New();
3331  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3332  LocalContext context;
3333  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3334  Local<Script> script = Script::Compile(v8_str("obj.x"));
3335  for (int i = 0; i < 10; i++) {
3336    Local<Value> result = script->Run();
3337    CHECK_EQ(result, v8_str("x"));
3338  }
3339}
3340
3341THREADED_TEST(DefinePropertyOnAPIAccessor) {
3342  v8::HandleScope scope;
3343  Local<ObjectTemplate> templ = ObjectTemplate::New();
3344  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3345  LocalContext context;
3346  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3347
3348  // Uses getOwnPropertyDescriptor to check the configurable status
3349  Local<Script> script_desc
3350    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3351                             "obj, 'x');"
3352                             "prop.configurable;"));
3353  Local<Value> result = script_desc->Run();
3354  CHECK_EQ(result->BooleanValue(), true);
3355
3356  // Redefine get - but still configurable
3357  Local<Script> script_define
3358    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3359                             "            configurable: true };"
3360                             "Object.defineProperty(obj, 'x', desc);"
3361                             "obj.x"));
3362  result = script_define->Run();
3363  CHECK_EQ(result, v8_num(42));
3364
3365  // Check that the accessor is still configurable
3366  result = script_desc->Run();
3367  CHECK_EQ(result->BooleanValue(), true);
3368
3369  // Redefine to a non-configurable
3370  script_define
3371    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3372                             "             configurable: false };"
3373                             "Object.defineProperty(obj, 'x', desc);"
3374                             "obj.x"));
3375  result = script_define->Run();
3376  CHECK_EQ(result, v8_num(43));
3377  result = script_desc->Run();
3378  CHECK_EQ(result->BooleanValue(), false);
3379
3380  // Make sure that it is not possible to redefine again
3381  v8::TryCatch try_catch;
3382  result = script_define->Run();
3383  CHECK(try_catch.HasCaught());
3384  String::AsciiValue exception_value(try_catch.Exception());
3385  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3386}
3387
3388THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3389  v8::HandleScope scope;
3390  Local<ObjectTemplate> templ = ObjectTemplate::New();
3391  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3392  LocalContext context;
3393  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3394
3395  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3396                                    "Object.getOwnPropertyDescriptor( "
3397                                    "obj, 'x');"
3398                                    "prop.configurable;"));
3399  Local<Value> result = script_desc->Run();
3400  CHECK_EQ(result->BooleanValue(), true);
3401
3402  Local<Script> script_define =
3403    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3404                           "            configurable: true };"
3405                           "Object.defineProperty(obj, 'x', desc);"
3406                           "obj.x"));
3407  result = script_define->Run();
3408  CHECK_EQ(result, v8_num(42));
3409
3410
3411  result = script_desc->Run();
3412  CHECK_EQ(result->BooleanValue(), true);
3413
3414
3415  script_define =
3416    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3417                           "            configurable: false };"
3418                           "Object.defineProperty(obj, 'x', desc);"
3419                           "obj.x"));
3420  result = script_define->Run();
3421  CHECK_EQ(result, v8_num(43));
3422  result = script_desc->Run();
3423
3424  CHECK_EQ(result->BooleanValue(), false);
3425
3426  v8::TryCatch try_catch;
3427  result = script_define->Run();
3428  CHECK(try_catch.HasCaught());
3429  String::AsciiValue exception_value(try_catch.Exception());
3430  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3431}
3432
3433
3434static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3435                                                char const* name) {
3436  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3437}
3438
3439
3440THREADED_TEST(DefineAPIAccessorOnObject) {
3441  v8::HandleScope scope;
3442  Local<ObjectTemplate> templ = ObjectTemplate::New();
3443  LocalContext context;
3444
3445  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3446  CompileRun("var obj2 = {};");
3447
3448  CHECK(CompileRun("obj1.x")->IsUndefined());
3449  CHECK(CompileRun("obj2.x")->IsUndefined());
3450
3451  CHECK(GetGlobalProperty(&context, "obj1")->
3452      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3453
3454  ExpectString("obj1.x", "x");
3455  CHECK(CompileRun("obj2.x")->IsUndefined());
3456
3457  CHECK(GetGlobalProperty(&context, "obj2")->
3458      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3459
3460  ExpectString("obj1.x", "x");
3461  ExpectString("obj2.x", "x");
3462
3463  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3464  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3465
3466  CompileRun("Object.defineProperty(obj1, 'x',"
3467             "{ get: function() { return 'y'; }, configurable: true })");
3468
3469  ExpectString("obj1.x", "y");
3470  ExpectString("obj2.x", "x");
3471
3472  CompileRun("Object.defineProperty(obj2, 'x',"
3473             "{ get: function() { return 'y'; }, configurable: true })");
3474
3475  ExpectString("obj1.x", "y");
3476  ExpectString("obj2.x", "y");
3477
3478  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3479  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3480
3481  CHECK(GetGlobalProperty(&context, "obj1")->
3482      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3483  CHECK(GetGlobalProperty(&context, "obj2")->
3484      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3485
3486  ExpectString("obj1.x", "x");
3487  ExpectString("obj2.x", "x");
3488
3489  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3490  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3491
3492  // Define getters/setters, but now make them not configurable.
3493  CompileRun("Object.defineProperty(obj1, 'x',"
3494             "{ get: function() { return 'z'; }, configurable: false })");
3495  CompileRun("Object.defineProperty(obj2, 'x',"
3496             "{ get: function() { return 'z'; }, configurable: false })");
3497
3498  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3499  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3500
3501  ExpectString("obj1.x", "z");
3502  ExpectString("obj2.x", "z");
3503
3504  CHECK(!GetGlobalProperty(&context, "obj1")->
3505      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3506  CHECK(!GetGlobalProperty(&context, "obj2")->
3507      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3508
3509  ExpectString("obj1.x", "z");
3510  ExpectString("obj2.x", "z");
3511}
3512
3513
3514THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3515  v8::HandleScope scope;
3516  Local<ObjectTemplate> templ = ObjectTemplate::New();
3517  LocalContext context;
3518
3519  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3520  CompileRun("var obj2 = {};");
3521
3522  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3523        v8_str("x"),
3524        GetXValue, NULL,
3525        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3526  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3527        v8_str("x"),
3528        GetXValue, NULL,
3529        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3530
3531  ExpectString("obj1.x", "x");
3532  ExpectString("obj2.x", "x");
3533
3534  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3535  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3536
3537  CHECK(!GetGlobalProperty(&context, "obj1")->
3538      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3539  CHECK(!GetGlobalProperty(&context, "obj2")->
3540      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541
3542  {
3543    v8::TryCatch try_catch;
3544    CompileRun("Object.defineProperty(obj1, 'x',"
3545        "{get: function() { return 'func'; }})");
3546    CHECK(try_catch.HasCaught());
3547    String::AsciiValue exception_value(try_catch.Exception());
3548    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3549  }
3550  {
3551    v8::TryCatch try_catch;
3552    CompileRun("Object.defineProperty(obj2, 'x',"
3553        "{get: function() { return 'func'; }})");
3554    CHECK(try_catch.HasCaught());
3555    String::AsciiValue exception_value(try_catch.Exception());
3556    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3557  }
3558}
3559
3560
3561static v8::Handle<Value> Get239Value(Local<String> name,
3562                                     const AccessorInfo& info) {
3563  ApiTestFuzzer::Fuzz();
3564  CHECK_EQ(info.Data(), v8_str("donut"));
3565  CHECK_EQ(name, v8_str("239"));
3566  return name;
3567}
3568
3569
3570THREADED_TEST(ElementAPIAccessor) {
3571  v8::HandleScope scope;
3572  Local<ObjectTemplate> templ = ObjectTemplate::New();
3573  LocalContext context;
3574
3575  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3576  CompileRun("var obj2 = {};");
3577
3578  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3579        v8_str("239"),
3580        Get239Value, NULL,
3581        v8_str("donut")));
3582  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3583        v8_str("239"),
3584        Get239Value, NULL,
3585        v8_str("donut")));
3586
3587  ExpectString("obj1[239]", "239");
3588  ExpectString("obj2[239]", "239");
3589  ExpectString("obj1['239']", "239");
3590  ExpectString("obj2['239']", "239");
3591}
3592
3593
3594v8::Persistent<Value> xValue;
3595
3596
3597static void SetXValue(Local<String> name,
3598                      Local<Value> value,
3599                      const AccessorInfo& info) {
3600  CHECK_EQ(value, v8_num(4));
3601  CHECK_EQ(info.Data(), v8_str("donut"));
3602  CHECK_EQ(name, v8_str("x"));
3603  CHECK(xValue.IsEmpty());
3604  xValue = v8::Persistent<Value>::New(value);
3605}
3606
3607
3608THREADED_TEST(SimplePropertyWrite) {
3609  v8::HandleScope scope;
3610  Local<ObjectTemplate> templ = ObjectTemplate::New();
3611  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3612  LocalContext context;
3613  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3614  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3615  for (int i = 0; i < 10; i++) {
3616    CHECK(xValue.IsEmpty());
3617    script->Run();
3618    CHECK_EQ(v8_num(4), xValue);
3619    xValue.Dispose();
3620    xValue = v8::Persistent<Value>();
3621  }
3622}
3623
3624
3625static v8::Handle<Value> XPropertyGetter(Local<String> property,
3626                                         const AccessorInfo& info) {
3627  ApiTestFuzzer::Fuzz();
3628  CHECK(info.Data()->IsUndefined());
3629  return property;
3630}
3631
3632
3633THREADED_TEST(NamedInterceptorPropertyRead) {
3634  v8::HandleScope scope;
3635  Local<ObjectTemplate> templ = ObjectTemplate::New();
3636  templ->SetNamedPropertyHandler(XPropertyGetter);
3637  LocalContext context;
3638  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639  Local<Script> script = Script::Compile(v8_str("obj.x"));
3640  for (int i = 0; i < 10; i++) {
3641    Local<Value> result = script->Run();
3642    CHECK_EQ(result, v8_str("x"));
3643  }
3644}
3645
3646
3647THREADED_TEST(NamedInterceptorDictionaryIC) {
3648  v8::HandleScope scope;
3649  Local<ObjectTemplate> templ = ObjectTemplate::New();
3650  templ->SetNamedPropertyHandler(XPropertyGetter);
3651  LocalContext context;
3652  // Create an object with a named interceptor.
3653  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3654  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3655  for (int i = 0; i < 10; i++) {
3656    Local<Value> result = script->Run();
3657    CHECK_EQ(result, v8_str("x"));
3658  }
3659  // Create a slow case object and a function accessing a property in
3660  // that slow case object (with dictionary probing in generated
3661  // code). Then force object with a named interceptor into slow-case,
3662  // pass it to the function, and check that the interceptor is called
3663  // instead of accessing the local property.
3664  Local<Value> result =
3665      CompileRun("function get_x(o) { return o.x; };"
3666                 "var obj = { x : 42, y : 0 };"
3667                 "delete obj.y;"
3668                 "for (var i = 0; i < 10; i++) get_x(obj);"
3669                 "interceptor_obj.x = 42;"
3670                 "interceptor_obj.y = 10;"
3671                 "delete interceptor_obj.y;"
3672                 "get_x(interceptor_obj)");
3673  CHECK_EQ(result, v8_str("x"));
3674}
3675
3676
3677THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3678  v8::HandleScope scope;
3679
3680  v8::Persistent<Context> context1 = Context::New();
3681
3682  context1->Enter();
3683  Local<ObjectTemplate> templ = ObjectTemplate::New();
3684  templ->SetNamedPropertyHandler(XPropertyGetter);
3685  // Create an object with a named interceptor.
3686  v8::Local<v8::Object> object = templ->NewInstance();
3687  context1->Global()->Set(v8_str("interceptor_obj"), object);
3688
3689  // Force the object into the slow case.
3690  CompileRun("interceptor_obj.y = 0;"
3691             "delete interceptor_obj.y;");
3692  context1->Exit();
3693
3694  {
3695    // Introduce the object into a different context.
3696    // Repeat named loads to exercise ICs.
3697    LocalContext context2;
3698    context2->Global()->Set(v8_str("interceptor_obj"), object);
3699    Local<Value> result =
3700      CompileRun("function get_x(o) { return o.x; }"
3701                 "interceptor_obj.x = 42;"
3702                 "for (var i=0; i != 10; i++) {"
3703                 "  get_x(interceptor_obj);"
3704                 "}"
3705                 "get_x(interceptor_obj)");
3706    // Check that the interceptor was actually invoked.
3707    CHECK_EQ(result, v8_str("x"));
3708  }
3709
3710  // Return to the original context and force some object to the slow case
3711  // to cause the NormalizedMapCache to verify.
3712  context1->Enter();
3713  CompileRun("var obj = { x : 0 }; delete obj.x;");
3714  context1->Exit();
3715
3716  context1.Dispose();
3717}
3718
3719
3720static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3721                                               const AccessorInfo& info) {
3722  // Set x on the prototype object and do not handle the get request.
3723  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3724  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3725  return v8::Handle<Value>();
3726}
3727
3728
3729// This is a regression test for http://crbug.com/20104. Map
3730// transitions should not interfere with post interceptor lookup.
3731THREADED_TEST(NamedInterceptorMapTransitionRead) {
3732  v8::HandleScope scope;
3733  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3734  Local<v8::ObjectTemplate> instance_template
3735      = function_template->InstanceTemplate();
3736  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3737  LocalContext context;
3738  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3739  // Create an instance of F and introduce a map transition for x.
3740  CompileRun("var o = new F(); o.x = 23;");
3741  // Create an instance of F and invoke the getter. The result should be 23.
3742  Local<Value> result = CompileRun("o = new F(); o.x");
3743  CHECK_EQ(result->Int32Value(), 23);
3744}
3745
3746
3747static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3748                                               const AccessorInfo& info) {
3749  ApiTestFuzzer::Fuzz();
3750  if (index == 37) {
3751    return v8::Handle<Value>(v8_num(625));
3752  }
3753  return v8::Handle<Value>();
3754}
3755
3756
3757static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3758                                               Local<Value> value,
3759                                               const AccessorInfo& info) {
3760  ApiTestFuzzer::Fuzz();
3761  if (index == 39) {
3762    return value;
3763  }
3764  return v8::Handle<Value>();
3765}
3766
3767
3768THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3769  v8::HandleScope scope;
3770  Local<ObjectTemplate> templ = ObjectTemplate::New();
3771  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3772                                   IndexedPropertySetter);
3773  LocalContext context;
3774  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3775  Local<Script> getter_script = Script::Compile(v8_str(
3776      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3777  Local<Script> setter_script = Script::Compile(v8_str(
3778      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3779      "obj[17] = 23;"
3780      "obj.foo;"));
3781  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3782      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3783      "obj[39] = 47;"
3784      "obj.foo;"));  // This setter should not run, due to the interceptor.
3785  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3786      "obj[37];"));
3787  Local<Value> result = getter_script->Run();
3788  CHECK_EQ(v8_num(5), result);
3789  result = setter_script->Run();
3790  CHECK_EQ(v8_num(23), result);
3791  result = interceptor_setter_script->Run();
3792  CHECK_EQ(v8_num(23), result);
3793  result = interceptor_getter_script->Run();
3794  CHECK_EQ(v8_num(625), result);
3795}
3796
3797
3798static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3799    uint32_t index,
3800    const AccessorInfo& info) {
3801  ApiTestFuzzer::Fuzz();
3802  if (index < 25) {
3803    return v8::Handle<Value>(v8_num(index));
3804  }
3805  return v8::Handle<Value>();
3806}
3807
3808
3809static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3810    uint32_t index,
3811    Local<Value> value,
3812    const AccessorInfo& info) {
3813  ApiTestFuzzer::Fuzz();
3814  if (index < 25) {
3815    return v8::Handle<Value>(v8_num(index));
3816  }
3817  return v8::Handle<Value>();
3818}
3819
3820
3821Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3822    const AccessorInfo& info) {
3823  // Force the list of returned keys to be stored in a FastDoubleArray.
3824  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3825      "keys = new Array(); keys[125000] = 1;"
3826      "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3827      "keys.length = 25; keys;"));
3828  Local<Value> result = indexed_property_names_script->Run();
3829  return Local<v8::Array>(::v8::Array::Cast(*result));
3830}
3831
3832
3833// Make sure that the the interceptor code in the runtime properly handles
3834// merging property name lists for double-array-backed arrays.
3835THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3836  v8::HandleScope scope;
3837  Local<ObjectTemplate> templ = ObjectTemplate::New();
3838  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3839                                   UnboxedDoubleIndexedPropertySetter,
3840                                   0,
3841                                   0,
3842                                   UnboxedDoubleIndexedPropertyEnumerator);
3843  LocalContext context;
3844  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3845  // When obj is created, force it to be Stored in a FastDoubleArray.
3846  Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3847      "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3848      "key_count = 0; "
3849      "for (x in obj) {key_count++;};"
3850      "obj;"));
3851  Local<Value> result = create_unboxed_double_script->Run();
3852  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3853  Local<Script> key_count_check = Script::Compile(v8_str(
3854      "key_count;"));
3855  result = key_count_check->Run();
3856  CHECK_EQ(v8_num(40013), result);
3857}
3858
3859
3860Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3861    const AccessorInfo& info) {
3862  // Force the list of returned keys to be stored in a Arguments object.
3863  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3864      "function f(w,x) {"
3865      " return arguments;"
3866      "}"
3867      "keys = f(0, 1, 2, 3);"
3868      "keys;"));
3869  Local<Value> result = indexed_property_names_script->Run();
3870  return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3871}
3872
3873
3874static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3875    uint32_t index,
3876    const AccessorInfo& info) {
3877  ApiTestFuzzer::Fuzz();
3878  if (index < 4) {
3879    return v8::Handle<Value>(v8_num(index));
3880  }
3881  return v8::Handle<Value>();
3882}
3883
3884
3885// Make sure that the the interceptor code in the runtime properly handles
3886// merging property name lists for non-string arguments arrays.
3887THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3888  v8::HandleScope scope;
3889  Local<ObjectTemplate> templ = ObjectTemplate::New();
3890  templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3891                                   0,
3892                                   0,
3893                                   0,
3894                                   NonStrictArgsIndexedPropertyEnumerator);
3895  LocalContext context;
3896  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3897  Local<Script> create_args_script =
3898      Script::Compile(v8_str(
3899          "var key_count = 0;"
3900          "for (x in obj) {key_count++;} key_count;"));
3901  Local<Value> result = create_args_script->Run();
3902  CHECK_EQ(v8_num(4), result);
3903}
3904
3905
3906static v8::Handle<Value> IdentityIndexedPropertyGetter(
3907    uint32_t index,
3908    const AccessorInfo& info) {
3909  return v8::Integer::NewFromUnsigned(index);
3910}
3911
3912
3913THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3914  v8::HandleScope scope;
3915  Local<ObjectTemplate> templ = ObjectTemplate::New();
3916  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3917
3918  LocalContext context;
3919  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3920
3921  // Check fast object case.
3922  const char* fast_case_code =
3923      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3924  ExpectString(fast_case_code, "0");
3925
3926  // Check slow case.
3927  const char* slow_case_code =
3928      "obj.x = 1; delete obj.x;"
3929      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3930  ExpectString(slow_case_code, "1");
3931}
3932
3933
3934THREADED_TEST(IndexedInterceptorWithNoSetter) {
3935  v8::HandleScope scope;
3936  Local<ObjectTemplate> templ = ObjectTemplate::New();
3937  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3938
3939  LocalContext context;
3940  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3941
3942  const char* code =
3943      "try {"
3944      "  obj[0] = 239;"
3945      "  for (var i = 0; i < 100; i++) {"
3946      "    var v = obj[0];"
3947      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3948      "  }"
3949      "  'PASSED'"
3950      "} catch(e) {"
3951      "  e"
3952      "}";
3953  ExpectString(code, "PASSED");
3954}
3955
3956
3957THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3958  v8::HandleScope scope;
3959  Local<ObjectTemplate> templ = ObjectTemplate::New();
3960  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3961
3962  LocalContext context;
3963  Local<v8::Object> obj = templ->NewInstance();
3964  obj->TurnOnAccessCheck();
3965  context->Global()->Set(v8_str("obj"), obj);
3966
3967  const char* code =
3968      "try {"
3969      "  for (var i = 0; i < 100; i++) {"
3970      "    var v = obj[0];"
3971      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3972      "  }"
3973      "  'PASSED'"
3974      "} catch(e) {"
3975      "  e"
3976      "}";
3977  ExpectString(code, "PASSED");
3978}
3979
3980
3981THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3982  i::FLAG_allow_natives_syntax = true;
3983  v8::HandleScope scope;
3984  Local<ObjectTemplate> templ = ObjectTemplate::New();
3985  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3986
3987  LocalContext context;
3988  Local<v8::Object> obj = templ->NewInstance();
3989  context->Global()->Set(v8_str("obj"), obj);
3990
3991  const char* code =
3992      "try {"
3993      "  for (var i = 0; i < 100; i++) {"
3994      "    var expected = i;"
3995      "    if (i == 5) {"
3996      "      %EnableAccessChecks(obj);"
3997      "      expected = undefined;"
3998      "    }"
3999      "    var v = obj[i];"
4000      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4001      "    if (i == 5) %DisableAccessChecks(obj);"
4002      "  }"
4003      "  'PASSED'"
4004      "} catch(e) {"
4005      "  e"
4006      "}";
4007  ExpectString(code, "PASSED");
4008}
4009
4010
4011THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4012  v8::HandleScope scope;
4013  Local<ObjectTemplate> templ = ObjectTemplate::New();
4014  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4015
4016  LocalContext context;
4017  Local<v8::Object> obj = templ->NewInstance();
4018  context->Global()->Set(v8_str("obj"), obj);
4019
4020  const char* code =
4021      "try {"
4022      "  for (var i = 0; i < 100; i++) {"
4023      "    var v = obj[i];"
4024      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4025      "  }"
4026      "  'PASSED'"
4027      "} catch(e) {"
4028      "  e"
4029      "}";
4030  ExpectString(code, "PASSED");
4031}
4032
4033
4034THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4035  v8::HandleScope scope;
4036  Local<ObjectTemplate> templ = ObjectTemplate::New();
4037  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4038
4039  LocalContext context;
4040  Local<v8::Object> obj = templ->NewInstance();
4041  context->Global()->Set(v8_str("obj"), obj);
4042
4043  const char* code =
4044      "try {"
4045      "  for (var i = 0; i < 100; i++) {"
4046      "    var expected = i;"
4047      "    var key = i;"
4048      "    if (i == 25) {"
4049      "       key = -1;"
4050      "       expected = undefined;"
4051      "    }"
4052      "    if (i == 50) {"
4053      "       /* probe minimal Smi number on 32-bit platforms */"
4054      "       key = -(1 << 30);"
4055      "       expected = undefined;"
4056      "    }"
4057      "    if (i == 75) {"
4058      "       /* probe minimal Smi number on 64-bit platforms */"
4059      "       key = 1 << 31;"
4060      "       expected = undefined;"
4061      "    }"
4062      "    var v = obj[key];"
4063      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4064      "  }"
4065      "  'PASSED'"
4066      "} catch(e) {"
4067      "  e"
4068      "}";
4069  ExpectString(code, "PASSED");
4070}
4071
4072
4073THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4074  v8::HandleScope scope;
4075  Local<ObjectTemplate> templ = ObjectTemplate::New();
4076  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4077
4078  LocalContext context;
4079  Local<v8::Object> obj = templ->NewInstance();
4080  context->Global()->Set(v8_str("obj"), obj);
4081
4082  const char* code =
4083      "try {"
4084      "  for (var i = 0; i < 100; i++) {"
4085      "    var expected = i;"
4086      "    var key = i;"
4087      "    if (i == 50) {"
4088      "       key = 'foobar';"
4089      "       expected = undefined;"
4090      "    }"
4091      "    var v = obj[key];"
4092      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4093      "  }"
4094      "  'PASSED'"
4095      "} catch(e) {"
4096      "  e"
4097      "}";
4098  ExpectString(code, "PASSED");
4099}
4100
4101
4102THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4103  v8::HandleScope scope;
4104  Local<ObjectTemplate> templ = ObjectTemplate::New();
4105  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4106
4107  LocalContext context;
4108  Local<v8::Object> obj = templ->NewInstance();
4109  context->Global()->Set(v8_str("obj"), obj);
4110
4111  const char* code =
4112      "var original = obj;"
4113      "try {"
4114      "  for (var i = 0; i < 100; i++) {"
4115      "    var expected = i;"
4116      "    if (i == 50) {"
4117      "       obj = {50: 'foobar'};"
4118      "       expected = 'foobar';"
4119      "    }"
4120      "    var v = obj[i];"
4121      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4122      "    if (i == 50) obj = original;"
4123      "  }"
4124      "  'PASSED'"
4125      "} catch(e) {"
4126      "  e"
4127      "}";
4128  ExpectString(code, "PASSED");
4129}
4130
4131
4132THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4133  v8::HandleScope scope;
4134  Local<ObjectTemplate> templ = ObjectTemplate::New();
4135  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4136
4137  LocalContext context;
4138  Local<v8::Object> obj = templ->NewInstance();
4139  context->Global()->Set(v8_str("obj"), obj);
4140
4141  const char* code =
4142      "var original = obj;"
4143      "try {"
4144      "  for (var i = 0; i < 100; i++) {"
4145      "    var expected = i;"
4146      "    if (i == 5) {"
4147      "       obj = 239;"
4148      "       expected = undefined;"
4149      "    }"
4150      "    var v = obj[i];"
4151      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152      "    if (i == 5) obj = original;"
4153      "  }"
4154      "  'PASSED'"
4155      "} catch(e) {"
4156      "  e"
4157      "}";
4158  ExpectString(code, "PASSED");
4159}
4160
4161
4162THREADED_TEST(IndexedInterceptorOnProto) {
4163  v8::HandleScope scope;
4164  Local<ObjectTemplate> templ = ObjectTemplate::New();
4165  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4166
4167  LocalContext context;
4168  Local<v8::Object> obj = templ->NewInstance();
4169  context->Global()->Set(v8_str("obj"), obj);
4170
4171  const char* code =
4172      "var o = {__proto__: obj};"
4173      "try {"
4174      "  for (var i = 0; i < 100; i++) {"
4175      "    var v = o[i];"
4176      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4177      "  }"
4178      "  'PASSED'"
4179      "} catch(e) {"
4180      "  e"
4181      "}";
4182  ExpectString(code, "PASSED");
4183}
4184
4185
4186THREADED_TEST(MultiContexts) {
4187  v8::HandleScope scope;
4188  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4189  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4190
4191  Local<String> password = v8_str("Password");
4192
4193  // Create an environment
4194  LocalContext context0(0, templ);
4195  context0->SetSecurityToken(password);
4196  v8::Handle<v8::Object> global0 = context0->Global();
4197  global0->Set(v8_str("custom"), v8_num(1234));
4198  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4199
4200  // Create an independent environment
4201  LocalContext context1(0, templ);
4202  context1->SetSecurityToken(password);
4203  v8::Handle<v8::Object> global1 = context1->Global();
4204  global1->Set(v8_str("custom"), v8_num(1234));
4205  CHECK_NE(global0, global1);
4206  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4207  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4208
4209  // Now create a new context with the old global
4210  LocalContext context2(0, templ, global1);
4211  context2->SetSecurityToken(password);
4212  v8::Handle<v8::Object> global2 = context2->Global();
4213  CHECK_EQ(global1, global2);
4214  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4215  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4216}
4217
4218
4219THREADED_TEST(FunctionPrototypeAcrossContexts) {
4220  // Make sure that functions created by cloning boilerplates cannot
4221  // communicate through their __proto__ field.
4222
4223  v8::HandleScope scope;
4224
4225  LocalContext env0;
4226  v8::Handle<v8::Object> global0 =
4227      env0->Global();
4228  v8::Handle<v8::Object> object0 =
4229      global0->Get(v8_str("Object")).As<v8::Object>();
4230  v8::Handle<v8::Object> tostring0 =
4231      object0->Get(v8_str("toString")).As<v8::Object>();
4232  v8::Handle<v8::Object> proto0 =
4233      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4234  proto0->Set(v8_str("custom"), v8_num(1234));
4235
4236  LocalContext env1;
4237  v8::Handle<v8::Object> global1 =
4238      env1->Global();
4239  v8::Handle<v8::Object> object1 =
4240      global1->Get(v8_str("Object")).As<v8::Object>();
4241  v8::Handle<v8::Object> tostring1 =
4242      object1->Get(v8_str("toString")).As<v8::Object>();
4243  v8::Handle<v8::Object> proto1 =
4244      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4245  CHECK(!proto1->Has(v8_str("custom")));
4246}
4247
4248
4249THREADED_TEST(Regress892105) {
4250  // Make sure that object and array literals created by cloning
4251  // boilerplates cannot communicate through their __proto__
4252  // field. This is rather difficult to check, but we try to add stuff
4253  // to Object.prototype and Array.prototype and create a new
4254  // environment. This should succeed.
4255
4256  v8::HandleScope scope;
4257
4258  Local<String> source = v8_str("Object.prototype.obj = 1234;"
4259                                "Array.prototype.arr = 4567;"
4260                                "8901");
4261
4262  LocalContext env0;
4263  Local<Script> script0 = Script::Compile(source);
4264  CHECK_EQ(8901.0, script0->Run()->NumberValue());
4265
4266  LocalContext env1;
4267  Local<Script> script1 = Script::Compile(source);
4268  CHECK_EQ(8901.0, script1->Run()->NumberValue());
4269}
4270
4271
4272THREADED_TEST(UndetectableObject) {
4273  v8::HandleScope scope;
4274  LocalContext env;
4275
4276  Local<v8::FunctionTemplate> desc =
4277      v8::FunctionTemplate::New(0, v8::Handle<Value>());
4278  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4279
4280  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4281  env->Global()->Set(v8_str("undetectable"), obj);
4282
4283  ExpectString("undetectable.toString()", "[object Object]");
4284  ExpectString("typeof undetectable", "undefined");
4285  ExpectString("typeof(undetectable)", "undefined");
4286  ExpectBoolean("typeof undetectable == 'undefined'", true);
4287  ExpectBoolean("typeof undetectable == 'object'", false);
4288  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4289  ExpectBoolean("!undetectable", true);
4290
4291  ExpectObject("true&&undetectable", obj);
4292  ExpectBoolean("false&&undetectable", false);
4293  ExpectBoolean("true||undetectable", true);
4294  ExpectObject("false||undetectable", obj);
4295
4296  ExpectObject("undetectable&&true", obj);
4297  ExpectObject("undetectable&&false", obj);
4298  ExpectBoolean("undetectable||true", true);
4299  ExpectBoolean("undetectable||false", false);
4300
4301  ExpectBoolean("undetectable==null", true);
4302  ExpectBoolean("null==undetectable", true);
4303  ExpectBoolean("undetectable==undefined", true);
4304  ExpectBoolean("undefined==undetectable", true);
4305  ExpectBoolean("undetectable==undetectable", true);
4306
4307
4308  ExpectBoolean("undetectable===null", false);
4309  ExpectBoolean("null===undetectable", false);
4310  ExpectBoolean("undetectable===undefined", false);
4311  ExpectBoolean("undefined===undetectable", false);
4312  ExpectBoolean("undetectable===undetectable", true);
4313}
4314
4315
4316THREADED_TEST(VoidLiteral) {
4317  v8::HandleScope scope;
4318  LocalContext env;
4319
4320  Local<v8::FunctionTemplate> desc =
4321      v8::FunctionTemplate::New(0, v8::Handle<Value>());
4322  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4323
4324  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4325  env->Global()->Set(v8_str("undetectable"), obj);
4326
4327  ExpectBoolean("undefined == void 0", true);
4328  ExpectBoolean("undetectable == void 0", true);
4329  ExpectBoolean("null == void 0", true);
4330  ExpectBoolean("undefined === void 0", true);
4331  ExpectBoolean("undetectable === void 0", false);
4332  ExpectBoolean("null === void 0", false);
4333
4334  ExpectBoolean("void 0 == undefined", true);
4335  ExpectBoolean("void 0 == undetectable", true);
4336  ExpectBoolean("void 0 == null", true);
4337  ExpectBoolean("void 0 === undefined", true);
4338  ExpectBoolean("void 0 === undetectable", false);
4339  ExpectBoolean("void 0 === null", false);
4340
4341  ExpectString("(function() {"
4342               "  try {"
4343               "    return x === void 0;"
4344               "  } catch(e) {"
4345               "    return e.toString();"
4346               "  }"
4347               "})()",
4348               "ReferenceError: x is not defined");
4349  ExpectString("(function() {"
4350               "  try {"
4351               "    return void 0 === x;"
4352               "  } catch(e) {"
4353               "    return e.toString();"
4354               "  }"
4355               "})()",
4356               "ReferenceError: x is not defined");
4357}
4358
4359
4360THREADED_TEST(ExtensibleOnUndetectable) {
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  Local<String> source = v8_str("undetectable.x = 42;"
4372                                "undetectable.x");
4373
4374  Local<Script> script = Script::Compile(source);
4375
4376  CHECK_EQ(v8::Integer::New(42), script->Run());
4377
4378  ExpectBoolean("Object.isExtensible(undetectable)", true);
4379
4380  source = v8_str("Object.preventExtensions(undetectable);");
4381  script = Script::Compile(source);
4382  script->Run();
4383  ExpectBoolean("Object.isExtensible(undetectable)", false);
4384
4385  source = v8_str("undetectable.y = 2000;");
4386  script = Script::Compile(source);
4387  Local<Value> result(script->Run());
4388  ExpectBoolean("undetectable.y == undefined", true);
4389}
4390
4391
4392
4393THREADED_TEST(UndetectableString) {
4394  v8::HandleScope scope;
4395  LocalContext env;
4396
4397  Local<String> obj = String::NewUndetectable("foo");
4398  env->Global()->Set(v8_str("undetectable"), obj);
4399
4400  ExpectString("undetectable", "foo");
4401  ExpectString("typeof undetectable", "undefined");
4402  ExpectString("typeof(undetectable)", "undefined");
4403  ExpectBoolean("typeof undetectable == 'undefined'", true);
4404  ExpectBoolean("typeof undetectable == 'string'", false);
4405  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4406  ExpectBoolean("!undetectable", true);
4407
4408  ExpectObject("true&&undetectable", obj);
4409  ExpectBoolean("false&&undetectable", false);
4410  ExpectBoolean("true||undetectable", true);
4411  ExpectObject("false||undetectable", obj);
4412
4413  ExpectObject("undetectable&&true", obj);
4414  ExpectObject("undetectable&&false", obj);
4415  ExpectBoolean("undetectable||true", true);
4416  ExpectBoolean("undetectable||false", false);
4417
4418  ExpectBoolean("undetectable==null", true);
4419  ExpectBoolean("null==undetectable", true);
4420  ExpectBoolean("undetectable==undefined", true);
4421  ExpectBoolean("undefined==undetectable", true);
4422  ExpectBoolean("undetectable==undetectable", true);
4423
4424
4425  ExpectBoolean("undetectable===null", false);
4426  ExpectBoolean("null===undetectable", false);
4427  ExpectBoolean("undetectable===undefined", false);
4428  ExpectBoolean("undefined===undetectable", false);
4429  ExpectBoolean("undetectable===undetectable", true);
4430}
4431
4432
4433TEST(UndetectableOptimized) {
4434  i::FLAG_allow_natives_syntax = true;
4435  v8::HandleScope scope;
4436  LocalContext env;
4437
4438  Local<String> obj = String::NewUndetectable("foo");
4439  env->Global()->Set(v8_str("undetectable"), obj);
4440  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4441
4442  ExpectString(
4443      "function testBranch() {"
4444      "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
4445      "  if (%_IsUndetectableObject(detectable)) throw 2;"
4446      "}\n"
4447      "function testBool() {"
4448      "  var b1 = !%_IsUndetectableObject(undetectable);"
4449      "  var b2 = %_IsUndetectableObject(detectable);"
4450      "  if (b1) throw 3;"
4451      "  if (b2) throw 4;"
4452      "  return b1 == b2;"
4453      "}\n"
4454      "%OptimizeFunctionOnNextCall(testBranch);"
4455      "%OptimizeFunctionOnNextCall(testBool);"
4456      "for (var i = 0; i < 10; i++) {"
4457      "  testBranch();"
4458      "  testBool();"
4459      "}\n"
4460      "\"PASS\"",
4461      "PASS");
4462}
4463
4464
4465template <typename T> static void USE(T) { }
4466
4467
4468// This test is not intended to be run, just type checked.
4469static inline void PersistentHandles() {
4470  USE(PersistentHandles);
4471  Local<String> str = v8_str("foo");
4472  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4473  USE(p_str);
4474  Local<Script> scr = Script::Compile(v8_str(""));
4475  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4476  USE(p_scr);
4477  Local<ObjectTemplate> templ = ObjectTemplate::New();
4478  v8::Persistent<ObjectTemplate> p_templ =
4479    v8::Persistent<ObjectTemplate>::New(templ);
4480  USE(p_templ);
4481}
4482
4483
4484static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4485  ApiTestFuzzer::Fuzz();
4486  return v8::Undefined();
4487}
4488
4489
4490THREADED_TEST(GlobalObjectTemplate) {
4491  v8::HandleScope handle_scope;
4492  Local<ObjectTemplate> global_template = ObjectTemplate::New();
4493  global_template->Set(v8_str("JSNI_Log"),
4494                       v8::FunctionTemplate::New(HandleLogDelegator));
4495  v8::Persistent<Context> context = Context::New(0, global_template);
4496  Context::Scope context_scope(context);
4497  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4498  context.Dispose();
4499}
4500
4501
4502static const char* kSimpleExtensionSource =
4503  "function Foo() {"
4504  "  return 4;"
4505  "}";
4506
4507
4508THREADED_TEST(SimpleExtensions) {
4509  v8::HandleScope handle_scope;
4510  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4511  const char* extension_names[] = { "simpletest" };
4512  v8::ExtensionConfiguration extensions(1, extension_names);
4513  v8::Handle<Context> context = Context::New(&extensions);
4514  Context::Scope lock(context);
4515  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4516  CHECK_EQ(result, v8::Integer::New(4));
4517}
4518
4519
4520static const char* kEmbeddedExtensionSource =
4521    "function Ret54321(){return 54321;}~~@@$"
4522    "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4523static const int kEmbeddedExtensionSourceValidLen = 34;
4524
4525
4526THREADED_TEST(ExtensionMissingSourceLength) {
4527  v8::HandleScope handle_scope;
4528  v8::RegisterExtension(new Extension("srclentest_fail",
4529                                      kEmbeddedExtensionSource));
4530  const char* extension_names[] = { "srclentest_fail" };
4531  v8::ExtensionConfiguration extensions(1, extension_names);
4532  v8::Handle<Context> context = Context::New(&extensions);
4533  CHECK_EQ(0, *context);
4534}
4535
4536
4537THREADED_TEST(ExtensionWithSourceLength) {
4538  for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4539       source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4540    v8::HandleScope handle_scope;
4541    i::ScopedVector<char> extension_name(32);
4542    i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4543    v8::RegisterExtension(new Extension(extension_name.start(),
4544                                        kEmbeddedExtensionSource, 0, 0,
4545                                        source_len));
4546    const char* extension_names[1] = { extension_name.start() };
4547    v8::ExtensionConfiguration extensions(1, extension_names);
4548    v8::Handle<Context> context = Context::New(&extensions);
4549    if (source_len == kEmbeddedExtensionSourceValidLen) {
4550      Context::Scope lock(context);
4551      v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4552      CHECK_EQ(v8::Integer::New(54321), result);
4553    } else {
4554      // Anything but exactly the right length should fail to compile.
4555      CHECK_EQ(0, *context);
4556    }
4557  }
4558}
4559
4560
4561static const char* kEvalExtensionSource1 =
4562  "function UseEval1() {"
4563  "  var x = 42;"
4564  "  return eval('x');"
4565  "}";
4566
4567
4568static const char* kEvalExtensionSource2 =
4569  "(function() {"
4570  "  var x = 42;"
4571  "  function e() {"
4572  "    return eval('x');"
4573  "  }"
4574  "  this.UseEval2 = e;"
4575  "})()";
4576
4577
4578THREADED_TEST(UseEvalFromExtension) {
4579  v8::HandleScope handle_scope;
4580  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4581  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4582  const char* extension_names[] = { "evaltest1", "evaltest2" };
4583  v8::ExtensionConfiguration extensions(2, extension_names);
4584  v8::Handle<Context> context = Context::New(&extensions);
4585  Context::Scope lock(context);
4586  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4587  CHECK_EQ(result, v8::Integer::New(42));
4588  result = Script::Compile(v8_str("UseEval2()"))->Run();
4589  CHECK_EQ(result, v8::Integer::New(42));
4590}
4591
4592
4593static const char* kWithExtensionSource1 =
4594  "function UseWith1() {"
4595  "  var x = 42;"
4596  "  with({x:87}) { return x; }"
4597  "}";
4598
4599
4600
4601static const char* kWithExtensionSource2 =
4602  "(function() {"
4603  "  var x = 42;"
4604  "  function e() {"
4605  "    with ({x:87}) { return x; }"
4606  "  }"
4607  "  this.UseWith2 = e;"
4608  "})()";
4609
4610
4611THREADED_TEST(UseWithFromExtension) {
4612  v8::HandleScope handle_scope;
4613  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4614  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4615  const char* extension_names[] = { "withtest1", "withtest2" };
4616  v8::ExtensionConfiguration extensions(2, extension_names);
4617  v8::Handle<Context> context = Context::New(&extensions);
4618  Context::Scope lock(context);
4619  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4620  CHECK_EQ(result, v8::Integer::New(87));
4621  result = Script::Compile(v8_str("UseWith2()"))->Run();
4622  CHECK_EQ(result, v8::Integer::New(87));
4623}
4624
4625
4626THREADED_TEST(AutoExtensions) {
4627  v8::HandleScope handle_scope;
4628  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4629  extension->set_auto_enable(true);
4630  v8::RegisterExtension(extension);
4631  v8::Handle<Context> context = Context::New();
4632  Context::Scope lock(context);
4633  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4634  CHECK_EQ(result, v8::Integer::New(4));
4635}
4636
4637
4638static const char* kSyntaxErrorInExtensionSource =
4639    "[";
4640
4641
4642// Test that a syntax error in an extension does not cause a fatal
4643// error but results in an empty context.
4644THREADED_TEST(SyntaxErrorExtensions) {
4645  v8::HandleScope handle_scope;
4646  v8::RegisterExtension(new Extension("syntaxerror",
4647                                      kSyntaxErrorInExtensionSource));
4648  const char* extension_names[] = { "syntaxerror" };
4649  v8::ExtensionConfiguration extensions(1, extension_names);
4650  v8::Handle<Context> context = Context::New(&extensions);
4651  CHECK(context.IsEmpty());
4652}
4653
4654
4655static const char* kExceptionInExtensionSource =
4656    "throw 42";
4657
4658
4659// Test that an exception when installing an extension does not cause
4660// a fatal error but results in an empty context.
4661THREADED_TEST(ExceptionExtensions) {
4662  v8::HandleScope handle_scope;
4663  v8::RegisterExtension(new Extension("exception",
4664                                      kExceptionInExtensionSource));
4665  const char* extension_names[] = { "exception" };
4666  v8::ExtensionConfiguration extensions(1, extension_names);
4667  v8::Handle<Context> context = Context::New(&extensions);
4668  CHECK(context.IsEmpty());
4669}
4670
4671
4672static const char* kNativeCallInExtensionSource =
4673    "function call_runtime_last_index_of(x) {"
4674    "  return %StringLastIndexOf(x, 'bob', 10);"
4675    "}";
4676
4677
4678static const char* kNativeCallTest =
4679    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4680
4681// Test that a native runtime calls are supported in extensions.
4682THREADED_TEST(NativeCallInExtensions) {
4683  v8::HandleScope handle_scope;
4684  v8::RegisterExtension(new Extension("nativecall",
4685                                      kNativeCallInExtensionSource));
4686  const char* extension_names[] = { "nativecall" };
4687  v8::ExtensionConfiguration extensions(1, extension_names);
4688  v8::Handle<Context> context = Context::New(&extensions);
4689  Context::Scope lock(context);
4690  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4691  CHECK_EQ(result, v8::Integer::New(3));
4692}
4693
4694
4695class NativeFunctionExtension : public Extension {
4696 public:
4697  NativeFunctionExtension(const char* name,
4698                          const char* source,
4699                          v8::InvocationCallback fun = &Echo)
4700      : Extension(name, source),
4701        function_(fun) { }
4702
4703  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4704      v8::Handle<v8::String> name) {
4705    return v8::FunctionTemplate::New(function_);
4706  }
4707
4708  static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4709    if (args.Length() >= 1) return (args[0]);
4710    return v8::Undefined();
4711  }
4712 private:
4713  v8::InvocationCallback function_;
4714};
4715
4716
4717THREADED_TEST(NativeFunctionDeclaration) {
4718  v8::HandleScope handle_scope;
4719  const char* name = "nativedecl";
4720  v8::RegisterExtension(new NativeFunctionExtension(name,
4721                                                    "native function foo();"));
4722  const char* extension_names[] = { name };
4723  v8::ExtensionConfiguration extensions(1, extension_names);
4724  v8::Handle<Context> context = Context::New(&extensions);
4725  Context::Scope lock(context);
4726  v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4727  CHECK_EQ(result, v8::Integer::New(42));
4728}
4729
4730
4731THREADED_TEST(NativeFunctionDeclarationError) {
4732  v8::HandleScope handle_scope;
4733  const char* name = "nativedeclerr";
4734  // Syntax error in extension code.
4735  v8::RegisterExtension(new NativeFunctionExtension(name,
4736                                                    "native\nfunction foo();"));
4737  const char* extension_names[] = { name };
4738  v8::ExtensionConfiguration extensions(1, extension_names);
4739  v8::Handle<Context> context(Context::New(&extensions));
4740  ASSERT(context.IsEmpty());
4741}
4742
4743THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4744  v8::HandleScope handle_scope;
4745  const char* name = "nativedeclerresc";
4746  // Syntax error in extension code - escape code in "native" means that
4747  // it's not treated as a keyword.
4748  v8::RegisterExtension(new NativeFunctionExtension(
4749      name,
4750      "nativ\\u0065 function foo();"));
4751  const char* extension_names[] = { name };
4752  v8::ExtensionConfiguration extensions(1, extension_names);
4753  v8::Handle<Context> context(Context::New(&extensions));
4754  ASSERT(context.IsEmpty());
4755}
4756
4757
4758static void CheckDependencies(const char* name, const char* expected) {
4759  v8::HandleScope handle_scope;
4760  v8::ExtensionConfiguration config(1, &name);
4761  LocalContext context(&config);
4762  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4763}
4764
4765
4766/*
4767 * Configuration:
4768 *
4769 *     /-- B <--\
4770 * A <-          -- D <-- E
4771 *     \-- C <--/
4772 */
4773THREADED_TEST(ExtensionDependency) {
4774  static const char* kEDeps[] = { "D" };
4775  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4776  static const char* kDDeps[] = { "B", "C" };
4777  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4778  static const char* kBCDeps[] = { "A" };
4779  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4780  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4781  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4782  CheckDependencies("A", "undefinedA");
4783  CheckDependencies("B", "undefinedAB");
4784  CheckDependencies("C", "undefinedAC");
4785  CheckDependencies("D", "undefinedABCD");
4786  CheckDependencies("E", "undefinedABCDE");
4787  v8::HandleScope handle_scope;
4788  static const char* exts[2] = { "C", "E" };
4789  v8::ExtensionConfiguration config(2, exts);
4790  LocalContext context(&config);
4791  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4792}
4793
4794
4795static const char* kExtensionTestScript =
4796  "native function A();"
4797  "native function B();"
4798  "native function C();"
4799  "function Foo(i) {"
4800  "  if (i == 0) return A();"
4801  "  if (i == 1) return B();"
4802  "  if (i == 2) return C();"
4803  "}";
4804
4805
4806static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4807  ApiTestFuzzer::Fuzz();
4808  if (args.IsConstructCall()) {
4809    args.This()->Set(v8_str("data"), args.Data());
4810    return v8::Null();
4811  }
4812  return args.Data();
4813}
4814
4815
4816class FunctionExtension : public Extension {
4817 public:
4818  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4819  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4820      v8::Handle<String> name);
4821};
4822
4823
4824static int lookup_count = 0;
4825v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4826      v8::Handle<String> name) {
4827  lookup_count++;
4828  if (name->Equals(v8_str("A"))) {
4829    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4830  } else if (name->Equals(v8_str("B"))) {
4831    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4832  } else if (name->Equals(v8_str("C"))) {
4833    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4834  } else {
4835    return v8::Handle<v8::FunctionTemplate>();
4836  }
4837}
4838
4839
4840THREADED_TEST(FunctionLookup) {
4841  v8::RegisterExtension(new FunctionExtension());
4842  v8::HandleScope handle_scope;
4843  static const char* exts[1] = { "functiontest" };
4844  v8::ExtensionConfiguration config(1, exts);
4845  LocalContext context(&config);
4846  CHECK_EQ(3, lookup_count);
4847  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4848  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4849  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4850}
4851
4852
4853THREADED_TEST(NativeFunctionConstructCall) {
4854  v8::RegisterExtension(new FunctionExtension());
4855  v8::HandleScope handle_scope;
4856  static const char* exts[1] = { "functiontest" };
4857  v8::ExtensionConfiguration config(1, exts);
4858  LocalContext context(&config);
4859  for (int i = 0; i < 10; i++) {
4860    // Run a few times to ensure that allocation of objects doesn't
4861    // change behavior of a constructor function.
4862    CHECK_EQ(v8::Integer::New(8),
4863             Script::Compile(v8_str("(new A()).data"))->Run());
4864    CHECK_EQ(v8::Integer::New(7),
4865             Script::Compile(v8_str("(new B()).data"))->Run());
4866    CHECK_EQ(v8::Integer::New(6),
4867             Script::Compile(v8_str("(new C()).data"))->Run());
4868  }
4869}
4870
4871
4872static const char* last_location;
4873static const char* last_message;
4874void StoringErrorCallback(const char* location, const char* message) {
4875  if (last_location == NULL) {
4876    last_location = location;
4877    last_message = message;
4878  }
4879}
4880
4881
4882// ErrorReporting creates a circular extensions configuration and
4883// tests that the fatal error handler gets called.  This renders V8
4884// unusable and therefore this test cannot be run in parallel.
4885TEST(ErrorReporting) {
4886  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4887  static const char* aDeps[] = { "B" };
4888  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4889  static const char* bDeps[] = { "A" };
4890  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4891  last_location = NULL;
4892  v8::ExtensionConfiguration config(1, bDeps);
4893  v8::Handle<Context> context = Context::New(&config);
4894  CHECK(context.IsEmpty());
4895  CHECK_NE(last_location, NULL);
4896}
4897
4898
4899static const char* js_code_causing_huge_string_flattening =
4900    "var str = 'X';"
4901    "for (var i = 0; i < 30; i++) {"
4902    "  str = str + str;"
4903    "}"
4904    "str.match(/X/);";
4905
4906
4907void OOMCallback(const char* location, const char* message) {
4908  exit(0);
4909}
4910
4911
4912TEST(RegexpOutOfMemory) {
4913  // Execute a script that causes out of memory when flattening a string.
4914  v8::HandleScope scope;
4915  v8::V8::SetFatalErrorHandler(OOMCallback);
4916  LocalContext context;
4917  Local<Script> script =
4918      Script::Compile(String::New(js_code_causing_huge_string_flattening));
4919  last_location = NULL;
4920  Local<Value> result(script->Run());
4921
4922  CHECK(false);  // Should not return.
4923}
4924
4925
4926static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4927                                             v8::Handle<Value> data) {
4928  CHECK_EQ(v8::Undefined(), data);
4929  CHECK(message->GetScriptResourceName()->IsUndefined());
4930  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4931  message->GetLineNumber();
4932  message->GetSourceLine();
4933}
4934
4935
4936THREADED_TEST(ErrorWithMissingScriptInfo) {
4937  v8::HandleScope scope;
4938  LocalContext context;
4939  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4940  Script::Compile(v8_str("throw Error()"))->Run();
4941  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4942}
4943
4944
4945int global_index = 0;
4946
4947class Snorkel {
4948 public:
4949  Snorkel() { index_ = global_index++; }
4950  int index_;
4951};
4952
4953class Whammy {
4954 public:
4955  Whammy() {
4956    cursor_ = 0;
4957  }
4958  ~Whammy() {
4959    script_.Dispose();
4960  }
4961  v8::Handle<Script> getScript() {
4962    if (script_.IsEmpty())
4963      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4964    return Local<Script>(*script_);
4965  }
4966
4967 public:
4968  static const int kObjectCount = 256;
4969  int cursor_;
4970  v8::Persistent<v8::Object> objects_[kObjectCount];
4971  v8::Persistent<Script> script_;
4972};
4973
4974static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4975  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4976  delete snorkel;
4977  obj.ClearWeak();
4978}
4979
4980v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4981                                       const AccessorInfo& info) {
4982  Whammy* whammy =
4983    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4984
4985  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4986
4987  v8::Handle<v8::Object> obj = v8::Object::New();
4988  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4989  if (!prev.IsEmpty()) {
4990    prev->Set(v8_str("next"), obj);
4991    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4992    whammy->objects_[whammy->cursor_].Clear();
4993  }
4994  whammy->objects_[whammy->cursor_] = global;
4995  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4996  return whammy->getScript()->Run();
4997}
4998
4999THREADED_TEST(WeakReference) {
5000  v8::HandleScope handle_scope;
5001  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
5002  Whammy* whammy = new Whammy();
5003  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5004                                 0, 0, 0, 0,
5005                                 v8::External::New(whammy));
5006  const char* extension_list[] = { "v8/gc" };
5007  v8::ExtensionConfiguration extensions(1, extension_list);
5008  v8::Persistent<Context> context = Context::New(&extensions);
5009  Context::Scope context_scope(context);
5010
5011  v8::Handle<v8::Object> interceptor = templ->NewInstance();
5012  context->Global()->Set(v8_str("whammy"), interceptor);
5013  const char* code =
5014      "var last;"
5015      "for (var i = 0; i < 10000; i++) {"
5016      "  var obj = whammy.length;"
5017      "  if (last) last.next = obj;"
5018      "  last = obj;"
5019      "}"
5020      "gc();"
5021      "4";
5022  v8::Handle<Value> result = CompileRun(code);
5023  CHECK_EQ(4.0, result->NumberValue());
5024  delete whammy;
5025  context.Dispose();
5026}
5027
5028
5029static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5030  obj.Dispose();
5031  obj.Clear();
5032  *(reinterpret_cast<bool*>(data)) = true;
5033}
5034
5035
5036THREADED_TEST(IndependentWeakHandle) {
5037  v8::Persistent<Context> context = Context::New();
5038  Context::Scope context_scope(context);
5039
5040  v8::Persistent<v8::Object> object_a;
5041
5042  {
5043    v8::HandleScope handle_scope;
5044    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5045  }
5046
5047  bool object_a_disposed = false;
5048  object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5049  object_a.MarkIndependent();
5050  HEAP->PerformScavenge();
5051  CHECK(object_a_disposed);
5052}
5053
5054
5055static void InvokeScavenge() {
5056  HEAP->PerformScavenge();
5057}
5058
5059
5060static void InvokeMarkSweep() {
5061  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5062}
5063
5064
5065static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5066  obj.Dispose();
5067  obj.Clear();
5068  *(reinterpret_cast<bool*>(data)) = true;
5069  InvokeScavenge();
5070}
5071
5072
5073static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5074  obj.Dispose();
5075  obj.Clear();
5076  *(reinterpret_cast<bool*>(data)) = true;
5077  InvokeMarkSweep();
5078}
5079
5080
5081THREADED_TEST(GCFromWeakCallbacks) {
5082  v8::Persistent<Context> context = Context::New();
5083  Context::Scope context_scope(context);
5084
5085  static const int kNumberOfGCTypes = 2;
5086  v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5087      {&ForceScavenge, &ForceMarkSweep};
5088
5089  typedef void (*GCInvoker)();
5090  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5091
5092  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5093    for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5094      v8::Persistent<v8::Object> object;
5095      {
5096        v8::HandleScope handle_scope;
5097        object = v8::Persistent<v8::Object>::New(v8::Object::New());
5098      }
5099      bool disposed = false;
5100      object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5101      object.MarkIndependent();
5102      invoke_gc[outer_gc]();
5103      CHECK(disposed);
5104    }
5105  }
5106}
5107
5108
5109static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5110  obj.ClearWeak();
5111  *(reinterpret_cast<bool*>(data)) = true;
5112}
5113
5114
5115THREADED_TEST(IndependentHandleRevival) {
5116  v8::Persistent<Context> context = Context::New();
5117  Context::Scope context_scope(context);
5118
5119  v8::Persistent<v8::Object> object;
5120  {
5121    v8::HandleScope handle_scope;
5122    object = v8::Persistent<v8::Object>::New(v8::Object::New());
5123    object->Set(v8_str("x"), v8::Integer::New(1));
5124    v8::Local<String> y_str = v8_str("y");
5125    object->Set(y_str, y_str);
5126  }
5127  bool revived = false;
5128  object.MakeWeak(&revived, &RevivingCallback);
5129  object.MarkIndependent();
5130  HEAP->PerformScavenge();
5131  CHECK(revived);
5132  HEAP->CollectAllGarbage(true);
5133  {
5134    v8::HandleScope handle_scope;
5135    v8::Local<String> y_str = v8_str("y");
5136    CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5137    CHECK(object->Get(y_str)->Equals(y_str));
5138  }
5139}
5140
5141
5142v8::Handle<Function> args_fun;
5143
5144
5145static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5146  ApiTestFuzzer::Fuzz();
5147  CHECK_EQ(args_fun, args.Callee());
5148  CHECK_EQ(3, args.Length());
5149  CHECK_EQ(v8::Integer::New(1), args[0]);
5150  CHECK_EQ(v8::Integer::New(2), args[1]);
5151  CHECK_EQ(v8::Integer::New(3), args[2]);
5152  CHECK_EQ(v8::Undefined(), args[3]);
5153  v8::HandleScope scope;
5154  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5155  return v8::Undefined();
5156}
5157
5158
5159THREADED_TEST(Arguments) {
5160  v8::HandleScope scope;
5161  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5162  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5163  LocalContext context(NULL, global);
5164  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5165  v8_compile("f(1, 2, 3)")->Run();
5166}
5167
5168
5169static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5170                                        const AccessorInfo&) {
5171  return v8::Handle<Value>();
5172}
5173
5174
5175static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5176                                        const AccessorInfo&) {
5177  return v8::Handle<Value>();
5178}
5179
5180
5181static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5182                                        const AccessorInfo&) {
5183  if (!name->Equals(v8_str("foo"))) {
5184    return v8::Handle<v8::Boolean>();  // not intercepted
5185  }
5186
5187  return v8::False();  // intercepted, and don't delete the property
5188}
5189
5190
5191static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5192  if (index != 2) {
5193    return v8::Handle<v8::Boolean>();  // not intercepted
5194  }
5195
5196  return v8::False();  // intercepted, and don't delete the property
5197}
5198
5199
5200THREADED_TEST(Deleter) {
5201  v8::HandleScope scope;
5202  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5203  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5204  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5205  LocalContext context;
5206  context->Global()->Set(v8_str("k"), obj->NewInstance());
5207  CompileRun(
5208    "k.foo = 'foo';"
5209    "k.bar = 'bar';"
5210    "k[2] = 2;"
5211    "k[4] = 4;");
5212  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5213  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5214
5215  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5216  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5217
5218  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5219  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5220
5221  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5222  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5223}
5224
5225
5226static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5227  ApiTestFuzzer::Fuzz();
5228  if (name->Equals(v8_str("foo")) ||
5229      name->Equals(v8_str("bar")) ||
5230      name->Equals(v8_str("baz"))) {
5231    return v8::Undefined();
5232  }
5233  return v8::Handle<Value>();
5234}
5235
5236
5237static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5238  ApiTestFuzzer::Fuzz();
5239  if (index == 0 || index == 1) return v8::Undefined();
5240  return v8::Handle<Value>();
5241}
5242
5243
5244static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5245  ApiTestFuzzer::Fuzz();
5246  v8::Handle<v8::Array> result = v8::Array::New(3);
5247  result->Set(v8::Integer::New(0), v8_str("foo"));
5248  result->Set(v8::Integer::New(1), v8_str("bar"));
5249  result->Set(v8::Integer::New(2), v8_str("baz"));
5250  return result;
5251}
5252
5253
5254static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5255  ApiTestFuzzer::Fuzz();
5256  v8::Handle<v8::Array> result = v8::Array::New(2);
5257  result->Set(v8::Integer::New(0), v8_str("0"));
5258  result->Set(v8::Integer::New(1), v8_str("1"));
5259  return result;
5260}
5261
5262
5263THREADED_TEST(Enumerators) {
5264  v8::HandleScope scope;
5265  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5266  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5267  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5268  LocalContext context;
5269  context->Global()->Set(v8_str("k"), obj->NewInstance());
5270  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5271    "k[10] = 0;"
5272    "k.a = 0;"
5273    "k[5] = 0;"
5274    "k.b = 0;"
5275    "k[4294967295] = 0;"
5276    "k.c = 0;"
5277    "k[4294967296] = 0;"
5278    "k.d = 0;"
5279    "k[140000] = 0;"
5280    "k.e = 0;"
5281    "k[30000000000] = 0;"
5282    "k.f = 0;"
5283    "var result = [];"
5284    "for (var prop in k) {"
5285    "  result.push(prop);"
5286    "}"
5287    "result"));
5288  // Check that we get all the property names returned including the
5289  // ones from the enumerators in the right order: indexed properties
5290  // in numerical order, indexed interceptor properties, named
5291  // properties in insertion order, named interceptor properties.
5292  // This order is not mandated by the spec, so this test is just
5293  // documenting our behavior.
5294  CHECK_EQ(17, result->Length());
5295  // Indexed properties in numerical order.
5296  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5297  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5298  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5299  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5300  // Indexed interceptor properties in the order they are returned
5301  // from the enumerator interceptor.
5302  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5303  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5304  // Named properties in insertion order.
5305  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5306  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5307  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5308  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5309  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5310  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5311  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5312  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5313  // Named interceptor properties.
5314  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5315  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5316  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5317}
5318
5319
5320int p_getter_count;
5321int p_getter_count2;
5322
5323
5324static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5325  ApiTestFuzzer::Fuzz();
5326  p_getter_count++;
5327  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5328  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5329  if (name->Equals(v8_str("p1"))) {
5330    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5331  } else if (name->Equals(v8_str("p2"))) {
5332    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5333  } else if (name->Equals(v8_str("p3"))) {
5334    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5335  } else if (name->Equals(v8_str("p4"))) {
5336    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5337  }
5338  return v8::Undefined();
5339}
5340
5341
5342static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5343  ApiTestFuzzer::Fuzz();
5344  LocalContext context;
5345  context->Global()->Set(v8_str("o1"), obj->NewInstance());
5346  CompileRun(
5347    "o1.__proto__ = { };"
5348    "var o2 = { __proto__: o1 };"
5349    "var o3 = { __proto__: o2 };"
5350    "var o4 = { __proto__: o3 };"
5351    "for (var i = 0; i < 10; i++) o4.p4;"
5352    "for (var i = 0; i < 10; i++) o3.p3;"
5353    "for (var i = 0; i < 10; i++) o2.p2;"
5354    "for (var i = 0; i < 10; i++) o1.p1;");
5355}
5356
5357
5358static v8::Handle<Value> PGetter2(Local<String> name,
5359                                  const AccessorInfo& info) {
5360  ApiTestFuzzer::Fuzz();
5361  p_getter_count2++;
5362  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5363  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5364  if (name->Equals(v8_str("p1"))) {
5365    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5366  } else if (name->Equals(v8_str("p2"))) {
5367    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5368  } else if (name->Equals(v8_str("p3"))) {
5369    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5370  } else if (name->Equals(v8_str("p4"))) {
5371    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5372  }
5373  return v8::Undefined();
5374}
5375
5376
5377THREADED_TEST(GetterHolders) {
5378  v8::HandleScope scope;
5379  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5380  obj->SetAccessor(v8_str("p1"), PGetter);
5381  obj->SetAccessor(v8_str("p2"), PGetter);
5382  obj->SetAccessor(v8_str("p3"), PGetter);
5383  obj->SetAccessor(v8_str("p4"), PGetter);
5384  p_getter_count = 0;
5385  RunHolderTest(obj);
5386  CHECK_EQ(40, p_getter_count);
5387}
5388
5389
5390THREADED_TEST(PreInterceptorHolders) {
5391  v8::HandleScope scope;
5392  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5393  obj->SetNamedPropertyHandler(PGetter2);
5394  p_getter_count2 = 0;
5395  RunHolderTest(obj);
5396  CHECK_EQ(40, p_getter_count2);
5397}
5398
5399
5400THREADED_TEST(ObjectInstantiation) {
5401  v8::HandleScope scope;
5402  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5403  templ->SetAccessor(v8_str("t"), PGetter2);
5404  LocalContext context;
5405  context->Global()->Set(v8_str("o"), templ->NewInstance());
5406  for (int i = 0; i < 100; i++) {
5407    v8::HandleScope inner_scope;
5408    v8::Handle<v8::Object> obj = templ->NewInstance();
5409    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5410    context->Global()->Set(v8_str("o2"), obj);
5411    v8::Handle<Value> value =
5412        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5413    CHECK_EQ(v8::True(), value);
5414    context->Global()->Set(v8_str("o"), obj);
5415  }
5416}
5417
5418
5419static int StrCmp16(uint16_t* a, uint16_t* b) {
5420  while (true) {
5421    if (*a == 0 && *b == 0) return 0;
5422    if (*a != *b) return 0 + *a - *b;
5423    a++;
5424    b++;
5425  }
5426}
5427
5428
5429static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5430  while (true) {
5431    if (n-- == 0) return 0;
5432    if (*a == 0 && *b == 0) return 0;
5433    if (*a != *b) return 0 + *a - *b;
5434    a++;
5435    b++;
5436  }
5437}
5438
5439
5440THREADED_TEST(StringWrite) {
5441  LocalContext context;
5442  v8::HandleScope scope;
5443  v8::Handle<String> str = v8_str("abcde");
5444  // abc<Icelandic eth><Unicode snowman>.
5445  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5446  const int kStride = 4;  // Must match stride in for loops in JS below.
5447  CompileRun(
5448      "var left = '';"
5449      "for (var i = 0; i < 0xd800; i += 4) {"
5450      "  left = left + String.fromCharCode(i);"
5451      "}");
5452  CompileRun(
5453      "var right = '';"
5454      "for (var i = 0; i < 0xd800; i += 4) {"
5455      "  right = String.fromCharCode(i) + right;"
5456      "}");
5457  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5458  Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5459  Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5460
5461  CHECK_EQ(5, str2->Length());
5462  CHECK_EQ(0xd800 / kStride, left_tree->Length());
5463  CHECK_EQ(0xd800 / kStride, right_tree->Length());
5464
5465  char buf[100];
5466  char utf8buf[0xd800 * 3];
5467  uint16_t wbuf[100];
5468  int len;
5469  int charlen;
5470
5471  memset(utf8buf, 0x1, 1000);
5472  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5473  CHECK_EQ(9, len);
5474  CHECK_EQ(5, charlen);
5475  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5476
5477  memset(utf8buf, 0x1, 1000);
5478  len = str2->WriteUtf8(utf8buf, 8, &charlen);
5479  CHECK_EQ(8, len);
5480  CHECK_EQ(5, charlen);
5481  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5482
5483  memset(utf8buf, 0x1, 1000);
5484  len = str2->WriteUtf8(utf8buf, 7, &charlen);
5485  CHECK_EQ(5, len);
5486  CHECK_EQ(4, charlen);
5487  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5488
5489  memset(utf8buf, 0x1, 1000);
5490  len = str2->WriteUtf8(utf8buf, 6, &charlen);
5491  CHECK_EQ(5, len);
5492  CHECK_EQ(4, charlen);
5493  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5494
5495  memset(utf8buf, 0x1, 1000);
5496  len = str2->WriteUtf8(utf8buf, 5, &charlen);
5497  CHECK_EQ(5, len);
5498  CHECK_EQ(4, charlen);
5499  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5500
5501  memset(utf8buf, 0x1, 1000);
5502  len = str2->WriteUtf8(utf8buf, 4, &charlen);
5503  CHECK_EQ(3, len);
5504  CHECK_EQ(3, charlen);
5505  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5506
5507  memset(utf8buf, 0x1, 1000);
5508  len = str2->WriteUtf8(utf8buf, 3, &charlen);
5509  CHECK_EQ(3, len);
5510  CHECK_EQ(3, charlen);
5511  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5512
5513  memset(utf8buf, 0x1, 1000);
5514  len = str2->WriteUtf8(utf8buf, 2, &charlen);
5515  CHECK_EQ(2, len);
5516  CHECK_EQ(2, charlen);
5517  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5518
5519  memset(utf8buf, 0x1, sizeof(utf8buf));
5520  len = left_tree->Utf8Length();
5521  int utf8_expected =
5522      (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5523  CHECK_EQ(utf8_expected, len);
5524  len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5525  CHECK_EQ(utf8_expected, len);
5526  CHECK_EQ(0xd800 / kStride, charlen);
5527  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5528  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5529  CHECK_EQ(0xc0 - kStride,
5530           static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5531  CHECK_EQ(1, utf8buf[utf8_expected]);
5532
5533  memset(utf8buf, 0x1, sizeof(utf8buf));
5534  len = right_tree->Utf8Length();
5535  CHECK_EQ(utf8_expected, len);
5536  len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5537  CHECK_EQ(utf8_expected, len);
5538  CHECK_EQ(0xd800 / kStride, charlen);
5539  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5540  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5541  CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5542  CHECK_EQ(1, utf8buf[utf8_expected]);
5543
5544  memset(buf, 0x1, sizeof(buf));
5545  memset(wbuf, 0x1, sizeof(wbuf));
5546  len = str->WriteAscii(buf);
5547  CHECK_EQ(5, len);
5548  len = str->Write(wbuf);
5549  CHECK_EQ(5, len);
5550  CHECK_EQ(0, strcmp("abcde", buf));
5551  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5552  CHECK_EQ(0, StrCmp16(answer1, wbuf));
5553
5554  memset(buf, 0x1, sizeof(buf));
5555  memset(wbuf, 0x1, sizeof(wbuf));
5556  len = str->WriteAscii(buf, 0, 4);
5557  CHECK_EQ(4, len);
5558  len = str->Write(wbuf, 0, 4);
5559  CHECK_EQ(4, len);
5560  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5561  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5562  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5563
5564  memset(buf, 0x1, sizeof(buf));
5565  memset(wbuf, 0x1, sizeof(wbuf));
5566  len = str->WriteAscii(buf, 0, 5);
5567  CHECK_EQ(5, len);
5568  len = str->Write(wbuf, 0, 5);
5569  CHECK_EQ(5, len);
5570  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5571  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5572  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5573
5574  memset(buf, 0x1, sizeof(buf));
5575  memset(wbuf, 0x1, sizeof(wbuf));
5576  len = str->WriteAscii(buf, 0, 6);
5577  CHECK_EQ(5, len);
5578  len = str->Write(wbuf, 0, 6);
5579  CHECK_EQ(5, len);
5580  CHECK_EQ(0, strcmp("abcde", buf));
5581  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5582  CHECK_EQ(0, StrCmp16(answer4, wbuf));
5583
5584  memset(buf, 0x1, sizeof(buf));
5585  memset(wbuf, 0x1, sizeof(wbuf));
5586  len = str->WriteAscii(buf, 4, -1);
5587  CHECK_EQ(1, len);
5588  len = str->Write(wbuf, 4, -1);
5589  CHECK_EQ(1, len);
5590  CHECK_EQ(0, strcmp("e", buf));
5591  uint16_t answer5[] = {'e', '\0'};
5592  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5593
5594  memset(buf, 0x1, sizeof(buf));
5595  memset(wbuf, 0x1, sizeof(wbuf));
5596  len = str->WriteAscii(buf, 4, 6);
5597  CHECK_EQ(1, len);
5598  len = str->Write(wbuf, 4, 6);
5599  CHECK_EQ(1, len);
5600  CHECK_EQ(0, strcmp("e", buf));
5601  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5602
5603  memset(buf, 0x1, sizeof(buf));
5604  memset(wbuf, 0x1, sizeof(wbuf));
5605  len = str->WriteAscii(buf, 4, 1);
5606  CHECK_EQ(1, len);
5607  len = str->Write(wbuf, 4, 1);
5608  CHECK_EQ(1, len);
5609  CHECK_EQ(0, strncmp("e\1", buf, 2));
5610  uint16_t answer6[] = {'e', 0x101};
5611  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5612
5613  memset(buf, 0x1, sizeof(buf));
5614  memset(wbuf, 0x1, sizeof(wbuf));
5615  len = str->WriteAscii(buf, 3, 1);
5616  CHECK_EQ(1, len);
5617  len = str->Write(wbuf, 3, 1);
5618  CHECK_EQ(1, len);
5619  CHECK_EQ(0, strncmp("d\1", buf, 2));
5620  uint16_t answer7[] = {'d', 0x101};
5621  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5622
5623  memset(wbuf, 0x1, sizeof(wbuf));
5624  wbuf[5] = 'X';
5625  len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5626  CHECK_EQ(5, len);
5627  CHECK_EQ('X', wbuf[5]);
5628  uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5629  uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5630  CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5631  CHECK_NE(0, StrCmp16(answer8b, wbuf));
5632  wbuf[5] = '\0';
5633  CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5634
5635  memset(buf, 0x1, sizeof(buf));
5636  buf[5] = 'X';
5637  len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5638  CHECK_EQ(5, len);
5639  CHECK_EQ('X', buf[5]);
5640  CHECK_EQ(0, strncmp("abcde", buf, 5));
5641  CHECK_NE(0, strcmp("abcde", buf));
5642  buf[5] = '\0';
5643  CHECK_EQ(0, strcmp("abcde", buf));
5644
5645  memset(utf8buf, 0x1, sizeof(utf8buf));
5646  utf8buf[8] = 'X';
5647  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5648                        String::NO_NULL_TERMINATION);
5649  CHECK_EQ(8, len);
5650  CHECK_EQ('X', utf8buf[8]);
5651  CHECK_EQ(5, charlen);
5652  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5653  CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5654  utf8buf[8] = '\0';
5655  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5656}
5657
5658
5659THREADED_TEST(ToArrayIndex) {
5660  v8::HandleScope scope;
5661  LocalContext context;
5662
5663  v8::Handle<String> str = v8_str("42");
5664  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5665  CHECK(!index.IsEmpty());
5666  CHECK_EQ(42.0, index->Uint32Value());
5667  str = v8_str("42asdf");
5668  index = str->ToArrayIndex();
5669  CHECK(index.IsEmpty());
5670  str = v8_str("-42");
5671  index = str->ToArrayIndex();
5672  CHECK(index.IsEmpty());
5673  str = v8_str("4294967295");
5674  index = str->ToArrayIndex();
5675  CHECK(!index.IsEmpty());
5676  CHECK_EQ(4294967295.0, index->Uint32Value());
5677  v8::Handle<v8::Number> num = v8::Number::New(1);
5678  index = num->ToArrayIndex();
5679  CHECK(!index.IsEmpty());
5680  CHECK_EQ(1.0, index->Uint32Value());
5681  num = v8::Number::New(-1);
5682  index = num->ToArrayIndex();
5683  CHECK(index.IsEmpty());
5684  v8::Handle<v8::Object> obj = v8::Object::New();
5685  index = obj->ToArrayIndex();
5686  CHECK(index.IsEmpty());
5687}
5688
5689
5690THREADED_TEST(ErrorConstruction) {
5691  v8::HandleScope scope;
5692  LocalContext context;
5693
5694  v8::Handle<String> foo = v8_str("foo");
5695  v8::Handle<String> message = v8_str("message");
5696  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5697  CHECK(range_error->IsObject());
5698  v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
5699  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
5700  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5701  CHECK(reference_error->IsObject());
5702  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
5703  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5704  CHECK(syntax_error->IsObject());
5705  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
5706  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5707  CHECK(type_error->IsObject());
5708  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
5709  v8::Handle<Value> error = v8::Exception::Error(foo);
5710  CHECK(error->IsObject());
5711  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
5712}
5713
5714
5715static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5716  ApiTestFuzzer::Fuzz();
5717  return v8_num(10);
5718}
5719
5720
5721static void YSetter(Local<String> name,
5722                    Local<Value> value,
5723                    const AccessorInfo& info) {
5724  if (info.This()->Has(name)) {
5725    info.This()->Delete(name);
5726  }
5727  info.This()->Set(name, value);
5728}
5729
5730
5731THREADED_TEST(DeleteAccessor) {
5732  v8::HandleScope scope;
5733  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5734  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5735  LocalContext context;
5736  v8::Handle<v8::Object> holder = obj->NewInstance();
5737  context->Global()->Set(v8_str("holder"), holder);
5738  v8::Handle<Value> result = CompileRun(
5739      "holder.y = 11; holder.y = 12; holder.y");
5740  CHECK_EQ(12, result->Uint32Value());
5741}
5742
5743
5744THREADED_TEST(TypeSwitch) {
5745  v8::HandleScope scope;
5746  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5747  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5748  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5749  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5750  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5751  LocalContext context;
5752  v8::Handle<v8::Object> obj0 = v8::Object::New();
5753  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5754  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5755  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5756  for (int i = 0; i < 10; i++) {
5757    CHECK_EQ(0, type_switch->match(obj0));
5758    CHECK_EQ(1, type_switch->match(obj1));
5759    CHECK_EQ(2, type_switch->match(obj2));
5760    CHECK_EQ(3, type_switch->match(obj3));
5761    CHECK_EQ(3, type_switch->match(obj3));
5762    CHECK_EQ(2, type_switch->match(obj2));
5763    CHECK_EQ(1, type_switch->match(obj1));
5764    CHECK_EQ(0, type_switch->match(obj0));
5765  }
5766}
5767
5768
5769// For use within the TestSecurityHandler() test.
5770static bool g_security_callback_result = false;
5771static bool NamedSecurityTestCallback(Local<v8::Object> global,
5772                                      Local<Value> name,
5773                                      v8::AccessType type,
5774                                      Local<Value> data) {
5775  // Always allow read access.
5776  if (type == v8::ACCESS_GET)
5777    return true;
5778
5779  // Sometimes allow other access.
5780  return g_security_callback_result;
5781}
5782
5783
5784static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5785                                        uint32_t key,
5786                                        v8::AccessType type,
5787                                        Local<Value> data) {
5788  // Always allow read access.
5789  if (type == v8::ACCESS_GET)
5790    return true;
5791
5792  // Sometimes allow other access.
5793  return g_security_callback_result;
5794}
5795
5796
5797static int trouble_nesting = 0;
5798static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5799  ApiTestFuzzer::Fuzz();
5800  trouble_nesting++;
5801
5802  // Call a JS function that throws an uncaught exception.
5803  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5804  Local<Value> trouble_callee = (trouble_nesting == 3) ?
5805    arg_this->Get(v8_str("trouble_callee")) :
5806    arg_this->Get(v8_str("trouble_caller"));
5807  CHECK(trouble_callee->IsFunction());
5808  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5809}
5810
5811
5812static int report_count = 0;
5813static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5814                                             v8::Handle<Value>) {
5815  report_count++;
5816}
5817
5818
5819// Counts uncaught exceptions, but other tests running in parallel
5820// also have uncaught exceptions.
5821TEST(ApiUncaughtException) {
5822  report_count = 0;
5823  v8::HandleScope scope;
5824  LocalContext env;
5825  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5826
5827  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5828  v8::Local<v8::Object> global = env->Global();
5829  global->Set(v8_str("trouble"), fun->GetFunction());
5830
5831  Script::Compile(v8_str("function trouble_callee() {"
5832                         "  var x = null;"
5833                         "  return x.foo;"
5834                         "};"
5835                         "function trouble_caller() {"
5836                         "  trouble();"
5837                         "};"))->Run();
5838  Local<Value> trouble = global->Get(v8_str("trouble"));
5839  CHECK(trouble->IsFunction());
5840  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5841  CHECK(trouble_callee->IsFunction());
5842  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5843  CHECK(trouble_caller->IsFunction());
5844  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5845  CHECK_EQ(1, report_count);
5846  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5847}
5848
5849static const char* script_resource_name = "ExceptionInNativeScript.js";
5850static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5851                                                v8::Handle<Value>) {
5852  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5853  CHECK(!name_val.IsEmpty() && name_val->IsString());
5854  v8::String::AsciiValue name(message->GetScriptResourceName());
5855  CHECK_EQ(script_resource_name, *name);
5856  CHECK_EQ(3, message->GetLineNumber());
5857  v8::String::AsciiValue source_line(message->GetSourceLine());
5858  CHECK_EQ("  new o.foo();", *source_line);
5859}
5860
5861TEST(ExceptionInNativeScript) {
5862  v8::HandleScope scope;
5863  LocalContext env;
5864  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5865
5866  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5867  v8::Local<v8::Object> global = env->Global();
5868  global->Set(v8_str("trouble"), fun->GetFunction());
5869
5870  Script::Compile(v8_str("function trouble() {\n"
5871                         "  var o = {};\n"
5872                         "  new o.foo();\n"
5873                         "};"), v8::String::New(script_resource_name))->Run();
5874  Local<Value> trouble = global->Get(v8_str("trouble"));
5875  CHECK(trouble->IsFunction());
5876  Function::Cast(*trouble)->Call(global, 0, NULL);
5877  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5878}
5879
5880
5881TEST(CompilationErrorUsingTryCatchHandler) {
5882  v8::HandleScope scope;
5883  LocalContext env;
5884  v8::TryCatch try_catch;
5885  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5886  CHECK_NE(NULL, *try_catch.Exception());
5887  CHECK(try_catch.HasCaught());
5888}
5889
5890
5891TEST(TryCatchFinallyUsingTryCatchHandler) {
5892  v8::HandleScope scope;
5893  LocalContext env;
5894  v8::TryCatch try_catch;
5895  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5896  CHECK(!try_catch.HasCaught());
5897  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5898  CHECK(try_catch.HasCaught());
5899  try_catch.Reset();
5900  Script::Compile(v8_str("(function() {"
5901                         "try { throw ''; } finally { return; }"
5902                         "})()"))->Run();
5903  CHECK(!try_catch.HasCaught());
5904  Script::Compile(v8_str("(function()"
5905                         "  { try { throw ''; } finally { throw 0; }"
5906                         "})()"))->Run();
5907  CHECK(try_catch.HasCaught());
5908}
5909
5910
5911// SecurityHandler can't be run twice
5912TEST(SecurityHandler) {
5913  v8::HandleScope scope0;
5914  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5915  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5916                                           IndexedSecurityTestCallback);
5917  // Create an environment
5918  v8::Persistent<Context> context0 =
5919    Context::New(NULL, global_template);
5920  context0->Enter();
5921
5922  v8::Handle<v8::Object> global0 = context0->Global();
5923  v8::Handle<Script> script0 = v8_compile("foo = 111");
5924  script0->Run();
5925  global0->Set(v8_str("0"), v8_num(999));
5926  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5927  CHECK_EQ(111, foo0->Int32Value());
5928  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5929  CHECK_EQ(999, z0->Int32Value());
5930
5931  // Create another environment, should fail security checks.
5932  v8::HandleScope scope1;
5933
5934  v8::Persistent<Context> context1 =
5935    Context::New(NULL, global_template);
5936  context1->Enter();
5937
5938  v8::Handle<v8::Object> global1 = context1->Global();
5939  global1->Set(v8_str("othercontext"), global0);
5940  // This set will fail the security check.
5941  v8::Handle<Script> script1 =
5942    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5943  script1->Run();
5944  // This read will pass the security check.
5945  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5946  CHECK_EQ(111, foo1->Int32Value());
5947  // This read will pass the security check.
5948  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5949  CHECK_EQ(999, z1->Int32Value());
5950
5951  // Create another environment, should pass security checks.
5952  { g_security_callback_result = true;  // allow security handler to pass.
5953    v8::HandleScope scope2;
5954    LocalContext context2;
5955    v8::Handle<v8::Object> global2 = context2->Global();
5956    global2->Set(v8_str("othercontext"), global0);
5957    v8::Handle<Script> script2 =
5958        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5959    script2->Run();
5960    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5961    CHECK_EQ(333, foo2->Int32Value());
5962    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5963    CHECK_EQ(888, z2->Int32Value());
5964  }
5965
5966  context1->Exit();
5967  context1.Dispose();
5968
5969  context0->Exit();
5970  context0.Dispose();
5971}
5972
5973
5974THREADED_TEST(SecurityChecks) {
5975  v8::HandleScope handle_scope;
5976  LocalContext env1;
5977  v8::Persistent<Context> env2 = Context::New();
5978
5979  Local<Value> foo = v8_str("foo");
5980  Local<Value> bar = v8_str("bar");
5981
5982  // Set to the same domain.
5983  env1->SetSecurityToken(foo);
5984
5985  // Create a function in env1.
5986  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5987  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5988  CHECK(spy->IsFunction());
5989
5990  // Create another function accessing global objects.
5991  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5992  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5993  CHECK(spy2->IsFunction());
5994
5995  // Switch to env2 in the same domain and invoke spy on env2.
5996  {
5997    env2->SetSecurityToken(foo);
5998    // Enter env2
5999    Context::Scope scope_env2(env2);
6000    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6001    CHECK(result->IsFunction());
6002  }
6003
6004  {
6005    env2->SetSecurityToken(bar);
6006    Context::Scope scope_env2(env2);
6007
6008    // Call cross_domain_call, it should throw an exception
6009    v8::TryCatch try_catch;
6010    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6011    CHECK(try_catch.HasCaught());
6012  }
6013
6014  env2.Dispose();
6015}
6016
6017
6018// Regression test case for issue 1183439.
6019THREADED_TEST(SecurityChecksForPrototypeChain) {
6020  v8::HandleScope scope;
6021  LocalContext current;
6022  v8::Persistent<Context> other = Context::New();
6023
6024  // Change context to be able to get to the Object function in the
6025  // other context without hitting the security checks.
6026  v8::Local<Value> other_object;
6027  { Context::Scope scope(other);
6028    other_object = other->Global()->Get(v8_str("Object"));
6029    other->Global()->Set(v8_num(42), v8_num(87));
6030  }
6031
6032  current->Global()->Set(v8_str("other"), other->Global());
6033  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6034
6035  // Make sure the security check fails here and we get an undefined
6036  // result instead of getting the Object function. Repeat in a loop
6037  // to make sure to exercise the IC code.
6038  v8::Local<Script> access_other0 = v8_compile("other.Object");
6039  v8::Local<Script> access_other1 = v8_compile("other[42]");
6040  for (int i = 0; i < 5; i++) {
6041    CHECK(!access_other0->Run()->Equals(other_object));
6042    CHECK(access_other0->Run()->IsUndefined());
6043    CHECK(!access_other1->Run()->Equals(v8_num(87)));
6044    CHECK(access_other1->Run()->IsUndefined());
6045  }
6046
6047  // Create an object that has 'other' in its prototype chain and make
6048  // sure we cannot access the Object function indirectly through
6049  // that. Repeat in a loop to make sure to exercise the IC code.
6050  v8_compile("function F() { };"
6051             "F.prototype = other;"
6052             "var f = new F();")->Run();
6053  v8::Local<Script> access_f0 = v8_compile("f.Object");
6054  v8::Local<Script> access_f1 = v8_compile("f[42]");
6055  for (int j = 0; j < 5; j++) {
6056    CHECK(!access_f0->Run()->Equals(other_object));
6057    CHECK(access_f0->Run()->IsUndefined());
6058    CHECK(!access_f1->Run()->Equals(v8_num(87)));
6059    CHECK(access_f1->Run()->IsUndefined());
6060  }
6061
6062  // Now it gets hairy: Set the prototype for the other global object
6063  // to be the current global object. The prototype chain for 'f' now
6064  // goes through 'other' but ends up in the current global object.
6065  { Context::Scope scope(other);
6066    other->Global()->Set(v8_str("__proto__"), current->Global());
6067  }
6068  // Set a named and an index property on the current global
6069  // object. To force the lookup to go through the other global object,
6070  // the properties must not exist in the other global object.
6071  current->Global()->Set(v8_str("foo"), v8_num(100));
6072  current->Global()->Set(v8_num(99), v8_num(101));
6073  // Try to read the properties from f and make sure that the access
6074  // gets stopped by the security checks on the other global object.
6075  Local<Script> access_f2 = v8_compile("f.foo");
6076  Local<Script> access_f3 = v8_compile("f[99]");
6077  for (int k = 0; k < 5; k++) {
6078    CHECK(!access_f2->Run()->Equals(v8_num(100)));
6079    CHECK(access_f2->Run()->IsUndefined());
6080    CHECK(!access_f3->Run()->Equals(v8_num(101)));
6081    CHECK(access_f3->Run()->IsUndefined());
6082  }
6083  other.Dispose();
6084}
6085
6086
6087THREADED_TEST(CrossDomainDelete) {
6088  v8::HandleScope handle_scope;
6089  LocalContext env1;
6090  v8::Persistent<Context> env2 = Context::New();
6091
6092  Local<Value> foo = v8_str("foo");
6093  Local<Value> bar = v8_str("bar");
6094
6095  // Set to the same domain.
6096  env1->SetSecurityToken(foo);
6097  env2->SetSecurityToken(foo);
6098
6099  env1->Global()->Set(v8_str("prop"), v8_num(3));
6100  env2->Global()->Set(v8_str("env1"), env1->Global());
6101
6102  // Change env2 to a different domain and delete env1.prop.
6103  env2->SetSecurityToken(bar);
6104  {
6105    Context::Scope scope_env2(env2);
6106    Local<Value> result =
6107        Script::Compile(v8_str("delete env1.prop"))->Run();
6108    CHECK(result->IsFalse());
6109  }
6110
6111  // Check that env1.prop still exists.
6112  Local<Value> v = env1->Global()->Get(v8_str("prop"));
6113  CHECK(v->IsNumber());
6114  CHECK_EQ(3, v->Int32Value());
6115
6116  env2.Dispose();
6117}
6118
6119
6120THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6121  v8::HandleScope handle_scope;
6122  LocalContext env1;
6123  v8::Persistent<Context> env2 = Context::New();
6124
6125  Local<Value> foo = v8_str("foo");
6126  Local<Value> bar = v8_str("bar");
6127
6128  // Set to the same domain.
6129  env1->SetSecurityToken(foo);
6130  env2->SetSecurityToken(foo);
6131
6132  env1->Global()->Set(v8_str("prop"), v8_num(3));
6133  env2->Global()->Set(v8_str("env1"), env1->Global());
6134
6135  // env1.prop is enumerable in env2.
6136  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6137  {
6138    Context::Scope scope_env2(env2);
6139    Local<Value> result = Script::Compile(test)->Run();
6140    CHECK(result->IsTrue());
6141  }
6142
6143  // Change env2 to a different domain and test again.
6144  env2->SetSecurityToken(bar);
6145  {
6146    Context::Scope scope_env2(env2);
6147    Local<Value> result = Script::Compile(test)->Run();
6148    CHECK(result->IsFalse());
6149  }
6150
6151  env2.Dispose();
6152}
6153
6154
6155THREADED_TEST(CrossDomainForIn) {
6156  v8::HandleScope handle_scope;
6157  LocalContext env1;
6158  v8::Persistent<Context> env2 = Context::New();
6159
6160  Local<Value> foo = v8_str("foo");
6161  Local<Value> bar = v8_str("bar");
6162
6163  // Set to the same domain.
6164  env1->SetSecurityToken(foo);
6165  env2->SetSecurityToken(foo);
6166
6167  env1->Global()->Set(v8_str("prop"), v8_num(3));
6168  env2->Global()->Set(v8_str("env1"), env1->Global());
6169
6170  // Change env2 to a different domain and set env1's global object
6171  // as the __proto__ of an object in env2 and enumerate properties
6172  // in for-in. It shouldn't enumerate properties on env1's global
6173  // object.
6174  env2->SetSecurityToken(bar);
6175  {
6176    Context::Scope scope_env2(env2);
6177    Local<Value> result =
6178        CompileRun("(function(){var obj = {'__proto__':env1};"
6179                   "for (var p in obj)"
6180                   "   if (p == 'prop') return false;"
6181                   "return true;})()");
6182    CHECK(result->IsTrue());
6183  }
6184  env2.Dispose();
6185}
6186
6187
6188TEST(ContextDetachGlobal) {
6189  v8::HandleScope handle_scope;
6190  LocalContext env1;
6191  v8::Persistent<Context> env2 = Context::New();
6192
6193  Local<v8::Object> global1 = env1->Global();
6194
6195  Local<Value> foo = v8_str("foo");
6196
6197  // Set to the same domain.
6198  env1->SetSecurityToken(foo);
6199  env2->SetSecurityToken(foo);
6200
6201  // Enter env2
6202  env2->Enter();
6203
6204  // Create a function in env2 and add a reference to it in env1.
6205  Local<v8::Object> global2 = env2->Global();
6206  global2->Set(v8_str("prop"), v8::Integer::New(1));
6207  CompileRun("function getProp() {return prop;}");
6208
6209  env1->Global()->Set(v8_str("getProp"),
6210                      global2->Get(v8_str("getProp")));
6211
6212  // Detach env2's global, and reuse the global object of env2
6213  env2->Exit();
6214  env2->DetachGlobal();
6215  // env2 has a new global object.
6216  CHECK(!env2->Global()->Equals(global2));
6217
6218  v8::Persistent<Context> env3 =
6219      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6220  env3->SetSecurityToken(v8_str("bar"));
6221  env3->Enter();
6222
6223  Local<v8::Object> global3 = env3->Global();
6224  CHECK_EQ(global2, global3);
6225  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6226  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6227  global3->Set(v8_str("prop"), v8::Integer::New(-1));
6228  global3->Set(v8_str("prop2"), v8::Integer::New(2));
6229  env3->Exit();
6230
6231  // Call getProp in env1, and it should return the value 1
6232  {
6233    Local<Value> get_prop = global1->Get(v8_str("getProp"));
6234    CHECK(get_prop->IsFunction());
6235    v8::TryCatch try_catch;
6236    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6237    CHECK(!try_catch.HasCaught());
6238    CHECK_EQ(1, r->Int32Value());
6239  }
6240
6241  // Check that env3 is not accessible from env1
6242  {
6243    Local<Value> r = global3->Get(v8_str("prop2"));
6244    CHECK(r->IsUndefined());
6245  }
6246
6247  env2.Dispose();
6248  env3.Dispose();
6249}
6250
6251
6252TEST(DetachAndReattachGlobal) {
6253  v8::HandleScope scope;
6254  LocalContext env1;
6255
6256  // Create second environment.
6257  v8::Persistent<Context> env2 = Context::New();
6258
6259  Local<Value> foo = v8_str("foo");
6260
6261  // Set same security token for env1 and env2.
6262  env1->SetSecurityToken(foo);
6263  env2->SetSecurityToken(foo);
6264
6265  // Create a property on the global object in env2.
6266  {
6267    v8::Context::Scope scope(env2);
6268    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6269  }
6270
6271  // Create a reference to env2 global from env1 global.
6272  env1->Global()->Set(v8_str("other"), env2->Global());
6273
6274  // Check that we have access to other.p in env2 from env1.
6275  Local<Value> result = CompileRun("other.p");
6276  CHECK(result->IsInt32());
6277  CHECK_EQ(42, result->Int32Value());
6278
6279  // Hold on to global from env2 and detach global from env2.
6280  Local<v8::Object> global2 = env2->Global();
6281  env2->DetachGlobal();
6282
6283  // Check that the global has been detached. No other.p property can
6284  // be found.
6285  result = CompileRun("other.p");
6286  CHECK(result->IsUndefined());
6287
6288  // Reuse global2 for env3.
6289  v8::Persistent<Context> env3 =
6290      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6291  CHECK_EQ(global2, env3->Global());
6292
6293  // Start by using the same security token for env3 as for env1 and env2.
6294  env3->SetSecurityToken(foo);
6295
6296  // Create a property on the global object in env3.
6297  {
6298    v8::Context::Scope scope(env3);
6299    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6300  }
6301
6302  // Check that other.p is now the property in env3 and that we have access.
6303  result = CompileRun("other.p");
6304  CHECK(result->IsInt32());
6305  CHECK_EQ(24, result->Int32Value());
6306
6307  // Change security token for env3 to something different from env1 and env2.
6308  env3->SetSecurityToken(v8_str("bar"));
6309
6310  // Check that we do not have access to other.p in env1. |other| is now
6311  // the global object for env3 which has a different security token,
6312  // so access should be blocked.
6313  result = CompileRun("other.p");
6314  CHECK(result->IsUndefined());
6315
6316  // Detach the global for env3 and reattach it to env2.
6317  env3->DetachGlobal();
6318  env2->ReattachGlobal(global2);
6319
6320  // Check that we have access to other.p again in env1.  |other| is now
6321  // the global object for env2 which has the same security token as env1.
6322  result = CompileRun("other.p");
6323  CHECK(result->IsInt32());
6324  CHECK_EQ(42, result->Int32Value());
6325
6326  env2.Dispose();
6327  env3.Dispose();
6328}
6329
6330
6331static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6332static bool NamedAccessBlocker(Local<v8::Object> global,
6333                               Local<Value> name,
6334                               v8::AccessType type,
6335                               Local<Value> data) {
6336  return Context::GetCurrent()->Global()->Equals(global) ||
6337      allowed_access_type[type];
6338}
6339
6340
6341static bool IndexedAccessBlocker(Local<v8::Object> global,
6342                                 uint32_t key,
6343                                 v8::AccessType type,
6344                                 Local<Value> data) {
6345  return Context::GetCurrent()->Global()->Equals(global) ||
6346      allowed_access_type[type];
6347}
6348
6349
6350static int g_echo_value = -1;
6351static v8::Handle<Value> EchoGetter(Local<String> name,
6352                                    const AccessorInfo& info) {
6353  return v8_num(g_echo_value);
6354}
6355
6356
6357static void EchoSetter(Local<String> name,
6358                       Local<Value> value,
6359                       const AccessorInfo&) {
6360  if (value->IsNumber())
6361    g_echo_value = value->Int32Value();
6362}
6363
6364
6365static v8::Handle<Value> UnreachableGetter(Local<String> name,
6366                                           const AccessorInfo& info) {
6367  CHECK(false);  // This function should not be called..
6368  return v8::Undefined();
6369}
6370
6371
6372static void UnreachableSetter(Local<String>, Local<Value>,
6373                              const AccessorInfo&) {
6374  CHECK(false);  // This function should nto be called.
6375}
6376
6377
6378TEST(AccessControl) {
6379  v8::HandleScope handle_scope;
6380  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6381
6382  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6383                                           IndexedAccessBlocker);
6384
6385  // Add an accessor accessible by cross-domain JS code.
6386  global_template->SetAccessor(
6387      v8_str("accessible_prop"),
6388      EchoGetter, EchoSetter,
6389      v8::Handle<Value>(),
6390      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6391
6392  // Add an accessor that is not accessible by cross-domain JS code.
6393  global_template->SetAccessor(v8_str("blocked_prop"),
6394                               UnreachableGetter, UnreachableSetter,
6395                               v8::Handle<Value>(),
6396                               v8::DEFAULT);
6397
6398  // Create an environment
6399  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6400  context0->Enter();
6401
6402  v8::Handle<v8::Object> global0 = context0->Global();
6403
6404  // Define a property with JS getter and setter.
6405  CompileRun(
6406      "function getter() { return 'getter'; };\n"
6407      "function setter() { return 'setter'; }\n"
6408      "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6409
6410  Local<Value> getter = global0->Get(v8_str("getter"));
6411  Local<Value> setter = global0->Get(v8_str("setter"));
6412
6413  // And define normal element.
6414  global0->Set(239, v8_str("239"));
6415
6416  // Define an element with JS getter and setter.
6417  CompileRun(
6418      "function el_getter() { return 'el_getter'; };\n"
6419      "function el_setter() { return 'el_setter'; };\n"
6420      "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6421
6422  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6423  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6424
6425  v8::HandleScope scope1;
6426
6427  v8::Persistent<Context> context1 = Context::New();
6428  context1->Enter();
6429
6430  v8::Handle<v8::Object> global1 = context1->Global();
6431  global1->Set(v8_str("other"), global0);
6432
6433  // Access blocked property.
6434  CompileRun("other.blocked_prop = 1");
6435
6436  ExpectUndefined("other.blocked_prop");
6437  ExpectUndefined(
6438      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6439  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6440
6441  // Enable ACCESS_HAS
6442  allowed_access_type[v8::ACCESS_HAS] = true;
6443  ExpectUndefined("other.blocked_prop");
6444  // ... and now we can get the descriptor...
6445  ExpectUndefined(
6446      "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6447  // ... and enumerate the property.
6448  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6449  allowed_access_type[v8::ACCESS_HAS] = false;
6450
6451  // Access blocked element.
6452  CompileRun("other[239] = 1");
6453
6454  ExpectUndefined("other[239]");
6455  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6456  ExpectFalse("propertyIsEnumerable.call(other, '239')");
6457
6458  // Enable ACCESS_HAS
6459  allowed_access_type[v8::ACCESS_HAS] = true;
6460  ExpectUndefined("other[239]");
6461  // ... and now we can get the descriptor...
6462  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6463  // ... and enumerate the property.
6464  ExpectTrue("propertyIsEnumerable.call(other, '239')");
6465  allowed_access_type[v8::ACCESS_HAS] = false;
6466
6467  // Access a property with JS accessor.
6468  CompileRun("other.js_accessor_p = 2");
6469
6470  ExpectUndefined("other.js_accessor_p");
6471  ExpectUndefined(
6472      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6473
6474  // Enable ACCESS_HAS.
6475  allowed_access_type[v8::ACCESS_HAS] = true;
6476  ExpectUndefined("other.js_accessor_p");
6477  ExpectUndefined(
6478      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6479  ExpectUndefined(
6480      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6481  ExpectUndefined(
6482      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6483  allowed_access_type[v8::ACCESS_HAS] = false;
6484
6485  // Enable both ACCESS_HAS and ACCESS_GET.
6486  allowed_access_type[v8::ACCESS_HAS] = true;
6487  allowed_access_type[v8::ACCESS_GET] = true;
6488
6489  ExpectString("other.js_accessor_p", "getter");
6490  ExpectObject(
6491      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6492  ExpectUndefined(
6493      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6494  ExpectUndefined(
6495      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6496
6497  allowed_access_type[v8::ACCESS_GET] = false;
6498  allowed_access_type[v8::ACCESS_HAS] = false;
6499
6500  // Enable both ACCESS_HAS and ACCESS_SET.
6501  allowed_access_type[v8::ACCESS_HAS] = true;
6502  allowed_access_type[v8::ACCESS_SET] = true;
6503
6504  ExpectUndefined("other.js_accessor_p");
6505  ExpectUndefined(
6506      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6507  ExpectObject(
6508      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6509  ExpectUndefined(
6510      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6511
6512  allowed_access_type[v8::ACCESS_SET] = false;
6513  allowed_access_type[v8::ACCESS_HAS] = false;
6514
6515  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6516  allowed_access_type[v8::ACCESS_HAS] = true;
6517  allowed_access_type[v8::ACCESS_GET] = true;
6518  allowed_access_type[v8::ACCESS_SET] = true;
6519
6520  ExpectString("other.js_accessor_p", "getter");
6521  ExpectObject(
6522      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6523  ExpectObject(
6524      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6525  ExpectUndefined(
6526      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6527
6528  allowed_access_type[v8::ACCESS_SET] = false;
6529  allowed_access_type[v8::ACCESS_GET] = false;
6530  allowed_access_type[v8::ACCESS_HAS] = false;
6531
6532  // Access an element with JS accessor.
6533  CompileRun("other[42] = 2");
6534
6535  ExpectUndefined("other[42]");
6536  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6537
6538  // Enable ACCESS_HAS.
6539  allowed_access_type[v8::ACCESS_HAS] = true;
6540  ExpectUndefined("other[42]");
6541  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6542  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6543  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6544  allowed_access_type[v8::ACCESS_HAS] = false;
6545
6546  // Enable both ACCESS_HAS and ACCESS_GET.
6547  allowed_access_type[v8::ACCESS_HAS] = true;
6548  allowed_access_type[v8::ACCESS_GET] = true;
6549
6550  ExpectString("other[42]", "el_getter");
6551  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6552  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6553  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6554
6555  allowed_access_type[v8::ACCESS_GET] = false;
6556  allowed_access_type[v8::ACCESS_HAS] = false;
6557
6558  // Enable both ACCESS_HAS and ACCESS_SET.
6559  allowed_access_type[v8::ACCESS_HAS] = true;
6560  allowed_access_type[v8::ACCESS_SET] = true;
6561
6562  ExpectUndefined("other[42]");
6563  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6564  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6565  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6566
6567  allowed_access_type[v8::ACCESS_SET] = false;
6568  allowed_access_type[v8::ACCESS_HAS] = false;
6569
6570  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6571  allowed_access_type[v8::ACCESS_HAS] = true;
6572  allowed_access_type[v8::ACCESS_GET] = true;
6573  allowed_access_type[v8::ACCESS_SET] = true;
6574
6575  ExpectString("other[42]", "el_getter");
6576  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6577  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6578  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6579
6580  allowed_access_type[v8::ACCESS_SET] = false;
6581  allowed_access_type[v8::ACCESS_GET] = false;
6582  allowed_access_type[v8::ACCESS_HAS] = false;
6583
6584  v8::Handle<Value> value;
6585
6586  // Access accessible property
6587  value = CompileRun("other.accessible_prop = 3");
6588  CHECK(value->IsNumber());
6589  CHECK_EQ(3, value->Int32Value());
6590  CHECK_EQ(3, g_echo_value);
6591
6592  value = CompileRun("other.accessible_prop");
6593  CHECK(value->IsNumber());
6594  CHECK_EQ(3, value->Int32Value());
6595
6596  value = CompileRun(
6597      "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6598  CHECK(value->IsNumber());
6599  CHECK_EQ(3, value->Int32Value());
6600
6601  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
6602  CHECK(value->IsTrue());
6603
6604  // Enumeration doesn't enumerate accessors from inaccessible objects in
6605  // the prototype chain even if the accessors are in themselves accessible.
6606  value =
6607      CompileRun("(function(){var obj = {'__proto__':other};"
6608                 "for (var p in obj)"
6609                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
6610                 "     return false;"
6611                 "   }"
6612                 "return true;})()");
6613  CHECK(value->IsTrue());
6614
6615  context1->Exit();
6616  context0->Exit();
6617  context1.Dispose();
6618  context0.Dispose();
6619}
6620
6621
6622TEST(AccessControlES5) {
6623  v8::HandleScope handle_scope;
6624  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6625
6626  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6627                                           IndexedAccessBlocker);
6628
6629  // Add accessible accessor.
6630  global_template->SetAccessor(
6631      v8_str("accessible_prop"),
6632      EchoGetter, EchoSetter,
6633      v8::Handle<Value>(),
6634      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6635
6636
6637  // Add an accessor that is not accessible by cross-domain JS code.
6638  global_template->SetAccessor(v8_str("blocked_prop"),
6639                               UnreachableGetter, UnreachableSetter,
6640                               v8::Handle<Value>(),
6641                               v8::DEFAULT);
6642
6643  // Create an environment
6644  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6645  context0->Enter();
6646
6647  v8::Handle<v8::Object> global0 = context0->Global();
6648
6649  v8::Persistent<Context> context1 = Context::New();
6650  context1->Enter();
6651  v8::Handle<v8::Object> global1 = context1->Global();
6652  global1->Set(v8_str("other"), global0);
6653
6654  // Regression test for issue 1154.
6655  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6656
6657  ExpectUndefined("other.blocked_prop");
6658
6659  // Regression test for issue 1027.
6660  CompileRun("Object.defineProperty(\n"
6661             "  other, 'blocked_prop', {configurable: false})");
6662  ExpectUndefined("other.blocked_prop");
6663  ExpectUndefined(
6664      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6665
6666  // Regression test for issue 1171.
6667  ExpectTrue("Object.isExtensible(other)");
6668  CompileRun("Object.preventExtensions(other)");
6669  ExpectTrue("Object.isExtensible(other)");
6670
6671  // Object.seal and Object.freeze.
6672  CompileRun("Object.freeze(other)");
6673  ExpectTrue("Object.isExtensible(other)");
6674
6675  CompileRun("Object.seal(other)");
6676  ExpectTrue("Object.isExtensible(other)");
6677
6678  // Regression test for issue 1250.
6679  // Make sure that we can set the accessible accessors value using normal
6680  // assignment.
6681  CompileRun("other.accessible_prop = 42");
6682  CHECK_EQ(42, g_echo_value);
6683
6684  v8::Handle<Value> value;
6685  // We follow Safari in ignoring assignments to host object accessors.
6686  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6687  value = CompileRun("other.accessible_prop == 42");
6688  CHECK(value->IsTrue());
6689}
6690
6691
6692static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6693                                            Local<Value> name,
6694                                            v8::AccessType type,
6695                                            Local<Value> data) {
6696  return false;
6697}
6698
6699
6700static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6701                                              uint32_t key,
6702                                              v8::AccessType type,
6703                                              Local<Value> data) {
6704  return false;
6705}
6706
6707
6708THREADED_TEST(AccessControlGetOwnPropertyNames) {
6709  v8::HandleScope handle_scope;
6710  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6711
6712  obj_template->Set(v8_str("x"), v8::Integer::New(42));
6713  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6714                                        GetOwnPropertyNamesIndexedBlocker);
6715
6716  // Create an environment
6717  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6718  context0->Enter();
6719
6720  v8::Handle<v8::Object> global0 = context0->Global();
6721
6722  v8::HandleScope scope1;
6723
6724  v8::Persistent<Context> context1 = Context::New();
6725  context1->Enter();
6726
6727  v8::Handle<v8::Object> global1 = context1->Global();
6728  global1->Set(v8_str("other"), global0);
6729  global1->Set(v8_str("object"), obj_template->NewInstance());
6730
6731  v8::Handle<Value> value;
6732
6733  // Attempt to get the property names of the other global object and
6734  // of an object that requires access checks.  Accessing the other
6735  // global object should be blocked by access checks on the global
6736  // proxy object.  Accessing the object that requires access checks
6737  // is blocked by the access checks on the object itself.
6738  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6739  CHECK(value->IsTrue());
6740
6741  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6742  CHECK(value->IsTrue());
6743
6744  context1->Exit();
6745  context0->Exit();
6746  context1.Dispose();
6747  context0.Dispose();
6748}
6749
6750
6751static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6752  v8::Handle<v8::Array> result = v8::Array::New(1);
6753  result->Set(0, v8_str("x"));
6754  return result;
6755}
6756
6757
6758THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6759  v8::HandleScope handle_scope;
6760  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6761
6762  obj_template->Set(v8_str("x"), v8::Integer::New(42));
6763  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6764                                        NamedPropertyEnumerator);
6765
6766  LocalContext context;
6767  v8::Handle<v8::Object> global = context->Global();
6768  global->Set(v8_str("object"), obj_template->NewInstance());
6769
6770  v8::Handle<Value> value =
6771      CompileRun("Object.getOwnPropertyNames(object).join(',')");
6772  CHECK_EQ(v8_str("x"), value);
6773}
6774
6775
6776static v8::Handle<Value> ConstTenGetter(Local<String> name,
6777                                        const AccessorInfo& info) {
6778  return v8_num(10);
6779}
6780
6781
6782THREADED_TEST(CrossDomainAccessors) {
6783  v8::HandleScope handle_scope;
6784
6785  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6786
6787  v8::Handle<v8::ObjectTemplate> global_template =
6788      func_template->InstanceTemplate();
6789
6790  v8::Handle<v8::ObjectTemplate> proto_template =
6791      func_template->PrototypeTemplate();
6792
6793  // Add an accessor to proto that's accessible by cross-domain JS code.
6794  proto_template->SetAccessor(v8_str("accessible"),
6795                              ConstTenGetter, 0,
6796                              v8::Handle<Value>(),
6797                              v8::ALL_CAN_READ);
6798
6799  // Add an accessor that is not accessible by cross-domain JS code.
6800  global_template->SetAccessor(v8_str("unreachable"),
6801                               UnreachableGetter, 0,
6802                               v8::Handle<Value>(),
6803                               v8::DEFAULT);
6804
6805  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6806  context0->Enter();
6807
6808  Local<v8::Object> global = context0->Global();
6809  // Add a normal property that shadows 'accessible'
6810  global->Set(v8_str("accessible"), v8_num(11));
6811
6812  // Enter a new context.
6813  v8::HandleScope scope1;
6814  v8::Persistent<Context> context1 = Context::New();
6815  context1->Enter();
6816
6817  v8::Handle<v8::Object> global1 = context1->Global();
6818  global1->Set(v8_str("other"), global);
6819
6820  // Should return 10, instead of 11
6821  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6822  CHECK(value->IsNumber());
6823  CHECK_EQ(10, value->Int32Value());
6824
6825  value = v8_compile("other.unreachable")->Run();
6826  CHECK(value->IsUndefined());
6827
6828  context1->Exit();
6829  context0->Exit();
6830  context1.Dispose();
6831  context0.Dispose();
6832}
6833
6834
6835static int named_access_count = 0;
6836static int indexed_access_count = 0;
6837
6838static bool NamedAccessCounter(Local<v8::Object> global,
6839                               Local<Value> name,
6840                               v8::AccessType type,
6841                               Local<Value> data) {
6842  named_access_count++;
6843  return true;
6844}
6845
6846
6847static bool IndexedAccessCounter(Local<v8::Object> global,
6848                                 uint32_t key,
6849                                 v8::AccessType type,
6850                                 Local<Value> data) {
6851  indexed_access_count++;
6852  return true;
6853}
6854
6855
6856// This one is too easily disturbed by other tests.
6857TEST(AccessControlIC) {
6858  named_access_count = 0;
6859  indexed_access_count = 0;
6860
6861  v8::HandleScope handle_scope;
6862
6863  // Create an environment.
6864  v8::Persistent<Context> context0 = Context::New();
6865  context0->Enter();
6866
6867  // Create an object that requires access-check functions to be
6868  // called for cross-domain access.
6869  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6870  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6871                                           IndexedAccessCounter);
6872  Local<v8::Object> object = object_template->NewInstance();
6873
6874  v8::HandleScope scope1;
6875
6876  // Create another environment.
6877  v8::Persistent<Context> context1 = Context::New();
6878  context1->Enter();
6879
6880  // Make easy access to the object from the other environment.
6881  v8::Handle<v8::Object> global1 = context1->Global();
6882  global1->Set(v8_str("obj"), object);
6883
6884  v8::Handle<Value> value;
6885
6886  // Check that the named access-control function is called every time.
6887  CompileRun("function testProp(obj) {"
6888             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
6889             "  for (var j = 0; j < 10; j++) obj.prop;"
6890             "  return obj.prop"
6891             "}");
6892  value = CompileRun("testProp(obj)");
6893  CHECK(value->IsNumber());
6894  CHECK_EQ(1, value->Int32Value());
6895  CHECK_EQ(21, named_access_count);
6896
6897  // Check that the named access-control function is called every time.
6898  CompileRun("var p = 'prop';"
6899             "function testKeyed(obj) {"
6900             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
6901             "  for (var j = 0; j < 10; j++) obj[p];"
6902             "  return obj[p];"
6903             "}");
6904  // Use obj which requires access checks.  No inline caching is used
6905  // in that case.
6906  value = CompileRun("testKeyed(obj)");
6907  CHECK(value->IsNumber());
6908  CHECK_EQ(1, value->Int32Value());
6909  CHECK_EQ(42, named_access_count);
6910  // Force the inline caches into generic state and try again.
6911  CompileRun("testKeyed({ a: 0 })");
6912  CompileRun("testKeyed({ b: 0 })");
6913  value = CompileRun("testKeyed(obj)");
6914  CHECK(value->IsNumber());
6915  CHECK_EQ(1, value->Int32Value());
6916  CHECK_EQ(63, named_access_count);
6917
6918  // Check that the indexed access-control function is called every time.
6919  CompileRun("function testIndexed(obj) {"
6920             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
6921             "  for (var j = 0; j < 10; j++) obj[0];"
6922             "  return obj[0]"
6923             "}");
6924  value = CompileRun("testIndexed(obj)");
6925  CHECK(value->IsNumber());
6926  CHECK_EQ(1, value->Int32Value());
6927  CHECK_EQ(21, indexed_access_count);
6928  // Force the inline caches into generic state.
6929  CompileRun("testIndexed(new Array(1))");
6930  // Test that the indexed access check is called.
6931  value = CompileRun("testIndexed(obj)");
6932  CHECK(value->IsNumber());
6933  CHECK_EQ(1, value->Int32Value());
6934  CHECK_EQ(42, indexed_access_count);
6935
6936  // Check that the named access check is called when invoking
6937  // functions on an object that requires access checks.
6938  CompileRun("obj.f = function() {}");
6939  CompileRun("function testCallNormal(obj) {"
6940             "  for (var i = 0; i < 10; i++) obj.f();"
6941             "}");
6942  CompileRun("testCallNormal(obj)");
6943  CHECK_EQ(74, named_access_count);
6944
6945  // Force obj into slow case.
6946  value = CompileRun("delete obj.prop");
6947  CHECK(value->BooleanValue());
6948  // Force inline caches into dictionary probing mode.
6949  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6950  // Test that the named access check is called.
6951  value = CompileRun("testProp(obj);");
6952  CHECK(value->IsNumber());
6953  CHECK_EQ(1, value->Int32Value());
6954  CHECK_EQ(96, named_access_count);
6955
6956  // Force the call inline cache into dictionary probing mode.
6957  CompileRun("o.f = function() {}; testCallNormal(o)");
6958  // Test that the named access check is still called for each
6959  // invocation of the function.
6960  value = CompileRun("testCallNormal(obj)");
6961  CHECK_EQ(106, named_access_count);
6962
6963  context1->Exit();
6964  context0->Exit();
6965  context1.Dispose();
6966  context0.Dispose();
6967}
6968
6969
6970static bool NamedAccessFlatten(Local<v8::Object> global,
6971                               Local<Value> name,
6972                               v8::AccessType type,
6973                               Local<Value> data) {
6974  char buf[100];
6975  int len;
6976
6977  CHECK(name->IsString());
6978
6979  memset(buf, 0x1, sizeof(buf));
6980  len = name.As<String>()->WriteAscii(buf);
6981  CHECK_EQ(4, len);
6982
6983  uint16_t buf2[100];
6984
6985  memset(buf, 0x1, sizeof(buf));
6986  len = name.As<String>()->Write(buf2);
6987  CHECK_EQ(4, len);
6988
6989  return true;
6990}
6991
6992
6993static bool IndexedAccessFlatten(Local<v8::Object> global,
6994                                 uint32_t key,
6995                                 v8::AccessType type,
6996                                 Local<Value> data) {
6997  return true;
6998}
6999
7000
7001// Regression test.  In access checks, operations that may cause
7002// garbage collection are not allowed.  It used to be the case that
7003// using the Write operation on a string could cause a garbage
7004// collection due to flattening of the string.  This is no longer the
7005// case.
7006THREADED_TEST(AccessControlFlatten) {
7007  named_access_count = 0;
7008  indexed_access_count = 0;
7009
7010  v8::HandleScope handle_scope;
7011
7012  // Create an environment.
7013  v8::Persistent<Context> context0 = Context::New();
7014  context0->Enter();
7015
7016  // Create an object that requires access-check functions to be
7017  // called for cross-domain access.
7018  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7019  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7020                                           IndexedAccessFlatten);
7021  Local<v8::Object> object = object_template->NewInstance();
7022
7023  v8::HandleScope scope1;
7024
7025  // Create another environment.
7026  v8::Persistent<Context> context1 = Context::New();
7027  context1->Enter();
7028
7029  // Make easy access to the object from the other environment.
7030  v8::Handle<v8::Object> global1 = context1->Global();
7031  global1->Set(v8_str("obj"), object);
7032
7033  v8::Handle<Value> value;
7034
7035  value = v8_compile("var p = 'as' + 'df';")->Run();
7036  value = v8_compile("obj[p];")->Run();
7037
7038  context1->Exit();
7039  context0->Exit();
7040  context1.Dispose();
7041  context0.Dispose();
7042}
7043
7044
7045static v8::Handle<Value> AccessControlNamedGetter(
7046    Local<String>, const AccessorInfo&) {
7047  return v8::Integer::New(42);
7048}
7049
7050
7051static v8::Handle<Value> AccessControlNamedSetter(
7052    Local<String>, Local<Value> value, const AccessorInfo&) {
7053  return value;
7054}
7055
7056
7057static v8::Handle<Value> AccessControlIndexedGetter(
7058      uint32_t index,
7059      const AccessorInfo& info) {
7060  return v8_num(42);
7061}
7062
7063
7064static v8::Handle<Value> AccessControlIndexedSetter(
7065    uint32_t, Local<Value> value, const AccessorInfo&) {
7066  return value;
7067}
7068
7069
7070THREADED_TEST(AccessControlInterceptorIC) {
7071  named_access_count = 0;
7072  indexed_access_count = 0;
7073
7074  v8::HandleScope handle_scope;
7075
7076  // Create an environment.
7077  v8::Persistent<Context> context0 = Context::New();
7078  context0->Enter();
7079
7080  // Create an object that requires access-check functions to be
7081  // called for cross-domain access.  The object also has interceptors
7082  // interceptor.
7083  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7084  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7085                                           IndexedAccessCounter);
7086  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7087                                           AccessControlNamedSetter);
7088  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7089                                             AccessControlIndexedSetter);
7090  Local<v8::Object> object = object_template->NewInstance();
7091
7092  v8::HandleScope scope1;
7093
7094  // Create another environment.
7095  v8::Persistent<Context> context1 = Context::New();
7096  context1->Enter();
7097
7098  // Make easy access to the object from the other environment.
7099  v8::Handle<v8::Object> global1 = context1->Global();
7100  global1->Set(v8_str("obj"), object);
7101
7102  v8::Handle<Value> value;
7103
7104  // Check that the named access-control function is called every time
7105  // eventhough there is an interceptor on the object.
7106  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7107  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7108                     "obj.x")->Run();
7109  CHECK(value->IsNumber());
7110  CHECK_EQ(42, value->Int32Value());
7111  CHECK_EQ(21, named_access_count);
7112
7113  value = v8_compile("var p = 'x';")->Run();
7114  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7115  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7116                     "obj[p]")->Run();
7117  CHECK(value->IsNumber());
7118  CHECK_EQ(42, value->Int32Value());
7119  CHECK_EQ(42, named_access_count);
7120
7121  // Check that the indexed access-control function is called every
7122  // time eventhough there is an interceptor on the object.
7123  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7124  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7125                     "obj[0]")->Run();
7126  CHECK(value->IsNumber());
7127  CHECK_EQ(42, value->Int32Value());
7128  CHECK_EQ(21, indexed_access_count);
7129
7130  context1->Exit();
7131  context0->Exit();
7132  context1.Dispose();
7133  context0.Dispose();
7134}
7135
7136
7137THREADED_TEST(Version) {
7138  v8::V8::GetVersion();
7139}
7140
7141
7142static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7143  ApiTestFuzzer::Fuzz();
7144  return v8_num(12);
7145}
7146
7147
7148THREADED_TEST(InstanceProperties) {
7149  v8::HandleScope handle_scope;
7150  LocalContext context;
7151
7152  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7153  Local<ObjectTemplate> instance = t->InstanceTemplate();
7154
7155  instance->Set(v8_str("x"), v8_num(42));
7156  instance->Set(v8_str("f"),
7157                v8::FunctionTemplate::New(InstanceFunctionCallback));
7158
7159  Local<Value> o = t->GetFunction()->NewInstance();
7160
7161  context->Global()->Set(v8_str("i"), o);
7162  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7163  CHECK_EQ(42, value->Int32Value());
7164
7165  value = Script::Compile(v8_str("i.f()"))->Run();
7166  CHECK_EQ(12, value->Int32Value());
7167}
7168
7169
7170static v8::Handle<Value>
7171GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7172  ApiTestFuzzer::Fuzz();
7173  return v8::Handle<Value>();
7174}
7175
7176
7177THREADED_TEST(GlobalObjectInstanceProperties) {
7178  v8::HandleScope handle_scope;
7179
7180  Local<Value> global_object;
7181
7182  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7183  t->InstanceTemplate()->SetNamedPropertyHandler(
7184      GlobalObjectInstancePropertiesGet);
7185  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7186  instance_template->Set(v8_str("x"), v8_num(42));
7187  instance_template->Set(v8_str("f"),
7188                         v8::FunctionTemplate::New(InstanceFunctionCallback));
7189
7190  // The script to check how Crankshaft compiles missing global function
7191  // invocations.  function g is not defined and should throw on call.
7192  const char* script =
7193      "function wrapper(call) {"
7194      "  var x = 0, y = 1;"
7195      "  for (var i = 0; i < 1000; i++) {"
7196      "    x += i * 100;"
7197      "    y += i * 100;"
7198      "  }"
7199      "  if (call) g();"
7200      "}"
7201      "for (var i = 0; i < 17; i++) wrapper(false);"
7202      "var thrown = 0;"
7203      "try { wrapper(true); } catch (e) { thrown = 1; };"
7204      "thrown";
7205
7206  {
7207    LocalContext env(NULL, instance_template);
7208    // Hold on to the global object so it can be used again in another
7209    // environment initialization.
7210    global_object = env->Global();
7211
7212    Local<Value> value = Script::Compile(v8_str("x"))->Run();
7213    CHECK_EQ(42, value->Int32Value());
7214    value = Script::Compile(v8_str("f()"))->Run();
7215    CHECK_EQ(12, value->Int32Value());
7216    value = Script::Compile(v8_str(script))->Run();
7217    CHECK_EQ(1, value->Int32Value());
7218  }
7219
7220  {
7221    // Create new environment reusing the global object.
7222    LocalContext env(NULL, instance_template, global_object);
7223    Local<Value> value = Script::Compile(v8_str("x"))->Run();
7224    CHECK_EQ(42, value->Int32Value());
7225    value = Script::Compile(v8_str("f()"))->Run();
7226    CHECK_EQ(12, value->Int32Value());
7227    value = Script::Compile(v8_str(script))->Run();
7228    CHECK_EQ(1, value->Int32Value());
7229  }
7230}
7231
7232
7233THREADED_TEST(CallKnownGlobalReceiver) {
7234  v8::HandleScope handle_scope;
7235
7236  Local<Value> global_object;
7237
7238  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7239  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7240
7241  // The script to check that we leave global object not
7242  // global object proxy on stack when we deoptimize from inside
7243  // arguments evaluation.
7244  // To provoke error we need to both force deoptimization
7245  // from arguments evaluation and to force CallIC to take
7246  // CallIC_Miss code path that can't cope with global proxy.
7247  const char* script =
7248      "function bar(x, y) { try { } finally { } }"
7249      "function baz(x) { try { } finally { } }"
7250      "function bom(x) { try { } finally { } }"
7251      "function foo(x) { bar([x], bom(2)); }"
7252      "for (var i = 0; i < 10000; i++) foo(1);"
7253      "foo";
7254
7255  Local<Value> foo;
7256  {
7257    LocalContext env(NULL, instance_template);
7258    // Hold on to the global object so it can be used again in another
7259    // environment initialization.
7260    global_object = env->Global();
7261    foo = Script::Compile(v8_str(script))->Run();
7262  }
7263
7264  {
7265    // Create new environment reusing the global object.
7266    LocalContext env(NULL, instance_template, global_object);
7267    env->Global()->Set(v8_str("foo"), foo);
7268    Local<Value> value(Script::Compile(v8_str("foo()"))->Run());
7269  }
7270}
7271
7272
7273static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7274  ApiTestFuzzer::Fuzz();
7275  return v8_num(42);
7276}
7277
7278
7279static int shadow_y;
7280static int shadow_y_setter_call_count;
7281static int shadow_y_getter_call_count;
7282
7283
7284static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7285  shadow_y_setter_call_count++;
7286  shadow_y = 42;
7287}
7288
7289
7290static v8::Handle<Value> ShadowYGetter(Local<String> name,
7291                                       const AccessorInfo& info) {
7292  ApiTestFuzzer::Fuzz();
7293  shadow_y_getter_call_count++;
7294  return v8_num(shadow_y);
7295}
7296
7297
7298static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7299                                          const AccessorInfo& info) {
7300  return v8::Handle<Value>();
7301}
7302
7303
7304static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7305                                        const AccessorInfo&) {
7306  return v8::Handle<Value>();
7307}
7308
7309
7310THREADED_TEST(ShadowObject) {
7311  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7312  v8::HandleScope handle_scope;
7313
7314  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7315  LocalContext context(NULL, global_template);
7316
7317  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7318  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7319  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7320  Local<ObjectTemplate> proto = t->PrototypeTemplate();
7321  Local<ObjectTemplate> instance = t->InstanceTemplate();
7322
7323  // Only allow calls of f on instances of t.
7324  Local<v8::Signature> signature = v8::Signature::New(t);
7325  proto->Set(v8_str("f"),
7326             v8::FunctionTemplate::New(ShadowFunctionCallback,
7327                                       Local<Value>(),
7328                                       signature));
7329  proto->Set(v8_str("x"), v8_num(12));
7330
7331  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7332
7333  Local<Value> o = t->GetFunction()->NewInstance();
7334  context->Global()->Set(v8_str("__proto__"), o);
7335
7336  Local<Value> value =
7337      Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7338  CHECK(value->IsBoolean());
7339  CHECK(!value->BooleanValue());
7340
7341  value = Script::Compile(v8_str("x"))->Run();
7342  CHECK_EQ(12, value->Int32Value());
7343
7344  value = Script::Compile(v8_str("f()"))->Run();
7345  CHECK_EQ(42, value->Int32Value());
7346
7347  Script::Compile(v8_str("y = 42"))->Run();
7348  CHECK_EQ(1, shadow_y_setter_call_count);
7349  value = Script::Compile(v8_str("y"))->Run();
7350  CHECK_EQ(1, shadow_y_getter_call_count);
7351  CHECK_EQ(42, value->Int32Value());
7352}
7353
7354
7355THREADED_TEST(HiddenPrototype) {
7356  v8::HandleScope handle_scope;
7357  LocalContext context;
7358
7359  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7360  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7361  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7362  t1->SetHiddenPrototype(true);
7363  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7364  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7365  t2->SetHiddenPrototype(true);
7366  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7367  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7368  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7369
7370  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7371  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7372  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7373  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7374
7375  // Setting the prototype on an object skips hidden prototypes.
7376  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7377  o0->Set(v8_str("__proto__"), o1);
7378  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7379  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7380  o0->Set(v8_str("__proto__"), o2);
7381  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7382  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7383  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7384  o0->Set(v8_str("__proto__"), o3);
7385  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7386  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7387  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7388  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7389
7390  // Getting the prototype of o0 should get the first visible one
7391  // which is o3.  Therefore, z should not be defined on the prototype
7392  // object.
7393  Local<Value> proto = o0->Get(v8_str("__proto__"));
7394  CHECK(proto->IsObject());
7395  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7396}
7397
7398
7399THREADED_TEST(SetPrototype) {
7400  v8::HandleScope handle_scope;
7401  LocalContext context;
7402
7403  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7404  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7405  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7406  t1->SetHiddenPrototype(true);
7407  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7408  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7409  t2->SetHiddenPrototype(true);
7410  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7411  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7412  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7413
7414  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7415  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7416  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7417  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7418
7419  // Setting the prototype on an object does not skip hidden prototypes.
7420  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7421  CHECK(o0->SetPrototype(o1));
7422  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7423  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7424  CHECK(o1->SetPrototype(o2));
7425  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7426  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7427  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7428  CHECK(o2->SetPrototype(o3));
7429  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7430  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7431  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7432  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7433
7434  // Getting the prototype of o0 should get the first visible one
7435  // which is o3.  Therefore, z should not be defined on the prototype
7436  // object.
7437  Local<Value> proto = o0->Get(v8_str("__proto__"));
7438  CHECK(proto->IsObject());
7439  CHECK_EQ(proto.As<v8::Object>(), o3);
7440
7441  // However, Object::GetPrototype ignores hidden prototype.
7442  Local<Value> proto0 = o0->GetPrototype();
7443  CHECK(proto0->IsObject());
7444  CHECK_EQ(proto0.As<v8::Object>(), o1);
7445
7446  Local<Value> proto1 = o1->GetPrototype();
7447  CHECK(proto1->IsObject());
7448  CHECK_EQ(proto1.As<v8::Object>(), o2);
7449
7450  Local<Value> proto2 = o2->GetPrototype();
7451  CHECK(proto2->IsObject());
7452  CHECK_EQ(proto2.As<v8::Object>(), o3);
7453}
7454
7455
7456// Getting property names of an object with a prototype chain that
7457// triggers dictionary elements in GetLocalPropertyNames() shouldn't
7458// crash the runtime.
7459THREADED_TEST(Regress91517) {
7460  i::FLAG_allow_natives_syntax = true;
7461  v8::HandleScope handle_scope;
7462  LocalContext context;
7463
7464  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7465  t1->SetHiddenPrototype(true);
7466  t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7467  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7468  t2->SetHiddenPrototype(true);
7469  t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7470  t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7471  t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7472  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7473  t3->SetHiddenPrototype(true);
7474  t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
7475  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7476  t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
7477
7478  // Force dictionary-based properties.
7479  i::ScopedVector<char> name_buf(1024);
7480  for (int i = 1; i <= 1000; i++) {
7481    i::OS::SNPrintF(name_buf, "sdf%d", i);
7482    t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
7483  }
7484
7485  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7486  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7487  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7488  Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
7489
7490  // Create prototype chain of hidden prototypes.
7491  CHECK(o4->SetPrototype(o3));
7492  CHECK(o3->SetPrototype(o2));
7493  CHECK(o2->SetPrototype(o1));
7494
7495  // Call the runtime version of GetLocalPropertyNames() on the natively
7496  // created object through JavaScript.
7497  context->Global()->Set(v8_str("obj"), o4);
7498  CompileRun("var names = %GetLocalPropertyNames(obj);");
7499
7500  ExpectInt32("names.length", 1006);
7501  ExpectTrue("names.indexOf(\"baz\") >= 0");
7502  ExpectTrue("names.indexOf(\"boo\") >= 0");
7503  ExpectTrue("names.indexOf(\"foo\") >= 0");
7504  ExpectTrue("names.indexOf(\"fuz1\") >= 0");
7505  ExpectTrue("names.indexOf(\"fuz2\") >= 0");
7506  ExpectFalse("names[1005] == undefined");
7507}
7508
7509
7510THREADED_TEST(FunctionReadOnlyPrototype) {
7511  v8::HandleScope handle_scope;
7512  LocalContext context;
7513
7514  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7515  t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7516  t1->ReadOnlyPrototype();
7517  context->Global()->Set(v8_str("func1"), t1->GetFunction());
7518  // Configured value of ReadOnly flag.
7519  CHECK(CompileRun(
7520      "(function() {"
7521      "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7522      "  return (descriptor['writable'] == false);"
7523      "})()")->BooleanValue());
7524  CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7525  CHECK_EQ(42,
7526           CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
7527
7528  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7529  t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7530  context->Global()->Set(v8_str("func2"), t2->GetFunction());
7531  // Default value of ReadOnly flag.
7532  CHECK(CompileRun(
7533      "(function() {"
7534      "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7535      "  return (descriptor['writable'] == true);"
7536      "})()")->BooleanValue());
7537  CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
7538}
7539
7540
7541THREADED_TEST(SetPrototypeThrows) {
7542  v8::HandleScope handle_scope;
7543  LocalContext context;
7544
7545  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7546
7547  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7548  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7549
7550  CHECK(o0->SetPrototype(o1));
7551  // If setting the prototype leads to the cycle, SetPrototype should
7552  // return false and keep VM in sane state.
7553  v8::TryCatch try_catch;
7554  CHECK(!o1->SetPrototype(o0));
7555  CHECK(!try_catch.HasCaught());
7556  ASSERT(!i::Isolate::Current()->has_pending_exception());
7557
7558  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7559}
7560
7561
7562THREADED_TEST(GetterSetterExceptions) {
7563  v8::HandleScope handle_scope;
7564  LocalContext context;
7565  CompileRun(
7566    "function Foo() { };"
7567    "function Throw() { throw 5; };"
7568    "var x = { };"
7569    "x.__defineSetter__('set', Throw);"
7570    "x.__defineGetter__('get', Throw);");
7571  Local<v8::Object> x =
7572      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7573  v8::TryCatch try_catch;
7574  x->Set(v8_str("set"), v8::Integer::New(8));
7575  x->Get(v8_str("get"));
7576  x->Set(v8_str("set"), v8::Integer::New(8));
7577  x->Get(v8_str("get"));
7578  x->Set(v8_str("set"), v8::Integer::New(8));
7579  x->Get(v8_str("get"));
7580  x->Set(v8_str("set"), v8::Integer::New(8));
7581  x->Get(v8_str("get"));
7582}
7583
7584
7585THREADED_TEST(Constructor) {
7586  v8::HandleScope handle_scope;
7587  LocalContext context;
7588  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7589  templ->SetClassName(v8_str("Fun"));
7590  Local<Function> cons = templ->GetFunction();
7591  context->Global()->Set(v8_str("Fun"), cons);
7592  Local<v8::Object> inst = cons->NewInstance();
7593  i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
7594  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7595  CHECK(value->BooleanValue());
7596}
7597
7598
7599static Handle<Value> ConstructorCallback(const Arguments& args) {
7600  ApiTestFuzzer::Fuzz();
7601  Local<Object> This;
7602
7603  if (args.IsConstructCall()) {
7604    Local<Object> Holder = args.Holder();
7605    This = Object::New();
7606    Local<Value> proto = Holder->GetPrototype();
7607    if (proto->IsObject()) {
7608      This->SetPrototype(proto);
7609    }
7610  } else {
7611    This = args.This();
7612  }
7613
7614  This->Set(v8_str("a"), args[0]);
7615  return This;
7616}
7617
7618
7619static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7620  ApiTestFuzzer::Fuzz();
7621  return args[0];
7622}
7623
7624
7625THREADED_TEST(ConstructorForObject) {
7626  v8::HandleScope handle_scope;
7627  LocalContext context;
7628
7629  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7630    instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7631    Local<Object> instance = instance_template->NewInstance();
7632    context->Global()->Set(v8_str("obj"), instance);
7633    v8::TryCatch try_catch;
7634    Local<Value> value;
7635    CHECK(!try_catch.HasCaught());
7636
7637    // Call the Object's constructor with a 32-bit signed integer.
7638    value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7639    CHECK(!try_catch.HasCaught());
7640    CHECK(value->IsInt32());
7641    CHECK_EQ(28, value->Int32Value());
7642
7643    Local<Value> args1[] = { v8_num(28) };
7644    Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7645    CHECK(value_obj1->IsObject());
7646    Local<Object> object1 = Local<Object>::Cast(value_obj1);
7647    value = object1->Get(v8_str("a"));
7648    CHECK(value->IsInt32());
7649    CHECK(!try_catch.HasCaught());
7650    CHECK_EQ(28, value->Int32Value());
7651
7652    // Call the Object's constructor with a String.
7653    value = CompileRun(
7654        "(function() { var o = new obj('tipli'); return o.a; })()");
7655    CHECK(!try_catch.HasCaught());
7656    CHECK(value->IsString());
7657    String::AsciiValue string_value1(value->ToString());
7658    CHECK_EQ("tipli", *string_value1);
7659
7660    Local<Value> args2[] = { v8_str("tipli") };
7661    Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7662    CHECK(value_obj2->IsObject());
7663    Local<Object> object2 = Local<Object>::Cast(value_obj2);
7664    value = object2->Get(v8_str("a"));
7665    CHECK(!try_catch.HasCaught());
7666    CHECK(value->IsString());
7667    String::AsciiValue string_value2(value->ToString());
7668    CHECK_EQ("tipli", *string_value2);
7669
7670    // Call the Object's constructor with a Boolean.
7671    value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7672    CHECK(!try_catch.HasCaught());
7673    CHECK(value->IsBoolean());
7674    CHECK_EQ(true, value->BooleanValue());
7675
7676    Handle<Value> args3[] = { v8::True() };
7677    Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7678    CHECK(value_obj3->IsObject());
7679    Local<Object> object3 = Local<Object>::Cast(value_obj3);
7680    value = object3->Get(v8_str("a"));
7681    CHECK(!try_catch.HasCaught());
7682    CHECK(value->IsBoolean());
7683    CHECK_EQ(true, value->BooleanValue());
7684
7685    // Call the Object's constructor with undefined.
7686    Handle<Value> args4[] = { v8::Undefined() };
7687    Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7688    CHECK(value_obj4->IsObject());
7689    Local<Object> object4 = Local<Object>::Cast(value_obj4);
7690    value = object4->Get(v8_str("a"));
7691    CHECK(!try_catch.HasCaught());
7692    CHECK(value->IsUndefined());
7693
7694    // Call the Object's constructor with null.
7695    Handle<Value> args5[] = { v8::Null() };
7696    Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7697    CHECK(value_obj5->IsObject());
7698    Local<Object> object5 = Local<Object>::Cast(value_obj5);
7699    value = object5->Get(v8_str("a"));
7700    CHECK(!try_catch.HasCaught());
7701    CHECK(value->IsNull());
7702  }
7703
7704  // Check exception handling when there is no constructor set for the Object.
7705  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7706    Local<Object> instance = instance_template->NewInstance();
7707    context->Global()->Set(v8_str("obj2"), instance);
7708    v8::TryCatch try_catch;
7709    Local<Value> value;
7710    CHECK(!try_catch.HasCaught());
7711
7712    value = CompileRun("new obj2(28)");
7713    CHECK(try_catch.HasCaught());
7714    String::AsciiValue exception_value1(try_catch.Exception());
7715    CHECK_EQ("TypeError: object is not a function", *exception_value1);
7716    try_catch.Reset();
7717
7718    Local<Value> args[] = { v8_num(29) };
7719    value = instance->CallAsConstructor(1, args);
7720    CHECK(try_catch.HasCaught());
7721    String::AsciiValue exception_value2(try_catch.Exception());
7722    CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7723    try_catch.Reset();
7724  }
7725
7726  // Check the case when constructor throws exception.
7727  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7728    instance_template->SetCallAsFunctionHandler(ThrowValue);
7729    Local<Object> instance = instance_template->NewInstance();
7730    context->Global()->Set(v8_str("obj3"), instance);
7731    v8::TryCatch try_catch;
7732    Local<Value> value;
7733    CHECK(!try_catch.HasCaught());
7734
7735    value = CompileRun("new obj3(22)");
7736    CHECK(try_catch.HasCaught());
7737    String::AsciiValue exception_value1(try_catch.Exception());
7738    CHECK_EQ("22", *exception_value1);
7739    try_catch.Reset();
7740
7741    Local<Value> args[] = { v8_num(23) };
7742    value = instance->CallAsConstructor(1, args);
7743    CHECK(try_catch.HasCaught());
7744    String::AsciiValue exception_value2(try_catch.Exception());
7745    CHECK_EQ("23", *exception_value2);
7746    try_catch.Reset();
7747  }
7748
7749  // Check whether constructor returns with an object or non-object.
7750  { Local<FunctionTemplate> function_template =
7751        FunctionTemplate::New(FakeConstructorCallback);
7752    Local<Function> function = function_template->GetFunction();
7753    Local<Object> instance1 = function;
7754    context->Global()->Set(v8_str("obj4"), instance1);
7755    v8::TryCatch try_catch;
7756    Local<Value> value;
7757    CHECK(!try_catch.HasCaught());
7758
7759    CHECK(instance1->IsObject());
7760    CHECK(instance1->IsFunction());
7761
7762    value = CompileRun("new obj4(28)");
7763    CHECK(!try_catch.HasCaught());
7764    CHECK(value->IsObject());
7765
7766    Local<Value> args1[] = { v8_num(28) };
7767    value = instance1->CallAsConstructor(1, args1);
7768    CHECK(!try_catch.HasCaught());
7769    CHECK(value->IsObject());
7770
7771    Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7772    instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7773    Local<Object> instance2 = instance_template->NewInstance();
7774    context->Global()->Set(v8_str("obj5"), instance2);
7775    CHECK(!try_catch.HasCaught());
7776
7777    CHECK(instance2->IsObject());
7778    CHECK(!instance2->IsFunction());
7779
7780    value = CompileRun("new obj5(28)");
7781    CHECK(!try_catch.HasCaught());
7782    CHECK(!value->IsObject());
7783
7784    Local<Value> args2[] = { v8_num(28) };
7785    value = instance2->CallAsConstructor(1, args2);
7786    CHECK(!try_catch.HasCaught());
7787    CHECK(!value->IsObject());
7788  }
7789}
7790
7791
7792THREADED_TEST(FunctionDescriptorException) {
7793  v8::HandleScope handle_scope;
7794  LocalContext context;
7795  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7796  templ->SetClassName(v8_str("Fun"));
7797  Local<Function> cons = templ->GetFunction();
7798  context->Global()->Set(v8_str("Fun"), cons);
7799  Local<Value> value = CompileRun(
7800    "function test() {"
7801    "  try {"
7802    "    (new Fun()).blah()"
7803    "  } catch (e) {"
7804    "    var str = String(e);"
7805    "    if (str.indexOf('TypeError') == -1) return 1;"
7806    "    if (str.indexOf('[object Fun]') != -1) return 2;"
7807    "    if (str.indexOf('#<Fun>') == -1) return 3;"
7808    "    return 0;"
7809    "  }"
7810    "  return 4;"
7811    "}"
7812    "test();");
7813  CHECK_EQ(0, value->Int32Value());
7814}
7815
7816
7817THREADED_TEST(EvalAliasedDynamic) {
7818  v8::HandleScope scope;
7819  LocalContext current;
7820
7821  // Tests where aliased eval can only be resolved dynamically.
7822  Local<Script> script =
7823      Script::Compile(v8_str("function f(x) { "
7824                             "  var foo = 2;"
7825                             "  with (x) { return eval('foo'); }"
7826                             "}"
7827                             "foo = 0;"
7828                             "result1 = f(new Object());"
7829                             "result2 = f(this);"
7830                             "var x = new Object();"
7831                             "x.eval = function(x) { return 1; };"
7832                             "result3 = f(x);"));
7833  script->Run();
7834  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7835  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7836  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7837
7838  v8::TryCatch try_catch;
7839  script =
7840    Script::Compile(v8_str("function f(x) { "
7841                           "  var bar = 2;"
7842                           "  with (x) { return eval('bar'); }"
7843                           "}"
7844                           "result4 = f(this)"));
7845  script->Run();
7846  CHECK(!try_catch.HasCaught());
7847  CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7848
7849  try_catch.Reset();
7850}
7851
7852
7853THREADED_TEST(CrossEval) {
7854  v8::HandleScope scope;
7855  LocalContext other;
7856  LocalContext current;
7857
7858  Local<String> token = v8_str("<security token>");
7859  other->SetSecurityToken(token);
7860  current->SetSecurityToken(token);
7861
7862  // Setup reference from current to other.
7863  current->Global()->Set(v8_str("other"), other->Global());
7864
7865  // Check that new variables are introduced in other context.
7866  Local<Script> script =
7867      Script::Compile(v8_str("other.eval('var foo = 1234')"));
7868  script->Run();
7869  Local<Value> foo = other->Global()->Get(v8_str("foo"));
7870  CHECK_EQ(1234, foo->Int32Value());
7871  CHECK(!current->Global()->Has(v8_str("foo")));
7872
7873  // Check that writing to non-existing properties introduces them in
7874  // the other context.
7875  script =
7876      Script::Compile(v8_str("other.eval('na = 1234')"));
7877  script->Run();
7878  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7879  CHECK(!current->Global()->Has(v8_str("na")));
7880
7881  // Check that global variables in current context are not visible in other
7882  // context.
7883  v8::TryCatch try_catch;
7884  script =
7885      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7886  Local<Value> result = script->Run();
7887  CHECK(try_catch.HasCaught());
7888  try_catch.Reset();
7889
7890  // Check that local variables in current context are not visible in other
7891  // context.
7892  script =
7893      Script::Compile(v8_str("(function() { "
7894                             "  var baz = 87;"
7895                             "  return other.eval('baz');"
7896                             "})();"));
7897  result = script->Run();
7898  CHECK(try_catch.HasCaught());
7899  try_catch.Reset();
7900
7901  // Check that global variables in the other environment are visible
7902  // when evaluting code.
7903  other->Global()->Set(v8_str("bis"), v8_num(1234));
7904  script = Script::Compile(v8_str("other.eval('bis')"));
7905  CHECK_EQ(1234, script->Run()->Int32Value());
7906  CHECK(!try_catch.HasCaught());
7907
7908  // Check that the 'this' pointer points to the global object evaluating
7909  // code.
7910  other->Global()->Set(v8_str("t"), other->Global());
7911  script = Script::Compile(v8_str("other.eval('this == t')"));
7912  result = script->Run();
7913  CHECK(result->IsTrue());
7914  CHECK(!try_catch.HasCaught());
7915
7916  // Check that variables introduced in with-statement are not visible in
7917  // other context.
7918  script =
7919      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7920  result = script->Run();
7921  CHECK(try_catch.HasCaught());
7922  try_catch.Reset();
7923
7924  // Check that you cannot use 'eval.call' with another object than the
7925  // current global object.
7926  script =
7927      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7928  result = script->Run();
7929  CHECK(try_catch.HasCaught());
7930}
7931
7932
7933// Test that calling eval in a context which has been detached from
7934// its global throws an exception.  This behavior is consistent with
7935// other JavaScript implementations.
7936THREADED_TEST(EvalInDetachedGlobal) {
7937  v8::HandleScope scope;
7938
7939  v8::Persistent<Context> context0 = Context::New();
7940  v8::Persistent<Context> context1 = Context::New();
7941
7942  // Setup function in context0 that uses eval from context0.
7943  context0->Enter();
7944  v8::Handle<v8::Value> fun =
7945      CompileRun("var x = 42;"
7946                 "(function() {"
7947                 "  var e = eval;"
7948                 "  return function(s) { return e(s); }"
7949                 "})()");
7950  context0->Exit();
7951
7952  // Put the function into context1 and call it before and after
7953  // detaching the global.  Before detaching, the call succeeds and
7954  // after detaching and exception is thrown.
7955  context1->Enter();
7956  context1->Global()->Set(v8_str("fun"), fun);
7957  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7958  CHECK_EQ(42, x_value->Int32Value());
7959  context0->DetachGlobal();
7960  v8::TryCatch catcher;
7961  x_value = CompileRun("fun('x')");
7962  CHECK(x_value.IsEmpty());
7963  CHECK(catcher.HasCaught());
7964  context1->Exit();
7965
7966  context1.Dispose();
7967  context0.Dispose();
7968}
7969
7970
7971THREADED_TEST(CrossLazyLoad) {
7972  v8::HandleScope scope;
7973  LocalContext other;
7974  LocalContext current;
7975
7976  Local<String> token = v8_str("<security token>");
7977  other->SetSecurityToken(token);
7978  current->SetSecurityToken(token);
7979
7980  // Setup reference from current to other.
7981  current->Global()->Set(v8_str("other"), other->Global());
7982
7983  // Trigger lazy loading in other context.
7984  Local<Script> script =
7985      Script::Compile(v8_str("other.eval('new Date(42)')"));
7986  Local<Value> value = script->Run();
7987  CHECK_EQ(42.0, value->NumberValue());
7988}
7989
7990
7991static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7992  ApiTestFuzzer::Fuzz();
7993  if (args.IsConstructCall()) {
7994    if (args[0]->IsInt32()) {
7995       return v8_num(-args[0]->Int32Value());
7996    }
7997  }
7998
7999  return args[0];
8000}
8001
8002
8003// Test that a call handler can be set for objects which will allow
8004// non-function objects created through the API to be called as
8005// functions.
8006THREADED_TEST(CallAsFunction) {
8007  v8::HandleScope scope;
8008  LocalContext context;
8009
8010  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8011    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8012    instance_template->SetCallAsFunctionHandler(call_as_function);
8013    Local<v8::Object> instance = t->GetFunction()->NewInstance();
8014    context->Global()->Set(v8_str("obj"), instance);
8015    v8::TryCatch try_catch;
8016    Local<Value> value;
8017    CHECK(!try_catch.HasCaught());
8018
8019    value = CompileRun("obj(42)");
8020    CHECK(!try_catch.HasCaught());
8021    CHECK_EQ(42, value->Int32Value());
8022
8023    value = CompileRun("(function(o){return o(49)})(obj)");
8024    CHECK(!try_catch.HasCaught());
8025    CHECK_EQ(49, value->Int32Value());
8026
8027    // test special case of call as function
8028    value = CompileRun("[obj]['0'](45)");
8029    CHECK(!try_catch.HasCaught());
8030    CHECK_EQ(45, value->Int32Value());
8031
8032    value = CompileRun("obj.call = Function.prototype.call;"
8033                       "obj.call(null, 87)");
8034    CHECK(!try_catch.HasCaught());
8035    CHECK_EQ(87, value->Int32Value());
8036
8037    // Regression tests for bug #1116356: Calling call through call/apply
8038    // must work for non-function receivers.
8039    const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8040    value = CompileRun(apply_99);
8041    CHECK(!try_catch.HasCaught());
8042    CHECK_EQ(99, value->Int32Value());
8043
8044    const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8045    value = CompileRun(call_17);
8046    CHECK(!try_catch.HasCaught());
8047    CHECK_EQ(17, value->Int32Value());
8048
8049    // Check that the call-as-function handler can be called through
8050    // new.
8051    value = CompileRun("new obj(43)");
8052    CHECK(!try_catch.HasCaught());
8053    CHECK_EQ(-43, value->Int32Value());
8054
8055    // Check that the call-as-function handler can be called through
8056    // the API.
8057    v8::Handle<Value> args[] = { v8_num(28) };
8058    value = instance->CallAsFunction(instance, 1, args);
8059    CHECK(!try_catch.HasCaught());
8060    CHECK_EQ(28, value->Int32Value());
8061  }
8062
8063  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8064    Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8065    Local<v8::Object> instance = t->GetFunction()->NewInstance();
8066    context->Global()->Set(v8_str("obj2"), instance);
8067    v8::TryCatch try_catch;
8068    Local<Value> value;
8069    CHECK(!try_catch.HasCaught());
8070
8071    // Call an object without call-as-function handler through the JS
8072    value = CompileRun("obj2(28)");
8073    CHECK(value.IsEmpty());
8074    CHECK(try_catch.HasCaught());
8075    String::AsciiValue exception_value1(try_catch.Exception());
8076    CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8077             *exception_value1);
8078    try_catch.Reset();
8079
8080    // Call an object without call-as-function handler through the API
8081    value = CompileRun("obj2(28)");
8082    v8::Handle<Value> args[] = { v8_num(28) };
8083    value = instance->CallAsFunction(instance, 1, args);
8084    CHECK(value.IsEmpty());
8085    CHECK(try_catch.HasCaught());
8086    String::AsciiValue exception_value2(try_catch.Exception());
8087    CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8088    try_catch.Reset();
8089  }
8090
8091  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8092    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8093    instance_template->SetCallAsFunctionHandler(ThrowValue);
8094    Local<v8::Object> instance = t->GetFunction()->NewInstance();
8095    context->Global()->Set(v8_str("obj3"), instance);
8096    v8::TryCatch try_catch;
8097    Local<Value> value;
8098    CHECK(!try_catch.HasCaught());
8099
8100    // Catch the exception which is thrown by call-as-function handler
8101    value = CompileRun("obj3(22)");
8102    CHECK(try_catch.HasCaught());
8103    String::AsciiValue exception_value1(try_catch.Exception());
8104    CHECK_EQ("22", *exception_value1);
8105    try_catch.Reset();
8106
8107    v8::Handle<Value> args[] = { v8_num(23) };
8108    value = instance->CallAsFunction(instance, 1, args);
8109    CHECK(try_catch.HasCaught());
8110    String::AsciiValue exception_value2(try_catch.Exception());
8111    CHECK_EQ("23", *exception_value2);
8112    try_catch.Reset();
8113  }
8114}
8115
8116
8117// Check whether a non-function object is callable.
8118THREADED_TEST(CallableObject) {
8119  v8::HandleScope scope;
8120  LocalContext context;
8121
8122  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8123    instance_template->SetCallAsFunctionHandler(call_as_function);
8124    Local<Object> instance = instance_template->NewInstance();
8125    v8::TryCatch try_catch;
8126
8127    CHECK(instance->IsCallable());
8128    CHECK(!try_catch.HasCaught());
8129  }
8130
8131  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8132    Local<Object> instance = instance_template->NewInstance();
8133    v8::TryCatch try_catch;
8134
8135    CHECK(!instance->IsCallable());
8136    CHECK(!try_catch.HasCaught());
8137  }
8138
8139  { Local<FunctionTemplate> function_template =
8140        FunctionTemplate::New(call_as_function);
8141    Local<Function> function = function_template->GetFunction();
8142    Local<Object> instance = function;
8143    v8::TryCatch try_catch;
8144
8145    CHECK(instance->IsCallable());
8146    CHECK(!try_catch.HasCaught());
8147  }
8148
8149  { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8150    Local<Function> function = function_template->GetFunction();
8151    Local<Object> instance = function;
8152    v8::TryCatch try_catch;
8153
8154    CHECK(instance->IsCallable());
8155    CHECK(!try_catch.HasCaught());
8156  }
8157}
8158
8159
8160static int CountHandles() {
8161  return v8::HandleScope::NumberOfHandles();
8162}
8163
8164
8165static int Recurse(int depth, int iterations) {
8166  v8::HandleScope scope;
8167  if (depth == 0) return CountHandles();
8168  for (int i = 0; i < iterations; i++) {
8169    Local<v8::Number> n(v8::Integer::New(42));
8170  }
8171  return Recurse(depth - 1, iterations);
8172}
8173
8174
8175THREADED_TEST(HandleIteration) {
8176  static const int kIterations = 500;
8177  static const int kNesting = 200;
8178  CHECK_EQ(0, CountHandles());
8179  {
8180    v8::HandleScope scope1;
8181    CHECK_EQ(0, CountHandles());
8182    for (int i = 0; i < kIterations; i++) {
8183      Local<v8::Number> n(v8::Integer::New(42));
8184      CHECK_EQ(i + 1, CountHandles());
8185    }
8186
8187    CHECK_EQ(kIterations, CountHandles());
8188    {
8189      v8::HandleScope scope2;
8190      for (int j = 0; j < kIterations; j++) {
8191        Local<v8::Number> n(v8::Integer::New(42));
8192        CHECK_EQ(j + 1 + kIterations, CountHandles());
8193      }
8194    }
8195    CHECK_EQ(kIterations, CountHandles());
8196  }
8197  CHECK_EQ(0, CountHandles());
8198  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8199}
8200
8201
8202static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8203    Local<String> name,
8204    const AccessorInfo& info) {
8205  ApiTestFuzzer::Fuzz();
8206  return v8::Handle<Value>();
8207}
8208
8209
8210THREADED_TEST(InterceptorHasOwnProperty) {
8211  v8::HandleScope scope;
8212  LocalContext context;
8213  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8214  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8215  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8216  Local<Function> function = fun_templ->GetFunction();
8217  context->Global()->Set(v8_str("constructor"), function);
8218  v8::Handle<Value> value = CompileRun(
8219      "var o = new constructor();"
8220      "o.hasOwnProperty('ostehaps');");
8221  CHECK_EQ(false, value->BooleanValue());
8222  value = CompileRun(
8223      "o.ostehaps = 42;"
8224      "o.hasOwnProperty('ostehaps');");
8225  CHECK_EQ(true, value->BooleanValue());
8226  value = CompileRun(
8227      "var p = new constructor();"
8228      "p.hasOwnProperty('ostehaps');");
8229  CHECK_EQ(false, value->BooleanValue());
8230}
8231
8232
8233static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8234    Local<String> name,
8235    const AccessorInfo& info) {
8236  ApiTestFuzzer::Fuzz();
8237  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8238  return v8::Handle<Value>();
8239}
8240
8241
8242THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8243  v8::HandleScope scope;
8244  LocalContext context;
8245  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8246  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8247  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8248  Local<Function> function = fun_templ->GetFunction();
8249  context->Global()->Set(v8_str("constructor"), function);
8250  // Let's first make some stuff so we can be sure to get a good GC.
8251  CompileRun(
8252      "function makestr(size) {"
8253      "  switch (size) {"
8254      "    case 1: return 'f';"
8255      "    case 2: return 'fo';"
8256      "    case 3: return 'foo';"
8257      "  }"
8258      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
8259      "}"
8260      "var x = makestr(12345);"
8261      "x = makestr(31415);"
8262      "x = makestr(23456);");
8263  v8::Handle<Value> value = CompileRun(
8264      "var o = new constructor();"
8265      "o.__proto__ = new String(x);"
8266      "o.hasOwnProperty('ostehaps');");
8267  CHECK_EQ(false, value->BooleanValue());
8268}
8269
8270
8271typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8272                                                 const AccessorInfo& info);
8273
8274
8275static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8276                                   const char* source,
8277                                   int expected) {
8278  v8::HandleScope scope;
8279  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8280  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8281  LocalContext context;
8282  context->Global()->Set(v8_str("o"), templ->NewInstance());
8283  v8::Handle<Value> value = CompileRun(source);
8284  CHECK_EQ(expected, value->Int32Value());
8285}
8286
8287
8288static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8289                                                 const AccessorInfo& info) {
8290  ApiTestFuzzer::Fuzz();
8291  CHECK_EQ(v8_str("data"), info.Data());
8292  CHECK_EQ(v8_str("x"), name);
8293  return v8::Integer::New(42);
8294}
8295
8296
8297// This test should hit the load IC for the interceptor case.
8298THREADED_TEST(InterceptorLoadIC) {
8299  CheckInterceptorLoadIC(InterceptorLoadICGetter,
8300    "var result = 0;"
8301    "for (var i = 0; i < 1000; i++) {"
8302    "  result = o.x;"
8303    "}",
8304    42);
8305}
8306
8307
8308// Below go several tests which verify that JITing for various
8309// configurations of interceptor and explicit fields works fine
8310// (those cases are special cased to get better performance).
8311
8312static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8313                                                 const AccessorInfo& info) {
8314  ApiTestFuzzer::Fuzz();
8315  return v8_str("x")->Equals(name)
8316      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8317}
8318
8319
8320THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8321  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8322    "var result = 0;"
8323    "o.y = 239;"
8324    "for (var i = 0; i < 1000; i++) {"
8325    "  result = o.y;"
8326    "}",
8327    239);
8328}
8329
8330
8331THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8332  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8333    "var result = 0;"
8334    "o.__proto__ = { 'y': 239 };"
8335    "for (var i = 0; i < 1000; i++) {"
8336    "  result = o.y + o.x;"
8337    "}",
8338    239 + 42);
8339}
8340
8341
8342THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8343  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8344    "var result = 0;"
8345    "o.__proto__.y = 239;"
8346    "for (var i = 0; i < 1000; i++) {"
8347    "  result = o.y + o.x;"
8348    "}",
8349    239 + 42);
8350}
8351
8352
8353THREADED_TEST(InterceptorLoadICUndefined) {
8354  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8355    "var result = 0;"
8356    "for (var i = 0; i < 1000; i++) {"
8357    "  result = (o.y == undefined) ? 239 : 42;"
8358    "}",
8359    239);
8360}
8361
8362
8363THREADED_TEST(InterceptorLoadICWithOverride) {
8364  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8365    "fst = new Object();  fst.__proto__ = o;"
8366    "snd = new Object();  snd.__proto__ = fst;"
8367    "var result1 = 0;"
8368    "for (var i = 0; i < 1000;  i++) {"
8369    "  result1 = snd.x;"
8370    "}"
8371    "fst.x = 239;"
8372    "var result = 0;"
8373    "for (var i = 0; i < 1000; i++) {"
8374    "  result = snd.x;"
8375    "}"
8376    "result + result1",
8377    239 + 42);
8378}
8379
8380
8381// Test the case when we stored field into
8382// a stub, but interceptor produced value on its own.
8383THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8384  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8385    "proto = new Object();"
8386    "o.__proto__ = proto;"
8387    "proto.x = 239;"
8388    "for (var i = 0; i < 1000; i++) {"
8389    "  o.x;"
8390    // Now it should be ICed and keep a reference to x defined on proto
8391    "}"
8392    "var result = 0;"
8393    "for (var i = 0; i < 1000; i++) {"
8394    "  result += o.x;"
8395    "}"
8396    "result;",
8397    42 * 1000);
8398}
8399
8400
8401// Test the case when we stored field into
8402// a stub, but it got invalidated later on.
8403THREADED_TEST(InterceptorLoadICInvalidatedField) {
8404  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8405    "proto1 = new Object();"
8406    "proto2 = new Object();"
8407    "o.__proto__ = proto1;"
8408    "proto1.__proto__ = proto2;"
8409    "proto2.y = 239;"
8410    "for (var i = 0; i < 1000; i++) {"
8411    "  o.y;"
8412    // Now it should be ICed and keep a reference to y defined on proto2
8413    "}"
8414    "proto1.y = 42;"
8415    "var result = 0;"
8416    "for (var i = 0; i < 1000; i++) {"
8417    "  result += o.y;"
8418    "}"
8419    "result;",
8420    42 * 1000);
8421}
8422
8423
8424static int interceptor_load_not_handled_calls = 0;
8425static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8426                                                   const AccessorInfo& info) {
8427  ++interceptor_load_not_handled_calls;
8428  return v8::Handle<v8::Value>();
8429}
8430
8431
8432// Test how post-interceptor lookups are done in the non-cacheable
8433// case: the interceptor should not be invoked during this lookup.
8434THREADED_TEST(InterceptorLoadICPostInterceptor) {
8435  interceptor_load_not_handled_calls = 0;
8436  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8437    "receiver = new Object();"
8438    "receiver.__proto__ = o;"
8439    "proto = new Object();"
8440    "/* Make proto a slow-case object. */"
8441    "for (var i = 0; i < 1000; i++) {"
8442    "  proto[\"xxxxxxxx\" + i] = [];"
8443    "}"
8444    "proto.x = 17;"
8445    "o.__proto__ = proto;"
8446    "var result = 0;"
8447    "for (var i = 0; i < 1000; i++) {"
8448    "  result += receiver.x;"
8449    "}"
8450    "result;",
8451    17 * 1000);
8452  CHECK_EQ(1000, interceptor_load_not_handled_calls);
8453}
8454
8455
8456// Test the case when we stored field into
8457// a stub, but it got invalidated later on due to override on
8458// global object which is between interceptor and fields' holders.
8459THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8460  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8461    "o.__proto__ = this;"  // set a global to be a proto of o.
8462    "this.__proto__.y = 239;"
8463    "for (var i = 0; i < 10; i++) {"
8464    "  if (o.y != 239) throw 'oops: ' + o.y;"
8465    // Now it should be ICed and keep a reference to y defined on field_holder.
8466    "}"
8467    "this.y = 42;"  // Assign on a global.
8468    "var result = 0;"
8469    "for (var i = 0; i < 10; i++) {"
8470    "  result += o.y;"
8471    "}"
8472    "result;",
8473    42 * 10);
8474}
8475
8476
8477static void SetOnThis(Local<String> name,
8478                      Local<Value> value,
8479                      const AccessorInfo& info) {
8480  info.This()->ForceSet(name, value);
8481}
8482
8483
8484THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8485  v8::HandleScope scope;
8486  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8487  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8488  templ->SetAccessor(v8_str("y"), Return239);
8489  LocalContext context;
8490  context->Global()->Set(v8_str("o"), templ->NewInstance());
8491
8492  // Check the case when receiver and interceptor's holder
8493  // are the same objects.
8494  v8::Handle<Value> value = CompileRun(
8495      "var result = 0;"
8496      "for (var i = 0; i < 7; i++) {"
8497      "  result = o.y;"
8498      "}");
8499  CHECK_EQ(239, value->Int32Value());
8500
8501  // Check the case when interceptor's holder is in proto chain
8502  // of receiver.
8503  value = CompileRun(
8504      "r = { __proto__: o };"
8505      "var result = 0;"
8506      "for (var i = 0; i < 7; i++) {"
8507      "  result = r.y;"
8508      "}");
8509  CHECK_EQ(239, value->Int32Value());
8510}
8511
8512
8513THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8514  v8::HandleScope scope;
8515  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8516  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8517  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8518  templ_p->SetAccessor(v8_str("y"), Return239);
8519
8520  LocalContext context;
8521  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8522  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8523
8524  // Check the case when receiver and interceptor's holder
8525  // are the same objects.
8526  v8::Handle<Value> value = CompileRun(
8527      "o.__proto__ = p;"
8528      "var result = 0;"
8529      "for (var i = 0; i < 7; i++) {"
8530      "  result = o.x + o.y;"
8531      "}");
8532  CHECK_EQ(239 + 42, value->Int32Value());
8533
8534  // Check the case when interceptor's holder is in proto chain
8535  // of receiver.
8536  value = CompileRun(
8537      "r = { __proto__: o };"
8538      "var result = 0;"
8539      "for (var i = 0; i < 7; i++) {"
8540      "  result = r.x + r.y;"
8541      "}");
8542  CHECK_EQ(239 + 42, value->Int32Value());
8543}
8544
8545
8546THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8547  v8::HandleScope scope;
8548  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8549  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8550  templ->SetAccessor(v8_str("y"), Return239);
8551
8552  LocalContext context;
8553  context->Global()->Set(v8_str("o"), templ->NewInstance());
8554
8555  v8::Handle<Value> value = CompileRun(
8556    "fst = new Object();  fst.__proto__ = o;"
8557    "snd = new Object();  snd.__proto__ = fst;"
8558    "var result1 = 0;"
8559    "for (var i = 0; i < 7;  i++) {"
8560    "  result1 = snd.x;"
8561    "}"
8562    "fst.x = 239;"
8563    "var result = 0;"
8564    "for (var i = 0; i < 7; i++) {"
8565    "  result = snd.x;"
8566    "}"
8567    "result + result1");
8568  CHECK_EQ(239 + 42, value->Int32Value());
8569}
8570
8571
8572// Test the case when we stored callback into
8573// a stub, but interceptor produced value on its own.
8574THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8575  v8::HandleScope scope;
8576  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8577  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8578  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8579  templ_p->SetAccessor(v8_str("y"), Return239);
8580
8581  LocalContext context;
8582  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8583  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8584
8585  v8::Handle<Value> value = CompileRun(
8586    "o.__proto__ = p;"
8587    "for (var i = 0; i < 7; i++) {"
8588    "  o.x;"
8589    // Now it should be ICed and keep a reference to x defined on p
8590    "}"
8591    "var result = 0;"
8592    "for (var i = 0; i < 7; i++) {"
8593    "  result += o.x;"
8594    "}"
8595    "result");
8596  CHECK_EQ(42 * 7, value->Int32Value());
8597}
8598
8599
8600// Test the case when we stored callback into
8601// a stub, but it got invalidated later on.
8602THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8603  v8::HandleScope scope;
8604  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8605  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8606  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8607  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8608
8609  LocalContext context;
8610  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8611  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8612
8613  v8::Handle<Value> value = CompileRun(
8614    "inbetween = new Object();"
8615    "o.__proto__ = inbetween;"
8616    "inbetween.__proto__ = p;"
8617    "for (var i = 0; i < 10; i++) {"
8618    "  o.y;"
8619    // Now it should be ICed and keep a reference to y defined on p
8620    "}"
8621    "inbetween.y = 42;"
8622    "var result = 0;"
8623    "for (var i = 0; i < 10; i++) {"
8624    "  result += o.y;"
8625    "}"
8626    "result");
8627  CHECK_EQ(42 * 10, value->Int32Value());
8628}
8629
8630
8631// Test the case when we stored callback into
8632// a stub, but it got invalidated later on due to override on
8633// global object which is between interceptor and callbacks' holders.
8634THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8635  v8::HandleScope scope;
8636  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8637  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8638  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8639  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8640
8641  LocalContext context;
8642  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8643  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8644
8645  v8::Handle<Value> value = CompileRun(
8646    "o.__proto__ = this;"
8647    "this.__proto__ = p;"
8648    "for (var i = 0; i < 10; i++) {"
8649    "  if (o.y != 239) throw 'oops: ' + o.y;"
8650    // Now it should be ICed and keep a reference to y defined on p
8651    "}"
8652    "this.y = 42;"
8653    "var result = 0;"
8654    "for (var i = 0; i < 10; i++) {"
8655    "  result += o.y;"
8656    "}"
8657    "result");
8658  CHECK_EQ(42 * 10, value->Int32Value());
8659}
8660
8661
8662static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8663                                                  const AccessorInfo& info) {
8664  ApiTestFuzzer::Fuzz();
8665  CHECK(v8_str("x")->Equals(name));
8666  return v8::Integer::New(0);
8667}
8668
8669
8670THREADED_TEST(InterceptorReturningZero) {
8671  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8672     "o.x == undefined ? 1 : 0",
8673     0);
8674}
8675
8676
8677static v8::Handle<Value> InterceptorStoreICSetter(
8678    Local<String> key, Local<Value> value, const AccessorInfo&) {
8679  CHECK(v8_str("x")->Equals(key));
8680  CHECK_EQ(42, value->Int32Value());
8681  return value;
8682}
8683
8684
8685// This test should hit the store IC for the interceptor case.
8686THREADED_TEST(InterceptorStoreIC) {
8687  v8::HandleScope scope;
8688  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8689  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
8690                                 InterceptorStoreICSetter,
8691                                 0, 0, 0, v8_str("data"));
8692  LocalContext context;
8693  context->Global()->Set(v8_str("o"), templ->NewInstance());
8694  v8::Handle<Value> value(CompileRun(
8695    "for (var i = 0; i < 1000; i++) {"
8696    "  o.x = 42;"
8697    "}"));
8698}
8699
8700
8701THREADED_TEST(InterceptorStoreICWithNoSetter) {
8702  v8::HandleScope scope;
8703  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8704  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8705  LocalContext context;
8706  context->Global()->Set(v8_str("o"), templ->NewInstance());
8707  v8::Handle<Value> value = CompileRun(
8708    "for (var i = 0; i < 1000; i++) {"
8709    "  o.y = 239;"
8710    "}"
8711    "42 + o.y");
8712  CHECK_EQ(239 + 42, value->Int32Value());
8713}
8714
8715
8716
8717
8718v8::Handle<Value> call_ic_function;
8719v8::Handle<Value> call_ic_function2;
8720v8::Handle<Value> call_ic_function3;
8721
8722static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8723                                                 const AccessorInfo& info) {
8724  ApiTestFuzzer::Fuzz();
8725  CHECK(v8_str("x")->Equals(name));
8726  return call_ic_function;
8727}
8728
8729
8730// This test should hit the call IC for the interceptor case.
8731THREADED_TEST(InterceptorCallIC) {
8732  v8::HandleScope scope;
8733  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8734  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8735  LocalContext context;
8736  context->Global()->Set(v8_str("o"), templ->NewInstance());
8737  call_ic_function =
8738      v8_compile("function f(x) { return x + 1; }; f")->Run();
8739  v8::Handle<Value> value = CompileRun(
8740    "var result = 0;"
8741    "for (var i = 0; i < 1000; i++) {"
8742    "  result = o.x(41);"
8743    "}");
8744  CHECK_EQ(42, value->Int32Value());
8745}
8746
8747
8748// This test checks that if interceptor doesn't provide
8749// a value, we can fetch regular value.
8750THREADED_TEST(InterceptorCallICSeesOthers) {
8751  v8::HandleScope scope;
8752  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8753  templ->SetNamedPropertyHandler(NoBlockGetterX);
8754  LocalContext context;
8755  context->Global()->Set(v8_str("o"), templ->NewInstance());
8756  v8::Handle<Value> value = CompileRun(
8757    "o.x = function f(x) { return x + 1; };"
8758    "var result = 0;"
8759    "for (var i = 0; i < 7; i++) {"
8760    "  result = o.x(41);"
8761    "}");
8762  CHECK_EQ(42, value->Int32Value());
8763}
8764
8765
8766static v8::Handle<Value> call_ic_function4;
8767static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8768                                                  const AccessorInfo& info) {
8769  ApiTestFuzzer::Fuzz();
8770  CHECK(v8_str("x")->Equals(name));
8771  return call_ic_function4;
8772}
8773
8774
8775// This test checks that if interceptor provides a function,
8776// even if we cached shadowed variant, interceptor's function
8777// is invoked
8778THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8779  v8::HandleScope scope;
8780  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8781  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8782  LocalContext context;
8783  context->Global()->Set(v8_str("o"), templ->NewInstance());
8784  call_ic_function4 =
8785      v8_compile("function f(x) { return x - 1; }; f")->Run();
8786  v8::Handle<Value> value = CompileRun(
8787    "o.__proto__.x = function(x) { return x + 1; };"
8788    "var result = 0;"
8789    "for (var i = 0; i < 1000; i++) {"
8790    "  result = o.x(42);"
8791    "}");
8792  CHECK_EQ(41, value->Int32Value());
8793}
8794
8795
8796// Test the case when we stored cacheable lookup into
8797// a stub, but it got invalidated later on
8798THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8799  v8::HandleScope scope;
8800  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8801  templ->SetNamedPropertyHandler(NoBlockGetterX);
8802  LocalContext context;
8803  context->Global()->Set(v8_str("o"), templ->NewInstance());
8804  v8::Handle<Value> value = CompileRun(
8805    "proto1 = new Object();"
8806    "proto2 = new Object();"
8807    "o.__proto__ = proto1;"
8808    "proto1.__proto__ = proto2;"
8809    "proto2.y = function(x) { return x + 1; };"
8810    // Invoke it many times to compile a stub
8811    "for (var i = 0; i < 7; i++) {"
8812    "  o.y(42);"
8813    "}"
8814    "proto1.y = function(x) { return x - 1; };"
8815    "var result = 0;"
8816    "for (var i = 0; i < 7; i++) {"
8817    "  result += o.y(42);"
8818    "}");
8819  CHECK_EQ(41 * 7, value->Int32Value());
8820}
8821
8822
8823static v8::Handle<Value> call_ic_function5;
8824static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8825                                                  const AccessorInfo& info) {
8826  ApiTestFuzzer::Fuzz();
8827  if (v8_str("x")->Equals(name))
8828    return call_ic_function5;
8829  else
8830    return Local<Value>();
8831}
8832
8833
8834// This test checks that if interceptor doesn't provide a function,
8835// cached constant function is used
8836THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8837  v8::HandleScope scope;
8838  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8839  templ->SetNamedPropertyHandler(NoBlockGetterX);
8840  LocalContext context;
8841  context->Global()->Set(v8_str("o"), templ->NewInstance());
8842  v8::Handle<Value> value = CompileRun(
8843    "function inc(x) { return x + 1; };"
8844    "inc(1);"
8845    "o.x = inc;"
8846    "var result = 0;"
8847    "for (var i = 0; i < 1000; i++) {"
8848    "  result = o.x(42);"
8849    "}");
8850  CHECK_EQ(43, value->Int32Value());
8851}
8852
8853
8854// This test checks that if interceptor provides a function,
8855// even if we cached constant function, interceptor's function
8856// is invoked
8857THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8858  v8::HandleScope scope;
8859  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8860  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8861  LocalContext context;
8862  context->Global()->Set(v8_str("o"), templ->NewInstance());
8863  call_ic_function5 =
8864      v8_compile("function f(x) { return x - 1; }; f")->Run();
8865  v8::Handle<Value> value = CompileRun(
8866    "function inc(x) { return x + 1; };"
8867    "inc(1);"
8868    "o.x = inc;"
8869    "var result = 0;"
8870    "for (var i = 0; i < 1000; i++) {"
8871    "  result = o.x(42);"
8872    "}");
8873  CHECK_EQ(41, value->Int32Value());
8874}
8875
8876
8877// Test the case when we stored constant function into
8878// a stub, but it got invalidated later on
8879THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8880  v8::HandleScope scope;
8881  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8882  templ->SetNamedPropertyHandler(NoBlockGetterX);
8883  LocalContext context;
8884  context->Global()->Set(v8_str("o"), templ->NewInstance());
8885  v8::Handle<Value> value = CompileRun(
8886    "function inc(x) { return x + 1; };"
8887    "inc(1);"
8888    "proto1 = new Object();"
8889    "proto2 = new Object();"
8890    "o.__proto__ = proto1;"
8891    "proto1.__proto__ = proto2;"
8892    "proto2.y = inc;"
8893    // Invoke it many times to compile a stub
8894    "for (var i = 0; i < 7; i++) {"
8895    "  o.y(42);"
8896    "}"
8897    "proto1.y = function(x) { return x - 1; };"
8898    "var result = 0;"
8899    "for (var i = 0; i < 7; i++) {"
8900    "  result += o.y(42);"
8901    "}");
8902  CHECK_EQ(41 * 7, value->Int32Value());
8903}
8904
8905
8906// Test the case when we stored constant function into
8907// a stub, but it got invalidated later on due to override on
8908// global object which is between interceptor and constant function' holders.
8909THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8910  v8::HandleScope scope;
8911  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8912  templ->SetNamedPropertyHandler(NoBlockGetterX);
8913  LocalContext context;
8914  context->Global()->Set(v8_str("o"), templ->NewInstance());
8915  v8::Handle<Value> value = CompileRun(
8916    "function inc(x) { return x + 1; };"
8917    "inc(1);"
8918    "o.__proto__ = this;"
8919    "this.__proto__.y = inc;"
8920    // Invoke it many times to compile a stub
8921    "for (var i = 0; i < 7; i++) {"
8922    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8923    "}"
8924    "this.y = function(x) { return x - 1; };"
8925    "var result = 0;"
8926    "for (var i = 0; i < 7; i++) {"
8927    "  result += o.y(42);"
8928    "}");
8929  CHECK_EQ(41 * 7, value->Int32Value());
8930}
8931
8932
8933// Test the case when actual function to call sits on global object.
8934THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8935  v8::HandleScope scope;
8936  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8937  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8938
8939  LocalContext context;
8940  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8941
8942  v8::Handle<Value> value = CompileRun(
8943    "try {"
8944    "  o.__proto__ = this;"
8945    "  for (var i = 0; i < 10; i++) {"
8946    "    var v = o.parseFloat('239');"
8947    "    if (v != 239) throw v;"
8948      // Now it should be ICed and keep a reference to parseFloat.
8949    "  }"
8950    "  var result = 0;"
8951    "  for (var i = 0; i < 10; i++) {"
8952    "    result += o.parseFloat('239');"
8953    "  }"
8954    "  result"
8955    "} catch(e) {"
8956    "  e"
8957    "};");
8958  CHECK_EQ(239 * 10, value->Int32Value());
8959}
8960
8961static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8962                                                  const AccessorInfo& info) {
8963  ApiTestFuzzer::Fuzz();
8964  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8965  ++(*call_count);
8966  if ((*call_count) % 20 == 0) {
8967    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8968  }
8969  return v8::Handle<Value>();
8970}
8971
8972static v8::Handle<Value> FastApiCallback_TrivialSignature(
8973    const v8::Arguments& args) {
8974  ApiTestFuzzer::Fuzz();
8975  CHECK_EQ(args.This(), args.Holder());
8976  CHECK(args.Data()->Equals(v8_str("method_data")));
8977  return v8::Integer::New(args[0]->Int32Value() + 1);
8978}
8979
8980static v8::Handle<Value> FastApiCallback_SimpleSignature(
8981    const v8::Arguments& args) {
8982  ApiTestFuzzer::Fuzz();
8983  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8984  CHECK(args.Data()->Equals(v8_str("method_data")));
8985  // Note, we're using HasRealNamedProperty instead of Has to avoid
8986  // invoking the interceptor again.
8987  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8988  return v8::Integer::New(args[0]->Int32Value() + 1);
8989}
8990
8991// Helper to maximize the odds of object moving.
8992static void GenerateSomeGarbage() {
8993  CompileRun(
8994      "var garbage;"
8995      "for (var i = 0; i < 1000; i++) {"
8996      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8997      "}"
8998      "garbage = undefined;");
8999}
9000
9001
9002v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9003  static int count = 0;
9004  if (count++ % 3 == 0) {
9005    HEAP->  CollectAllGarbage(true);  // This should move the stub
9006    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
9007  }
9008  return v8::Handle<v8::Value>();
9009}
9010
9011
9012THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9013  v8::HandleScope scope;
9014  LocalContext context;
9015  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9016  nativeobject_templ->Set("callback",
9017                          v8::FunctionTemplate::New(DirectApiCallback));
9018  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9019  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9020  // call the api function multiple times to ensure direct call stub creation.
9021  CompileRun(
9022        "function f() {"
9023        "  for (var i = 1; i <= 30; i++) {"
9024        "    nativeobject.callback();"
9025        "  }"
9026        "}"
9027        "f();");
9028}
9029
9030
9031v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9032  return v8::ThrowException(v8_str("g"));
9033}
9034
9035
9036THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9037  v8::HandleScope scope;
9038  LocalContext context;
9039  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9040  nativeobject_templ->Set("callback",
9041                          v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9042  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9043  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9044  // call the api function multiple times to ensure direct call stub creation.
9045  v8::Handle<Value> result = CompileRun(
9046      "var result = '';"
9047      "function f() {"
9048      "  for (var i = 1; i <= 5; i++) {"
9049      "    try { nativeobject.callback(); } catch (e) { result += e; }"
9050      "  }"
9051      "}"
9052      "f(); result;");
9053  CHECK_EQ(v8_str("ggggg"), result);
9054}
9055
9056
9057v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9058                                           const v8::AccessorInfo& info) {
9059  if (++p_getter_count % 3 == 0) {
9060    HEAP->CollectAllGarbage(true);
9061    GenerateSomeGarbage();
9062  }
9063  return v8::Handle<v8::Value>();
9064}
9065
9066
9067THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9068  v8::HandleScope scope;
9069  LocalContext context;
9070  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9071  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9072  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9073  p_getter_count = 0;
9074  CompileRun(
9075      "function f() {"
9076      "  for (var i = 0; i < 30; i++) o1.p1;"
9077      "}"
9078      "f();");
9079  CHECK_EQ(30, p_getter_count);
9080}
9081
9082
9083v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9084    Local<String> name, const v8::AccessorInfo& info) {
9085  return v8::ThrowException(v8_str("g"));
9086}
9087
9088
9089THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9090  v8::HandleScope scope;
9091  LocalContext context;
9092  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9093  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9094  context->Global()->Set(v8_str("o1"), obj->NewInstance());
9095  v8::Handle<Value> result = CompileRun(
9096      "var result = '';"
9097      "for (var i = 0; i < 5; i++) {"
9098      "    try { o1.p1; } catch (e) { result += e; }"
9099      "}"
9100      "result;");
9101  CHECK_EQ(v8_str("ggggg"), result);
9102}
9103
9104
9105THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9106  int interceptor_call_count = 0;
9107  v8::HandleScope scope;
9108  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9109  v8::Handle<v8::FunctionTemplate> method_templ =
9110      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9111                                v8_str("method_data"),
9112                                v8::Handle<v8::Signature>());
9113  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9114  proto_templ->Set(v8_str("method"), method_templ);
9115  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9116  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9117                                 NULL, NULL, NULL, NULL,
9118                                 v8::External::Wrap(&interceptor_call_count));
9119  LocalContext context;
9120  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9121  GenerateSomeGarbage();
9122  context->Global()->Set(v8_str("o"), fun->NewInstance());
9123  v8::Handle<Value> value(CompileRun(
9124      "var result = 0;"
9125      "for (var i = 0; i < 100; i++) {"
9126      "  result = o.method(41);"
9127      "}"));
9128  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9129  CHECK_EQ(100, interceptor_call_count);
9130}
9131
9132THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9133  int interceptor_call_count = 0;
9134  v8::HandleScope scope;
9135  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9136  v8::Handle<v8::FunctionTemplate> method_templ =
9137      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9138                                v8_str("method_data"),
9139                                v8::Signature::New(fun_templ));
9140  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9141  proto_templ->Set(v8_str("method"), method_templ);
9142  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9143  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9144                                 NULL, NULL, NULL, NULL,
9145                                 v8::External::Wrap(&interceptor_call_count));
9146  LocalContext context;
9147  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9148  GenerateSomeGarbage();
9149  context->Global()->Set(v8_str("o"), fun->NewInstance());
9150  v8::Handle<Value> value(CompileRun(
9151      "o.foo = 17;"
9152      "var receiver = {};"
9153      "receiver.__proto__ = o;"
9154      "var result = 0;"
9155      "for (var i = 0; i < 100; i++) {"
9156      "  result = receiver.method(41);"
9157      "}"));
9158  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9159  CHECK_EQ(100, interceptor_call_count);
9160}
9161
9162THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9163  int interceptor_call_count = 0;
9164  v8::HandleScope scope;
9165  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9166  v8::Handle<v8::FunctionTemplate> method_templ =
9167      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9168                                v8_str("method_data"),
9169                                v8::Signature::New(fun_templ));
9170  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9171  proto_templ->Set(v8_str("method"), method_templ);
9172  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9173  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9174                                 NULL, NULL, NULL, NULL,
9175                                 v8::External::Wrap(&interceptor_call_count));
9176  LocalContext context;
9177  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9178  GenerateSomeGarbage();
9179  context->Global()->Set(v8_str("o"), fun->NewInstance());
9180  v8::Handle<Value> value(CompileRun(
9181      "o.foo = 17;"
9182      "var receiver = {};"
9183      "receiver.__proto__ = o;"
9184      "var result = 0;"
9185      "var saved_result = 0;"
9186      "for (var i = 0; i < 100; i++) {"
9187      "  result = receiver.method(41);"
9188      "  if (i == 50) {"
9189      "    saved_result = result;"
9190      "    receiver = {method: function(x) { return x - 1 }};"
9191      "  }"
9192      "}"));
9193  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9194  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9195  CHECK_GE(interceptor_call_count, 50);
9196}
9197
9198THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9199  int interceptor_call_count = 0;
9200  v8::HandleScope scope;
9201  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9202  v8::Handle<v8::FunctionTemplate> method_templ =
9203      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9204                                v8_str("method_data"),
9205                                v8::Signature::New(fun_templ));
9206  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9207  proto_templ->Set(v8_str("method"), method_templ);
9208  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9209  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9210                                 NULL, NULL, NULL, NULL,
9211                                 v8::External::Wrap(&interceptor_call_count));
9212  LocalContext context;
9213  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9214  GenerateSomeGarbage();
9215  context->Global()->Set(v8_str("o"), fun->NewInstance());
9216  v8::Handle<Value> value(CompileRun(
9217      "o.foo = 17;"
9218      "var receiver = {};"
9219      "receiver.__proto__ = o;"
9220      "var result = 0;"
9221      "var saved_result = 0;"
9222      "for (var i = 0; i < 100; i++) {"
9223      "  result = receiver.method(41);"
9224      "  if (i == 50) {"
9225      "    saved_result = result;"
9226      "    o.method = function(x) { return x - 1 };"
9227      "  }"
9228      "}"));
9229  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9230  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9231  CHECK_GE(interceptor_call_count, 50);
9232}
9233
9234THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9235  int interceptor_call_count = 0;
9236  v8::HandleScope scope;
9237  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9238  v8::Handle<v8::FunctionTemplate> method_templ =
9239      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9240                                v8_str("method_data"),
9241                                v8::Signature::New(fun_templ));
9242  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9243  proto_templ->Set(v8_str("method"), method_templ);
9244  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9245  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9246                                 NULL, NULL, NULL, NULL,
9247                                 v8::External::Wrap(&interceptor_call_count));
9248  LocalContext context;
9249  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9250  GenerateSomeGarbage();
9251  context->Global()->Set(v8_str("o"), fun->NewInstance());
9252  v8::TryCatch try_catch;
9253  v8::Handle<Value> value(CompileRun(
9254      "o.foo = 17;"
9255      "var receiver = {};"
9256      "receiver.__proto__ = o;"
9257      "var result = 0;"
9258      "var saved_result = 0;"
9259      "for (var i = 0; i < 100; i++) {"
9260      "  result = receiver.method(41);"
9261      "  if (i == 50) {"
9262      "    saved_result = result;"
9263      "    receiver = 333;"
9264      "  }"
9265      "}"));
9266  CHECK(try_catch.HasCaught());
9267  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9268           try_catch.Exception()->ToString());
9269  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9270  CHECK_GE(interceptor_call_count, 50);
9271}
9272
9273THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9274  int interceptor_call_count = 0;
9275  v8::HandleScope scope;
9276  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9277  v8::Handle<v8::FunctionTemplate> method_templ =
9278      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9279                                v8_str("method_data"),
9280                                v8::Signature::New(fun_templ));
9281  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9282  proto_templ->Set(v8_str("method"), method_templ);
9283  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9284  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9285                                 NULL, NULL, NULL, NULL,
9286                                 v8::External::Wrap(&interceptor_call_count));
9287  LocalContext context;
9288  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9289  GenerateSomeGarbage();
9290  context->Global()->Set(v8_str("o"), fun->NewInstance());
9291  v8::TryCatch try_catch;
9292  v8::Handle<Value> value(CompileRun(
9293      "o.foo = 17;"
9294      "var receiver = {};"
9295      "receiver.__proto__ = o;"
9296      "var result = 0;"
9297      "var saved_result = 0;"
9298      "for (var i = 0; i < 100; i++) {"
9299      "  result = receiver.method(41);"
9300      "  if (i == 50) {"
9301      "    saved_result = result;"
9302      "    receiver = {method: receiver.method};"
9303      "  }"
9304      "}"));
9305  CHECK(try_catch.HasCaught());
9306  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9307           try_catch.Exception()->ToString());
9308  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9309  CHECK_GE(interceptor_call_count, 50);
9310}
9311
9312THREADED_TEST(CallICFastApi_TrivialSignature) {
9313  v8::HandleScope scope;
9314  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9315  v8::Handle<v8::FunctionTemplate> method_templ =
9316      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9317                                v8_str("method_data"),
9318                                v8::Handle<v8::Signature>());
9319  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9320  proto_templ->Set(v8_str("method"), method_templ);
9321  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9322  LocalContext context;
9323  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9324  GenerateSomeGarbage();
9325  context->Global()->Set(v8_str("o"), fun->NewInstance());
9326  v8::Handle<Value> value(CompileRun(
9327      "var result = 0;"
9328      "for (var i = 0; i < 100; i++) {"
9329      "  result = o.method(41);"
9330      "}"));
9331
9332  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9333}
9334
9335THREADED_TEST(CallICFastApi_SimpleSignature) {
9336  v8::HandleScope scope;
9337  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9338  v8::Handle<v8::FunctionTemplate> method_templ =
9339      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9340                                v8_str("method_data"),
9341                                v8::Signature::New(fun_templ));
9342  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9343  proto_templ->Set(v8_str("method"), method_templ);
9344  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9345  LocalContext context;
9346  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9347  GenerateSomeGarbage();
9348  context->Global()->Set(v8_str("o"), fun->NewInstance());
9349  v8::Handle<Value> value(CompileRun(
9350      "o.foo = 17;"
9351      "var receiver = {};"
9352      "receiver.__proto__ = o;"
9353      "var result = 0;"
9354      "for (var i = 0; i < 100; i++) {"
9355      "  result = receiver.method(41);"
9356      "}"));
9357
9358  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9359}
9360
9361THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9362  v8::HandleScope scope;
9363  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9364  v8::Handle<v8::FunctionTemplate> method_templ =
9365      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9366                                v8_str("method_data"),
9367                                v8::Signature::New(fun_templ));
9368  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9369  proto_templ->Set(v8_str("method"), method_templ);
9370  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9371  LocalContext context;
9372  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9373  GenerateSomeGarbage();
9374  context->Global()->Set(v8_str("o"), fun->NewInstance());
9375  v8::Handle<Value> value(CompileRun(
9376      "o.foo = 17;"
9377      "var receiver = {};"
9378      "receiver.__proto__ = o;"
9379      "var result = 0;"
9380      "var saved_result = 0;"
9381      "for (var i = 0; i < 100; i++) {"
9382      "  result = receiver.method(41);"
9383      "  if (i == 50) {"
9384      "    saved_result = result;"
9385      "    receiver = {method: function(x) { return x - 1 }};"
9386      "  }"
9387      "}"));
9388  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9389  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9390}
9391
9392THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9393  v8::HandleScope scope;
9394  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9395  v8::Handle<v8::FunctionTemplate> method_templ =
9396      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9397                                v8_str("method_data"),
9398                                v8::Signature::New(fun_templ));
9399  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9400  proto_templ->Set(v8_str("method"), method_templ);
9401  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9402  LocalContext context;
9403  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9404  GenerateSomeGarbage();
9405  context->Global()->Set(v8_str("o"), fun->NewInstance());
9406  v8::TryCatch try_catch;
9407  v8::Handle<Value> value(CompileRun(
9408      "o.foo = 17;"
9409      "var receiver = {};"
9410      "receiver.__proto__ = o;"
9411      "var result = 0;"
9412      "var saved_result = 0;"
9413      "for (var i = 0; i < 100; i++) {"
9414      "  result = receiver.method(41);"
9415      "  if (i == 50) {"
9416      "    saved_result = result;"
9417      "    receiver = 333;"
9418      "  }"
9419      "}"));
9420  CHECK(try_catch.HasCaught());
9421  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9422           try_catch.Exception()->ToString());
9423  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9424}
9425
9426
9427v8::Handle<Value> keyed_call_ic_function;
9428
9429static v8::Handle<Value> InterceptorKeyedCallICGetter(
9430    Local<String> name, const AccessorInfo& info) {
9431  ApiTestFuzzer::Fuzz();
9432  if (v8_str("x")->Equals(name)) {
9433    return keyed_call_ic_function;
9434  }
9435  return v8::Handle<Value>();
9436}
9437
9438
9439// Test the case when we stored cacheable lookup into
9440// a stub, but the function name changed (to another cacheable function).
9441THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9442  v8::HandleScope scope;
9443  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9444  templ->SetNamedPropertyHandler(NoBlockGetterX);
9445  LocalContext context;
9446  context->Global()->Set(v8_str("o"), templ->NewInstance());
9447  v8::Handle<Value> value(CompileRun(
9448    "proto = new Object();"
9449    "proto.y = function(x) { return x + 1; };"
9450    "proto.z = function(x) { return x - 1; };"
9451    "o.__proto__ = proto;"
9452    "var result = 0;"
9453    "var method = 'y';"
9454    "for (var i = 0; i < 10; i++) {"
9455    "  if (i == 5) { method = 'z'; };"
9456    "  result += o[method](41);"
9457    "}"));
9458  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9459}
9460
9461
9462// Test the case when we stored cacheable lookup into
9463// a stub, but the function name changed (and the new function is present
9464// both before and after the interceptor in the prototype chain).
9465THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9466  v8::HandleScope scope;
9467  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9468  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9469  LocalContext context;
9470  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9471  keyed_call_ic_function =
9472      v8_compile("function f(x) { return x - 1; }; f")->Run();
9473  v8::Handle<Value> value(CompileRun(
9474    "o = new Object();"
9475    "proto2 = new Object();"
9476    "o.y = function(x) { return x + 1; };"
9477    "proto2.y = function(x) { return x + 2; };"
9478    "o.__proto__ = proto1;"
9479    "proto1.__proto__ = proto2;"
9480    "var result = 0;"
9481    "var method = 'x';"
9482    "for (var i = 0; i < 10; i++) {"
9483    "  if (i == 5) { method = 'y'; };"
9484    "  result += o[method](41);"
9485    "}"));
9486  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9487}
9488
9489
9490// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9491// on the global object.
9492THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9493  v8::HandleScope scope;
9494  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9495  templ->SetNamedPropertyHandler(NoBlockGetterX);
9496  LocalContext context;
9497  context->Global()->Set(v8_str("o"), templ->NewInstance());
9498  v8::Handle<Value> value(CompileRun(
9499    "function inc(x) { return x + 1; };"
9500    "inc(1);"
9501    "function dec(x) { return x - 1; };"
9502    "dec(1);"
9503    "o.__proto__ = this;"
9504    "this.__proto__.x = inc;"
9505    "this.__proto__.y = dec;"
9506    "var result = 0;"
9507    "var method = 'x';"
9508    "for (var i = 0; i < 10; i++) {"
9509    "  if (i == 5) { method = 'y'; };"
9510    "  result += o[method](41);"
9511    "}"));
9512  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9513}
9514
9515
9516// Test the case when actual function to call sits on global object.
9517THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9518  v8::HandleScope scope;
9519  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9520  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9521  LocalContext context;
9522  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9523
9524  v8::Handle<Value> value(CompileRun(
9525    "function len(x) { return x.length; };"
9526    "o.__proto__ = this;"
9527    "var m = 'parseFloat';"
9528    "var result = 0;"
9529    "for (var i = 0; i < 10; i++) {"
9530    "  if (i == 5) {"
9531    "    m = 'len';"
9532    "    saved_result = result;"
9533    "  };"
9534    "  result = o[m]('239');"
9535    "}"));
9536  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9537  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9538}
9539
9540// Test the map transition before the interceptor.
9541THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9542  v8::HandleScope scope;
9543  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9544  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9545  LocalContext context;
9546  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9547
9548  v8::Handle<Value> value(CompileRun(
9549    "var o = new Object();"
9550    "o.__proto__ = proto;"
9551    "o.method = function(x) { return x + 1; };"
9552    "var m = 'method';"
9553    "var result = 0;"
9554    "for (var i = 0; i < 10; i++) {"
9555    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
9556    "  result += o[m](41);"
9557    "}"));
9558  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9559}
9560
9561
9562// Test the map transition after the interceptor.
9563THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9564  v8::HandleScope scope;
9565  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9566  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9567  LocalContext context;
9568  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9569
9570  v8::Handle<Value> value(CompileRun(
9571    "var proto = new Object();"
9572    "o.__proto__ = proto;"
9573    "proto.method = function(x) { return x + 1; };"
9574    "var m = 'method';"
9575    "var result = 0;"
9576    "for (var i = 0; i < 10; i++) {"
9577    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9578    "  result += o[m](41);"
9579    "}"));
9580  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9581}
9582
9583
9584static int interceptor_call_count = 0;
9585
9586static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9587                                                     const AccessorInfo& info) {
9588  ApiTestFuzzer::Fuzz();
9589  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9590    return call_ic_function2;
9591  }
9592  return v8::Handle<Value>();
9593}
9594
9595
9596// This test should hit load and call ICs for the interceptor case.
9597// Once in a while, the interceptor will reply that a property was not
9598// found in which case we should get a reference error.
9599THREADED_TEST(InterceptorICReferenceErrors) {
9600  v8::HandleScope scope;
9601  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9602  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9603  LocalContext context(0, templ, v8::Handle<Value>());
9604  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9605  v8::Handle<Value> value = CompileRun(
9606    "function f() {"
9607    "  for (var i = 0; i < 1000; i++) {"
9608    "    try { x; } catch(e) { return true; }"
9609    "  }"
9610    "  return false;"
9611    "};"
9612    "f();");
9613  CHECK_EQ(true, value->BooleanValue());
9614  interceptor_call_count = 0;
9615  value = CompileRun(
9616    "function g() {"
9617    "  for (var i = 0; i < 1000; i++) {"
9618    "    try { x(42); } catch(e) { return true; }"
9619    "  }"
9620    "  return false;"
9621    "};"
9622    "g();");
9623  CHECK_EQ(true, value->BooleanValue());
9624}
9625
9626
9627static int interceptor_ic_exception_get_count = 0;
9628
9629static v8::Handle<Value> InterceptorICExceptionGetter(
9630    Local<String> name,
9631    const AccessorInfo& info) {
9632  ApiTestFuzzer::Fuzz();
9633  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9634    return call_ic_function3;
9635  }
9636  if (interceptor_ic_exception_get_count == 20) {
9637    return v8::ThrowException(v8_num(42));
9638  }
9639  // Do not handle get for properties other than x.
9640  return v8::Handle<Value>();
9641}
9642
9643// Test interceptor load/call IC where the interceptor throws an
9644// exception once in a while.
9645THREADED_TEST(InterceptorICGetterExceptions) {
9646  interceptor_ic_exception_get_count = 0;
9647  v8::HandleScope scope;
9648  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9649  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9650  LocalContext context(0, templ, v8::Handle<Value>());
9651  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9652  v8::Handle<Value> value = CompileRun(
9653    "function f() {"
9654    "  for (var i = 0; i < 100; i++) {"
9655    "    try { x; } catch(e) { return true; }"
9656    "  }"
9657    "  return false;"
9658    "};"
9659    "f();");
9660  CHECK_EQ(true, value->BooleanValue());
9661  interceptor_ic_exception_get_count = 0;
9662  value = CompileRun(
9663    "function f() {"
9664    "  for (var i = 0; i < 100; i++) {"
9665    "    try { x(42); } catch(e) { return true; }"
9666    "  }"
9667    "  return false;"
9668    "};"
9669    "f();");
9670  CHECK_EQ(true, value->BooleanValue());
9671}
9672
9673
9674static int interceptor_ic_exception_set_count = 0;
9675
9676static v8::Handle<Value> InterceptorICExceptionSetter(
9677      Local<String> key, Local<Value> value, const AccessorInfo&) {
9678  ApiTestFuzzer::Fuzz();
9679  if (++interceptor_ic_exception_set_count > 20) {
9680    return v8::ThrowException(v8_num(42));
9681  }
9682  // Do not actually handle setting.
9683  return v8::Handle<Value>();
9684}
9685
9686// Test interceptor store IC where the interceptor throws an exception
9687// once in a while.
9688THREADED_TEST(InterceptorICSetterExceptions) {
9689  interceptor_ic_exception_set_count = 0;
9690  v8::HandleScope scope;
9691  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9692  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9693  LocalContext context(0, templ, v8::Handle<Value>());
9694  v8::Handle<Value> value = CompileRun(
9695    "function f() {"
9696    "  for (var i = 0; i < 100; i++) {"
9697    "    try { x = 42; } catch(e) { return true; }"
9698    "  }"
9699    "  return false;"
9700    "};"
9701    "f();");
9702  CHECK_EQ(true, value->BooleanValue());
9703}
9704
9705
9706// Test that we ignore null interceptors.
9707THREADED_TEST(NullNamedInterceptor) {
9708  v8::HandleScope scope;
9709  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9710  templ->SetNamedPropertyHandler(0);
9711  LocalContext context;
9712  templ->Set("x", v8_num(42));
9713  v8::Handle<v8::Object> obj = templ->NewInstance();
9714  context->Global()->Set(v8_str("obj"), obj);
9715  v8::Handle<Value> value = CompileRun("obj.x");
9716  CHECK(value->IsInt32());
9717  CHECK_EQ(42, value->Int32Value());
9718}
9719
9720
9721// Test that we ignore null interceptors.
9722THREADED_TEST(NullIndexedInterceptor) {
9723  v8::HandleScope scope;
9724  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9725  templ->SetIndexedPropertyHandler(0);
9726  LocalContext context;
9727  templ->Set("42", v8_num(42));
9728  v8::Handle<v8::Object> obj = templ->NewInstance();
9729  context->Global()->Set(v8_str("obj"), obj);
9730  v8::Handle<Value> value = CompileRun("obj[42]");
9731  CHECK(value->IsInt32());
9732  CHECK_EQ(42, value->Int32Value());
9733}
9734
9735
9736THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9737  v8::HandleScope scope;
9738  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9739  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9740  LocalContext env;
9741  env->Global()->Set(v8_str("obj"),
9742                     templ->GetFunction()->NewInstance());
9743  ExpectTrue("obj.x === 42");
9744  ExpectTrue("!obj.propertyIsEnumerable('x')");
9745}
9746
9747
9748static Handle<Value> ThrowingGetter(Local<String> name,
9749                                    const AccessorInfo& info) {
9750  ApiTestFuzzer::Fuzz();
9751  ThrowException(Handle<Value>());
9752  return Undefined();
9753}
9754
9755
9756THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9757  HandleScope scope;
9758  LocalContext context;
9759
9760  Local<FunctionTemplate> templ = FunctionTemplate::New();
9761  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9762  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9763
9764  Local<Object> instance = templ->GetFunction()->NewInstance();
9765
9766  Local<Object> another = Object::New();
9767  another->SetPrototype(instance);
9768
9769  Local<Object> with_js_getter = CompileRun(
9770      "o = {};\n"
9771      "o.__defineGetter__('f', function() { throw undefined; });\n"
9772      "o\n").As<Object>();
9773  CHECK(!with_js_getter.IsEmpty());
9774
9775  TryCatch try_catch;
9776
9777  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9778  CHECK(try_catch.HasCaught());
9779  try_catch.Reset();
9780  CHECK(result.IsEmpty());
9781
9782  result = another->GetRealNamedProperty(v8_str("f"));
9783  CHECK(try_catch.HasCaught());
9784  try_catch.Reset();
9785  CHECK(result.IsEmpty());
9786
9787  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9788  CHECK(try_catch.HasCaught());
9789  try_catch.Reset();
9790  CHECK(result.IsEmpty());
9791
9792  result = another->Get(v8_str("f"));
9793  CHECK(try_catch.HasCaught());
9794  try_catch.Reset();
9795  CHECK(result.IsEmpty());
9796
9797  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9798  CHECK(try_catch.HasCaught());
9799  try_catch.Reset();
9800  CHECK(result.IsEmpty());
9801
9802  result = with_js_getter->Get(v8_str("f"));
9803  CHECK(try_catch.HasCaught());
9804  try_catch.Reset();
9805  CHECK(result.IsEmpty());
9806}
9807
9808
9809static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9810  TryCatch try_catch;
9811  // Verboseness is important: it triggers message delivery which can call into
9812  // external code.
9813  try_catch.SetVerbose(true);
9814  CompileRun("throw 'from JS';");
9815  CHECK(try_catch.HasCaught());
9816  CHECK(!i::Isolate::Current()->has_pending_exception());
9817  CHECK(!i::Isolate::Current()->has_scheduled_exception());
9818  return Undefined();
9819}
9820
9821
9822static int call_depth;
9823
9824
9825static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9826  TryCatch try_catch;
9827}
9828
9829
9830static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9831  if (--call_depth) CompileRun("throw 'ThrowInJS';");
9832}
9833
9834
9835static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9836  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9837}
9838
9839
9840static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9841  Handle<String> errorMessageString = message->Get();
9842  CHECK(!errorMessageString.IsEmpty());
9843  message->GetStackTrace();
9844  message->GetScriptResourceName();
9845}
9846
9847THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9848  HandleScope scope;
9849  LocalContext context;
9850
9851  Local<Function> func =
9852      FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9853  context->Global()->Set(v8_str("func"), func);
9854
9855  MessageCallback callbacks[] =
9856      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9857  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9858    MessageCallback callback = callbacks[i];
9859    if (callback != NULL) {
9860      V8::AddMessageListener(callback);
9861    }
9862    // Some small number to control number of times message handler should
9863    // throw an exception.
9864    call_depth = 5;
9865    ExpectFalse(
9866        "var thrown = false;\n"
9867        "try { func(); } catch(e) { thrown = true; }\n"
9868        "thrown\n");
9869    if (callback != NULL) {
9870      V8::RemoveMessageListeners(callback);
9871    }
9872  }
9873}
9874
9875
9876static v8::Handle<Value> ParentGetter(Local<String> name,
9877                                      const AccessorInfo& info) {
9878  ApiTestFuzzer::Fuzz();
9879  return v8_num(1);
9880}
9881
9882
9883static v8::Handle<Value> ChildGetter(Local<String> name,
9884                                     const AccessorInfo& info) {
9885  ApiTestFuzzer::Fuzz();
9886  return v8_num(42);
9887}
9888
9889
9890THREADED_TEST(Overriding) {
9891  v8::HandleScope scope;
9892  LocalContext context;
9893
9894  // Parent template.
9895  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9896  Local<ObjectTemplate> parent_instance_templ =
9897      parent_templ->InstanceTemplate();
9898  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9899
9900  // Template that inherits from the parent template.
9901  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9902  Local<ObjectTemplate> child_instance_templ =
9903      child_templ->InstanceTemplate();
9904  child_templ->Inherit(parent_templ);
9905  // Override 'f'.  The child version of 'f' should get called for child
9906  // instances.
9907  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9908  // Add 'g' twice.  The 'g' added last should get called for instances.
9909  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9910  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9911
9912  // Add 'h' as an accessor to the proto template with ReadOnly attributes
9913  // so 'h' can be shadowed on the instance object.
9914  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9915  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9916      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9917
9918  // Add 'i' as an accessor to the instance template with ReadOnly attributes
9919  // but the attribute does not have effect because it is duplicated with
9920  // NULL setter.
9921  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9922      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9923
9924
9925
9926  // Instantiate the child template.
9927  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9928
9929  // Check that the child function overrides the parent one.
9930  context->Global()->Set(v8_str("o"), instance);
9931  Local<Value> value = v8_compile("o.f")->Run();
9932  // Check that the 'g' that was added last is hit.
9933  CHECK_EQ(42, value->Int32Value());
9934  value = v8_compile("o.g")->Run();
9935  CHECK_EQ(42, value->Int32Value());
9936
9937  // Check 'h' can be shadowed.
9938  value = v8_compile("o.h = 3; o.h")->Run();
9939  CHECK_EQ(3, value->Int32Value());
9940
9941  // Check 'i' is cannot be shadowed or changed.
9942  value = v8_compile("o.i = 3; o.i")->Run();
9943  CHECK_EQ(42, value->Int32Value());
9944}
9945
9946
9947static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9948  ApiTestFuzzer::Fuzz();
9949  return v8::Boolean::New(args.IsConstructCall());
9950}
9951
9952
9953THREADED_TEST(IsConstructCall) {
9954  v8::HandleScope scope;
9955
9956  // Function template with call handler.
9957  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9958  templ->SetCallHandler(IsConstructHandler);
9959
9960  LocalContext context;
9961
9962  context->Global()->Set(v8_str("f"), templ->GetFunction());
9963  Local<Value> value = v8_compile("f()")->Run();
9964  CHECK(!value->BooleanValue());
9965  value = v8_compile("new f()")->Run();
9966  CHECK(value->BooleanValue());
9967}
9968
9969
9970THREADED_TEST(ObjectProtoToString) {
9971  v8::HandleScope scope;
9972  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9973  templ->SetClassName(v8_str("MyClass"));
9974
9975  LocalContext context;
9976
9977  Local<String> customized_tostring = v8_str("customized toString");
9978
9979  // Replace Object.prototype.toString
9980  v8_compile("Object.prototype.toString = function() {"
9981                  "  return 'customized toString';"
9982                  "}")->Run();
9983
9984  // Normal ToString call should call replaced Object.prototype.toString
9985  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9986  Local<String> value = instance->ToString();
9987  CHECK(value->IsString() && value->Equals(customized_tostring));
9988
9989  // ObjectProtoToString should not call replace toString function.
9990  value = instance->ObjectProtoToString();
9991  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9992
9993  // Check global
9994  value = context->Global()->ObjectProtoToString();
9995  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9996
9997  // Check ordinary object
9998  Local<Value> object = v8_compile("new Object()")->Run();
9999  value = object.As<v8::Object>()->ObjectProtoToString();
10000  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10001}
10002
10003
10004THREADED_TEST(ObjectGetConstructorName) {
10005  v8::HandleScope scope;
10006  LocalContext context;
10007  v8_compile("function Parent() {};"
10008             "function Child() {};"
10009             "Child.prototype = new Parent();"
10010             "var outer = { inner: function() { } };"
10011             "var p = new Parent();"
10012             "var c = new Child();"
10013             "var x = new outer.inner();")->Run();
10014
10015  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10016  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10017      v8_str("Parent")));
10018
10019  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10020  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10021      v8_str("Child")));
10022
10023  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10024  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10025      v8_str("outer.inner")));
10026}
10027
10028
10029bool ApiTestFuzzer::fuzzing_ = false;
10030i::Semaphore* ApiTestFuzzer::all_tests_done_=
10031  i::OS::CreateSemaphore(0);
10032int ApiTestFuzzer::active_tests_;
10033int ApiTestFuzzer::tests_being_run_;
10034int ApiTestFuzzer::current_;
10035
10036
10037// We are in a callback and want to switch to another thread (if we
10038// are currently running the thread fuzzing test).
10039void ApiTestFuzzer::Fuzz() {
10040  if (!fuzzing_) return;
10041  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10042  test->ContextSwitch();
10043}
10044
10045
10046// Let the next thread go.  Since it is also waiting on the V8 lock it may
10047// not start immediately.
10048bool ApiTestFuzzer::NextThread() {
10049  int test_position = GetNextTestNumber();
10050  const char* test_name = RegisterThreadedTest::nth(current_)->name();
10051  if (test_position == current_) {
10052    if (kLogThreading)
10053      printf("Stay with %s\n", test_name);
10054    return false;
10055  }
10056  if (kLogThreading) {
10057    printf("Switch from %s to %s\n",
10058           test_name,
10059           RegisterThreadedTest::nth(test_position)->name());
10060  }
10061  current_ = test_position;
10062  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10063  return true;
10064}
10065
10066
10067void ApiTestFuzzer::Run() {
10068  // When it is our turn...
10069  gate_->Wait();
10070  {
10071    // ... get the V8 lock and start running the test.
10072    v8::Locker locker;
10073    CallTest();
10074  }
10075  // This test finished.
10076  active_ = false;
10077  active_tests_--;
10078  // If it was the last then signal that fact.
10079  if (active_tests_ == 0) {
10080    all_tests_done_->Signal();
10081  } else {
10082    // Otherwise select a new test and start that.
10083    NextThread();
10084  }
10085}
10086
10087
10088static unsigned linear_congruential_generator;
10089
10090
10091void ApiTestFuzzer::Setup(PartOfTest part) {
10092  linear_congruential_generator = i::FLAG_testing_prng_seed;
10093  fuzzing_ = true;
10094  int count = RegisterThreadedTest::count();
10095  int start =  count * part / (LAST_PART + 1);
10096  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10097  active_tests_ = tests_being_run_ = end - start + 1;
10098  for (int i = 0; i < tests_being_run_; i++) {
10099    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10100  }
10101  for (int i = 0; i < active_tests_; i++) {
10102    RegisterThreadedTest::nth(i)->fuzzer_->Start();
10103  }
10104}
10105
10106
10107static void CallTestNumber(int test_number) {
10108  (RegisterThreadedTest::nth(test_number)->callback())();
10109}
10110
10111
10112void ApiTestFuzzer::RunAllTests() {
10113  // Set off the first test.
10114  current_ = -1;
10115  NextThread();
10116  // Wait till they are all done.
10117  all_tests_done_->Wait();
10118}
10119
10120
10121int ApiTestFuzzer::GetNextTestNumber() {
10122  int next_test;
10123  do {
10124    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10125    linear_congruential_generator *= 1664525u;
10126    linear_congruential_generator += 1013904223u;
10127  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10128  return next_test;
10129}
10130
10131
10132void ApiTestFuzzer::ContextSwitch() {
10133  // If the new thread is the same as the current thread there is nothing to do.
10134  if (NextThread()) {
10135    // Now it can start.
10136    v8::Unlocker unlocker;
10137    // Wait till someone starts us again.
10138    gate_->Wait();
10139    // And we're off.
10140  }
10141}
10142
10143
10144void ApiTestFuzzer::TearDown() {
10145  fuzzing_ = false;
10146  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10147    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10148    if (fuzzer != NULL) fuzzer->Join();
10149  }
10150}
10151
10152
10153// Lets not be needlessly self-referential.
10154TEST(Threading) {
10155  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
10156  ApiTestFuzzer::RunAllTests();
10157  ApiTestFuzzer::TearDown();
10158}
10159
10160TEST(Threading2) {
10161  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
10162  ApiTestFuzzer::RunAllTests();
10163  ApiTestFuzzer::TearDown();
10164}
10165
10166TEST(Threading3) {
10167  ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
10168  ApiTestFuzzer::RunAllTests();
10169  ApiTestFuzzer::TearDown();
10170}
10171
10172TEST(Threading4) {
10173  ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
10174  ApiTestFuzzer::RunAllTests();
10175  ApiTestFuzzer::TearDown();
10176}
10177
10178void ApiTestFuzzer::CallTest() {
10179  if (kLogThreading)
10180    printf("Start test %d\n", test_number_);
10181  CallTestNumber(test_number_);
10182  if (kLogThreading)
10183    printf("End test %d\n", test_number_);
10184}
10185
10186
10187static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10188  CHECK(v8::Locker::IsLocked());
10189  ApiTestFuzzer::Fuzz();
10190  v8::Unlocker unlocker;
10191  const char* code = "throw 7;";
10192  {
10193    v8::Locker nested_locker;
10194    v8::HandleScope scope;
10195    v8::Handle<Value> exception;
10196    { v8::TryCatch try_catch;
10197      v8::Handle<Value> value = CompileRun(code);
10198      CHECK(value.IsEmpty());
10199      CHECK(try_catch.HasCaught());
10200      // Make sure to wrap the exception in a new handle because
10201      // the handle returned from the TryCatch is destroyed
10202      // when the TryCatch is destroyed.
10203      exception = Local<Value>::New(try_catch.Exception());
10204    }
10205    return v8::ThrowException(exception);
10206  }
10207}
10208
10209
10210static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10211  CHECK(v8::Locker::IsLocked());
10212  ApiTestFuzzer::Fuzz();
10213  v8::Unlocker unlocker;
10214  const char* code = "throw 7;";
10215  {
10216    v8::Locker nested_locker;
10217    v8::HandleScope scope;
10218    v8::Handle<Value> value = CompileRun(code);
10219    CHECK(value.IsEmpty());
10220    return v8_str("foo");
10221  }
10222}
10223
10224
10225// These are locking tests that don't need to be run again
10226// as part of the locking aggregation tests.
10227TEST(NestedLockers) {
10228  v8::Locker locker;
10229  CHECK(v8::Locker::IsLocked());
10230  v8::HandleScope scope;
10231  LocalContext env;
10232  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10233  Local<Function> fun = fun_templ->GetFunction();
10234  env->Global()->Set(v8_str("throw_in_js"), fun);
10235  Local<Script> script = v8_compile("(function () {"
10236                                    "  try {"
10237                                    "    throw_in_js();"
10238                                    "    return 42;"
10239                                    "  } catch (e) {"
10240                                    "    return e * 13;"
10241                                    "  }"
10242                                    "})();");
10243  CHECK_EQ(91, script->Run()->Int32Value());
10244}
10245
10246
10247// These are locking tests that don't need to be run again
10248// as part of the locking aggregation tests.
10249TEST(NestedLockersNoTryCatch) {
10250  v8::Locker locker;
10251  v8::HandleScope scope;
10252  LocalContext env;
10253  Local<v8::FunctionTemplate> fun_templ =
10254      v8::FunctionTemplate::New(ThrowInJSNoCatch);
10255  Local<Function> fun = fun_templ->GetFunction();
10256  env->Global()->Set(v8_str("throw_in_js"), fun);
10257  Local<Script> script = v8_compile("(function () {"
10258                                    "  try {"
10259                                    "    throw_in_js();"
10260                                    "    return 42;"
10261                                    "  } catch (e) {"
10262                                    "    return e * 13;"
10263                                    "  }"
10264                                    "})();");
10265  CHECK_EQ(91, script->Run()->Int32Value());
10266}
10267
10268
10269THREADED_TEST(RecursiveLocking) {
10270  v8::Locker locker;
10271  {
10272    v8::Locker locker2;
10273    CHECK(v8::Locker::IsLocked());
10274  }
10275}
10276
10277
10278static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10279  ApiTestFuzzer::Fuzz();
10280  v8::Unlocker unlocker;
10281  return v8::Undefined();
10282}
10283
10284
10285THREADED_TEST(LockUnlockLock) {
10286  {
10287    v8::Locker locker;
10288    v8::HandleScope scope;
10289    LocalContext env;
10290    Local<v8::FunctionTemplate> fun_templ =
10291        v8::FunctionTemplate::New(UnlockForAMoment);
10292    Local<Function> fun = fun_templ->GetFunction();
10293    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10294    Local<Script> script = v8_compile("(function () {"
10295                                      "  unlock_for_a_moment();"
10296                                      "  return 42;"
10297                                      "})();");
10298    CHECK_EQ(42, script->Run()->Int32Value());
10299  }
10300  {
10301    v8::Locker locker;
10302    v8::HandleScope scope;
10303    LocalContext env;
10304    Local<v8::FunctionTemplate> fun_templ =
10305        v8::FunctionTemplate::New(UnlockForAMoment);
10306    Local<Function> fun = fun_templ->GetFunction();
10307    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10308    Local<Script> script = v8_compile("(function () {"
10309                                      "  unlock_for_a_moment();"
10310                                      "  return 42;"
10311                                      "})();");
10312    CHECK_EQ(42, script->Run()->Int32Value());
10313  }
10314}
10315
10316
10317static int GetGlobalObjectsCount() {
10318  i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10319  int count = 0;
10320  i::HeapIterator it;
10321  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10322    if (object->IsJSGlobalObject()) count++;
10323  return count;
10324}
10325
10326
10327static void CheckSurvivingGlobalObjectsCount(int expected) {
10328  // We need to collect all garbage twice to be sure that everything
10329  // has been collected.  This is because inline caches are cleared in
10330  // the first garbage collection but some of the maps have already
10331  // been marked at that point.  Therefore some of the maps are not
10332  // collected until the second garbage collection.
10333  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10334  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10335  int count = GetGlobalObjectsCount();
10336#ifdef DEBUG
10337  if (count != expected) HEAP->TracePathToGlobal();
10338#endif
10339  CHECK_EQ(expected, count);
10340}
10341
10342
10343TEST(DontLeakGlobalObjects) {
10344  // Regression test for issues 1139850 and 1174891.
10345
10346  v8::V8::Initialize();
10347
10348  for (int i = 0; i < 5; i++) {
10349    { v8::HandleScope scope;
10350      LocalContext context;
10351    }
10352    CheckSurvivingGlobalObjectsCount(0);
10353
10354    { v8::HandleScope scope;
10355      LocalContext context;
10356      v8_compile("Date")->Run();
10357    }
10358    CheckSurvivingGlobalObjectsCount(0);
10359
10360    { v8::HandleScope scope;
10361      LocalContext context;
10362      v8_compile("/aaa/")->Run();
10363    }
10364    CheckSurvivingGlobalObjectsCount(0);
10365
10366    { v8::HandleScope scope;
10367      const char* extension_list[] = { "v8/gc" };
10368      v8::ExtensionConfiguration extensions(1, extension_list);
10369      LocalContext context(&extensions);
10370      v8_compile("gc();")->Run();
10371    }
10372    CheckSurvivingGlobalObjectsCount(0);
10373  }
10374}
10375
10376
10377v8::Persistent<v8::Object> some_object;
10378v8::Persistent<v8::Object> bad_handle;
10379
10380void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10381  v8::HandleScope scope;
10382  bad_handle = v8::Persistent<v8::Object>::New(some_object);
10383  handle.Dispose();
10384}
10385
10386
10387THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10388  LocalContext context;
10389
10390  v8::Persistent<v8::Object> handle1, handle2;
10391  {
10392    v8::HandleScope scope;
10393    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10394    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10395    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10396  }
10397  // Note: order is implementation dependent alas: currently
10398  // global handle nodes are processed by PostGarbageCollectionProcessing
10399  // in reverse allocation order, so if second allocated handle is deleted,
10400  // weak callback of the first handle would be able to 'reallocate' it.
10401  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10402  handle2.Dispose();
10403  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10404}
10405
10406
10407v8::Persistent<v8::Object> to_be_disposed;
10408
10409void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10410  to_be_disposed.Dispose();
10411  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10412  handle.Dispose();
10413}
10414
10415
10416THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10417  LocalContext context;
10418
10419  v8::Persistent<v8::Object> handle1, handle2;
10420  {
10421    v8::HandleScope scope;
10422    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10423    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10424  }
10425  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10426  to_be_disposed = handle2;
10427  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10428}
10429
10430void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10431  handle.Dispose();
10432}
10433
10434void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10435  v8::HandleScope scope;
10436  v8::Persistent<v8::Object>::New(v8::Object::New());
10437  handle.Dispose();
10438}
10439
10440
10441THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10442  LocalContext context;
10443
10444  v8::Persistent<v8::Object> handle1, handle2, handle3;
10445  {
10446    v8::HandleScope scope;
10447    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10448    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10449    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10450  }
10451  handle2.MakeWeak(NULL, DisposingCallback);
10452  handle3.MakeWeak(NULL, HandleCreatingCallback);
10453  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10454}
10455
10456
10457THREADED_TEST(CheckForCrossContextObjectLiterals) {
10458  v8::V8::Initialize();
10459
10460  const int nof = 2;
10461  const char* sources[nof] = {
10462    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10463    "Object()"
10464  };
10465
10466  for (int i = 0; i < nof; i++) {
10467    const char* source = sources[i];
10468    { v8::HandleScope scope;
10469      LocalContext context;
10470      CompileRun(source);
10471    }
10472    { v8::HandleScope scope;
10473      LocalContext context;
10474      CompileRun(source);
10475    }
10476  }
10477}
10478
10479
10480static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10481  v8::HandleScope inner;
10482  env->Enter();
10483  v8::Handle<Value> three = v8_num(3);
10484  v8::Handle<Value> value = inner.Close(three);
10485  env->Exit();
10486  return value;
10487}
10488
10489
10490THREADED_TEST(NestedHandleScopeAndContexts) {
10491  v8::HandleScope outer;
10492  v8::Persistent<Context> env = Context::New();
10493  env->Enter();
10494  v8::Handle<Value> value = NestedScope(env);
10495  v8::Handle<String> str(value->ToString());
10496  env->Exit();
10497  env.Dispose();
10498}
10499
10500
10501THREADED_TEST(ExternalAllocatedMemory) {
10502  v8::HandleScope outer;
10503  v8::Persistent<Context> env(Context::New());
10504  const int kSize = 1024*1024;
10505  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10506  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10507}
10508
10509
10510THREADED_TEST(DisposeEnteredContext) {
10511  v8::HandleScope scope;
10512  LocalContext outer;
10513  { v8::Persistent<v8::Context> inner = v8::Context::New();
10514    inner->Enter();
10515    inner.Dispose();
10516    inner.Clear();
10517    inner->Exit();
10518  }
10519}
10520
10521
10522// Regression test for issue 54, object templates with internal fields
10523// but no accessors or interceptors did not get their internal field
10524// count set on instances.
10525THREADED_TEST(Regress54) {
10526  v8::HandleScope outer;
10527  LocalContext context;
10528  static v8::Persistent<v8::ObjectTemplate> templ;
10529  if (templ.IsEmpty()) {
10530    v8::HandleScope inner;
10531    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10532    local->SetInternalFieldCount(1);
10533    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10534  }
10535  v8::Handle<v8::Object> result = templ->NewInstance();
10536  CHECK_EQ(1, result->InternalFieldCount());
10537}
10538
10539
10540// If part of the threaded tests, this test makes ThreadingTest fail
10541// on mac.
10542TEST(CatchStackOverflow) {
10543  v8::HandleScope scope;
10544  LocalContext context;
10545  v8::TryCatch try_catch;
10546  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10547    "function f() {"
10548    "  return f();"
10549    "}"
10550    ""
10551    "f();"));
10552  v8::Handle<v8::Value> result = script->Run();
10553  CHECK(result.IsEmpty());
10554}
10555
10556
10557static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10558                                    const char* resource_name,
10559                                    int line_offset) {
10560  v8::HandleScope scope;
10561  v8::TryCatch try_catch;
10562  v8::Handle<v8::Value> result = script->Run();
10563  CHECK(result.IsEmpty());
10564  CHECK(try_catch.HasCaught());
10565  v8::Handle<v8::Message> message = try_catch.Message();
10566  CHECK(!message.IsEmpty());
10567  CHECK_EQ(10 + line_offset, message->GetLineNumber());
10568  CHECK_EQ(91, message->GetStartPosition());
10569  CHECK_EQ(92, message->GetEndPosition());
10570  CHECK_EQ(2, message->GetStartColumn());
10571  CHECK_EQ(3, message->GetEndColumn());
10572  v8::String::AsciiValue line(message->GetSourceLine());
10573  CHECK_EQ("  throw 'nirk';", *line);
10574  v8::String::AsciiValue name(message->GetScriptResourceName());
10575  CHECK_EQ(resource_name, *name);
10576}
10577
10578
10579THREADED_TEST(TryCatchSourceInfo) {
10580  v8::HandleScope scope;
10581  LocalContext context;
10582  v8::Handle<v8::String> source = v8::String::New(
10583      "function Foo() {\n"
10584      "  return Bar();\n"
10585      "}\n"
10586      "\n"
10587      "function Bar() {\n"
10588      "  return Baz();\n"
10589      "}\n"
10590      "\n"
10591      "function Baz() {\n"
10592      "  throw 'nirk';\n"
10593      "}\n"
10594      "\n"
10595      "Foo();\n");
10596
10597  const char* resource_name;
10598  v8::Handle<v8::Script> script;
10599  resource_name = "test.js";
10600  script = v8::Script::Compile(source, v8::String::New(resource_name));
10601  CheckTryCatchSourceInfo(script, resource_name, 0);
10602
10603  resource_name = "test1.js";
10604  v8::ScriptOrigin origin1(v8::String::New(resource_name));
10605  script = v8::Script::Compile(source, &origin1);
10606  CheckTryCatchSourceInfo(script, resource_name, 0);
10607
10608  resource_name = "test2.js";
10609  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10610  script = v8::Script::Compile(source, &origin2);
10611  CheckTryCatchSourceInfo(script, resource_name, 7);
10612}
10613
10614
10615THREADED_TEST(CompilationCache) {
10616  v8::HandleScope scope;
10617  LocalContext context;
10618  v8::Handle<v8::String> source0 = v8::String::New("1234");
10619  v8::Handle<v8::String> source1 = v8::String::New("1234");
10620  v8::Handle<v8::Script> script0 =
10621      v8::Script::Compile(source0, v8::String::New("test.js"));
10622  v8::Handle<v8::Script> script1 =
10623      v8::Script::Compile(source1, v8::String::New("test.js"));
10624  v8::Handle<v8::Script> script2 =
10625      v8::Script::Compile(source0);  // different origin
10626  CHECK_EQ(1234, script0->Run()->Int32Value());
10627  CHECK_EQ(1234, script1->Run()->Int32Value());
10628  CHECK_EQ(1234, script2->Run()->Int32Value());
10629}
10630
10631
10632static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10633  ApiTestFuzzer::Fuzz();
10634  return v8_num(42);
10635}
10636
10637
10638THREADED_TEST(CallbackFunctionName) {
10639  v8::HandleScope scope;
10640  LocalContext context;
10641  Local<ObjectTemplate> t = ObjectTemplate::New();
10642  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10643  context->Global()->Set(v8_str("obj"), t->NewInstance());
10644  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10645  CHECK(value->IsString());
10646  v8::String::AsciiValue name(value);
10647  CHECK_EQ("asdf", *name);
10648}
10649
10650
10651THREADED_TEST(DateAccess) {
10652  v8::HandleScope scope;
10653  LocalContext context;
10654  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10655  CHECK(date->IsDate());
10656  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
10657}
10658
10659
10660void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
10661  v8::Handle<v8::Object> obj = val.As<v8::Object>();
10662  v8::Handle<v8::Array> props = obj->GetPropertyNames();
10663  CHECK_EQ(elmc, props->Length());
10664  for (int i = 0; i < elmc; i++) {
10665    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10666    CHECK_EQ(elmv[i], *elm);
10667  }
10668}
10669
10670
10671void CheckOwnProperties(v8::Handle<v8::Value> val,
10672                        int elmc,
10673                        const char* elmv[]) {
10674  v8::Handle<v8::Object> obj = val.As<v8::Object>();
10675  v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10676  CHECK_EQ(elmc, props->Length());
10677  for (int i = 0; i < elmc; i++) {
10678    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10679    CHECK_EQ(elmv[i], *elm);
10680  }
10681}
10682
10683
10684THREADED_TEST(PropertyEnumeration) {
10685  v8::HandleScope scope;
10686  LocalContext context;
10687  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10688      "var result = [];"
10689      "result[0] = {};"
10690      "result[1] = {a: 1, b: 2};"
10691      "result[2] = [1, 2, 3];"
10692      "var proto = {x: 1, y: 2, z: 3};"
10693      "var x = { __proto__: proto, w: 0, z: 1 };"
10694      "result[3] = x;"
10695      "result;"))->Run();
10696  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10697  CHECK_EQ(4, elms->Length());
10698  int elmc0 = 0;
10699  const char** elmv0 = NULL;
10700  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10701  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10702  int elmc1 = 2;
10703  const char* elmv1[] = {"a", "b"};
10704  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10705  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10706  int elmc2 = 3;
10707  const char* elmv2[] = {"0", "1", "2"};
10708  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10709  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10710  int elmc3 = 4;
10711  const char* elmv3[] = {"w", "z", "x", "y"};
10712  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
10713  int elmc4 = 2;
10714  const char* elmv4[] = {"w", "z"};
10715  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
10716}
10717
10718THREADED_TEST(PropertyEnumeration2) {
10719  v8::HandleScope scope;
10720  LocalContext context;
10721  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10722      "var result = [];"
10723      "result[0] = {};"
10724      "result[1] = {a: 1, b: 2};"
10725      "result[2] = [1, 2, 3];"
10726      "var proto = {x: 1, y: 2, z: 3};"
10727      "var x = { __proto__: proto, w: 0, z: 1 };"
10728      "result[3] = x;"
10729      "result;"))->Run();
10730  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10731  CHECK_EQ(4, elms->Length());
10732  int elmc0 = 0;
10733  const char** elmv0 = NULL;
10734  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10735
10736  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10737  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10738  CHECK_EQ(0, props->Length());
10739  for (uint32_t i = 0; i < props->Length(); i++) {
10740    printf("p[%d]\n", i);
10741  }
10742}
10743
10744static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10745                                  Local<Value> name,
10746                                  v8::AccessType type,
10747                                  Local<Value> data) {
10748  return type != v8::ACCESS_SET;
10749}
10750
10751
10752static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10753                                    uint32_t key,
10754                                    v8::AccessType type,
10755                                    Local<Value> data) {
10756  return type != v8::ACCESS_SET;
10757}
10758
10759
10760THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10761  v8::HandleScope scope;
10762  LocalContext context;
10763  Local<ObjectTemplate> templ = ObjectTemplate::New();
10764  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10765                                 IndexedSetAccessBlocker);
10766  templ->Set(v8_str("x"), v8::True());
10767  Local<v8::Object> instance = templ->NewInstance();
10768  context->Global()->Set(v8_str("obj"), instance);
10769  Local<Value> value = CompileRun("obj.x");
10770  CHECK(value->BooleanValue());
10771}
10772
10773
10774static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10775                                  Local<Value> name,
10776                                  v8::AccessType type,
10777                                  Local<Value> data) {
10778  return false;
10779}
10780
10781
10782static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10783                                    uint32_t key,
10784                                    v8::AccessType type,
10785                                    Local<Value> data) {
10786  return false;
10787}
10788
10789
10790
10791THREADED_TEST(AccessChecksReenabledCorrectly) {
10792  v8::HandleScope scope;
10793  LocalContext context;
10794  Local<ObjectTemplate> templ = ObjectTemplate::New();
10795  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10796                                 IndexedGetAccessBlocker);
10797  templ->Set(v8_str("a"), v8_str("a"));
10798  // Add more than 8 (see kMaxFastProperties) properties
10799  // so that the constructor will force copying map.
10800  // Cannot sprintf, gcc complains unsafety.
10801  char buf[4];
10802  for (char i = '0'; i <= '9' ; i++) {
10803    buf[0] = i;
10804    for (char j = '0'; j <= '9'; j++) {
10805      buf[1] = j;
10806      for (char k = '0'; k <= '9'; k++) {
10807        buf[2] = k;
10808        buf[3] = 0;
10809        templ->Set(v8_str(buf), v8::Number::New(k));
10810      }
10811    }
10812  }
10813
10814  Local<v8::Object> instance_1 = templ->NewInstance();
10815  context->Global()->Set(v8_str("obj_1"), instance_1);
10816
10817  Local<Value> value_1 = CompileRun("obj_1.a");
10818  CHECK(value_1->IsUndefined());
10819
10820  Local<v8::Object> instance_2 = templ->NewInstance();
10821  context->Global()->Set(v8_str("obj_2"), instance_2);
10822
10823  Local<Value> value_2 = CompileRun("obj_2.a");
10824  CHECK(value_2->IsUndefined());
10825}
10826
10827
10828// This tests that access check information remains on the global
10829// object template when creating contexts.
10830THREADED_TEST(AccessControlRepeatedContextCreation) {
10831  v8::HandleScope handle_scope;
10832  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10833  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10834                                           IndexedSetAccessBlocker);
10835  i::Handle<i::ObjectTemplateInfo> internal_template =
10836      v8::Utils::OpenHandle(*global_template);
10837  CHECK(!internal_template->constructor()->IsUndefined());
10838  i::Handle<i::FunctionTemplateInfo> constructor(
10839      i::FunctionTemplateInfo::cast(internal_template->constructor()));
10840  CHECK(!constructor->access_check_info()->IsUndefined());
10841  v8::Persistent<Context> context0(Context::New(NULL, global_template));
10842  CHECK(!constructor->access_check_info()->IsUndefined());
10843}
10844
10845
10846THREADED_TEST(TurnOnAccessCheck) {
10847  v8::HandleScope handle_scope;
10848
10849  // Create an environment with access check to the global object disabled by
10850  // default.
10851  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10852  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10853                                           IndexedGetAccessBlocker,
10854                                           v8::Handle<v8::Value>(),
10855                                           false);
10856  v8::Persistent<Context> context = Context::New(NULL, global_template);
10857  Context::Scope context_scope(context);
10858
10859  // Set up a property and a number of functions.
10860  context->Global()->Set(v8_str("a"), v8_num(1));
10861  CompileRun("function f1() {return a;}"
10862             "function f2() {return a;}"
10863             "function g1() {return h();}"
10864             "function g2() {return h();}"
10865             "function h() {return 1;}");
10866  Local<Function> f1 =
10867      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10868  Local<Function> f2 =
10869      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10870  Local<Function> g1 =
10871      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10872  Local<Function> g2 =
10873      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10874  Local<Function> h =
10875      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10876
10877  // Get the global object.
10878  v8::Handle<v8::Object> global = context->Global();
10879
10880  // Call f1 one time and f2 a number of times. This will ensure that f1 still
10881  // uses the runtime system to retreive property a whereas f2 uses global load
10882  // inline cache.
10883  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10884  for (int i = 0; i < 4; i++) {
10885    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10886  }
10887
10888  // Same for g1 and g2.
10889  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10890  for (int i = 0; i < 4; i++) {
10891    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10892  }
10893
10894  // Detach the global and turn on access check.
10895  context->DetachGlobal();
10896  context->Global()->TurnOnAccessCheck();
10897
10898  // Failing access check to property get results in undefined.
10899  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10900  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10901
10902  // Failing access check to function call results in exception.
10903  CHECK(g1->Call(global, 0, NULL).IsEmpty());
10904  CHECK(g2->Call(global, 0, NULL).IsEmpty());
10905
10906  // No failing access check when just returning a constant.
10907  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10908}
10909
10910
10911v8::Handle<v8::String> a;
10912v8::Handle<v8::String> h;
10913
10914static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10915                                       Local<Value> name,
10916                                       v8::AccessType type,
10917                                       Local<Value> data) {
10918  return !(name->Equals(a) || name->Equals(h));
10919}
10920
10921
10922THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10923  v8::HandleScope handle_scope;
10924
10925  // Create an environment with access check to the global object disabled by
10926  // default. When the registered access checker will block access to properties
10927  // a and h
10928  a = v8_str("a");
10929  h = v8_str("h");
10930  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10931  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10932                                           IndexedGetAccessBlocker,
10933                                           v8::Handle<v8::Value>(),
10934                                           false);
10935  v8::Persistent<Context> context = Context::New(NULL, global_template);
10936  Context::Scope context_scope(context);
10937
10938  // Set up a property and a number of functions.
10939  context->Global()->Set(v8_str("a"), v8_num(1));
10940  static const char* source = "function f1() {return a;}"
10941                              "function f2() {return a;}"
10942                              "function g1() {return h();}"
10943                              "function g2() {return h();}"
10944                              "function h() {return 1;}";
10945
10946  CompileRun(source);
10947  Local<Function> f1;
10948  Local<Function> f2;
10949  Local<Function> g1;
10950  Local<Function> g2;
10951  Local<Function> h;
10952  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10953  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10954  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10955  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10956  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10957
10958  // Get the global object.
10959  v8::Handle<v8::Object> global = context->Global();
10960
10961  // Call f1 one time and f2 a number of times. This will ensure that f1 still
10962  // uses the runtime system to retreive property a whereas f2 uses global load
10963  // inline cache.
10964  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10965  for (int i = 0; i < 4; i++) {
10966    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10967  }
10968
10969  // Same for g1 and g2.
10970  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10971  for (int i = 0; i < 4; i++) {
10972    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10973  }
10974
10975  // Detach the global and turn on access check now blocking access to property
10976  // a and function h.
10977  context->DetachGlobal();
10978  context->Global()->TurnOnAccessCheck();
10979
10980  // Failing access check to property get results in undefined.
10981  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10982  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10983
10984  // Failing access check to function call results in exception.
10985  CHECK(g1->Call(global, 0, NULL).IsEmpty());
10986  CHECK(g2->Call(global, 0, NULL).IsEmpty());
10987
10988  // No failing access check when just returning a constant.
10989  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10990
10991  // Now compile the source again. And get the newly compiled functions, except
10992  // for h for which access is blocked.
10993  CompileRun(source);
10994  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10995  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10996  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10997  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10998  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10999
11000  // Failing access check to property get results in undefined.
11001  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11002  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11003
11004  // Failing access check to function call results in exception.
11005  CHECK(g1->Call(global, 0, NULL).IsEmpty());
11006  CHECK(g2->Call(global, 0, NULL).IsEmpty());
11007}
11008
11009
11010// This test verifies that pre-compilation (aka preparsing) can be called
11011// without initializing the whole VM. Thus we cannot run this test in a
11012// multi-threaded setup.
11013TEST(PreCompile) {
11014  // TODO(155): This test would break without the initialization of V8. This is
11015  // a workaround for now to make this test not fail.
11016  v8::V8::Initialize();
11017  const char* script = "function foo(a) { return a+1; }";
11018  v8::ScriptData* sd =
11019      v8::ScriptData::PreCompile(script, i::StrLength(script));
11020  CHECK_NE(sd->Length(), 0);
11021  CHECK_NE(sd->Data(), NULL);
11022  CHECK(!sd->HasError());
11023  delete sd;
11024}
11025
11026
11027TEST(PreCompileWithError) {
11028  v8::V8::Initialize();
11029  const char* script = "function foo(a) { return 1 * * 2; }";
11030  v8::ScriptData* sd =
11031      v8::ScriptData::PreCompile(script, i::StrLength(script));
11032  CHECK(sd->HasError());
11033  delete sd;
11034}
11035
11036
11037TEST(Regress31661) {
11038  v8::V8::Initialize();
11039  const char* script = " The Definintive Guide";
11040  v8::ScriptData* sd =
11041      v8::ScriptData::PreCompile(script, i::StrLength(script));
11042  CHECK(sd->HasError());
11043  delete sd;
11044}
11045
11046
11047// Tests that ScriptData can be serialized and deserialized.
11048TEST(PreCompileSerialization) {
11049  v8::V8::Initialize();
11050  const char* script = "function foo(a) { return a+1; }";
11051  v8::ScriptData* sd =
11052      v8::ScriptData::PreCompile(script, i::StrLength(script));
11053
11054  // Serialize.
11055  int serialized_data_length = sd->Length();
11056  char* serialized_data = i::NewArray<char>(serialized_data_length);
11057  memcpy(serialized_data, sd->Data(), serialized_data_length);
11058
11059  // Deserialize.
11060  v8::ScriptData* deserialized_sd =
11061      v8::ScriptData::New(serialized_data, serialized_data_length);
11062
11063  // Verify that the original is the same as the deserialized.
11064  CHECK_EQ(sd->Length(), deserialized_sd->Length());
11065  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11066  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11067
11068  delete sd;
11069  delete deserialized_sd;
11070}
11071
11072
11073// Attempts to deserialize bad data.
11074TEST(PreCompileDeserializationError) {
11075  v8::V8::Initialize();
11076  const char* data = "DONT CARE";
11077  int invalid_size = 3;
11078  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11079
11080  CHECK_EQ(0, sd->Length());
11081
11082  delete sd;
11083}
11084
11085
11086// Attempts to deserialize bad data.
11087TEST(PreCompileInvalidPreparseDataError) {
11088  v8::V8::Initialize();
11089  v8::HandleScope scope;
11090  LocalContext context;
11091
11092  const char* script = "function foo(){ return 5;}\n"
11093      "function bar(){ return 6 + 7;}  foo();";
11094  v8::ScriptData* sd =
11095      v8::ScriptData::PreCompile(script, i::StrLength(script));
11096  CHECK(!sd->HasError());
11097  // ScriptDataImpl private implementation details
11098  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11099  const int kFunctionEntrySize = i::FunctionEntry::kSize;
11100  const int kFunctionEntryStartOffset = 0;
11101  const int kFunctionEntryEndOffset = 1;
11102  unsigned* sd_data =
11103      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11104
11105  // Overwrite function bar's end position with 0.
11106  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11107  v8::TryCatch try_catch;
11108
11109  Local<String> source = String::New(script);
11110  Local<Script> compiled_script = Script::New(source, NULL, sd);
11111  CHECK(try_catch.HasCaught());
11112  String::AsciiValue exception_value(try_catch.Message()->Get());
11113  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11114           *exception_value);
11115
11116  try_catch.Reset();
11117
11118  // Overwrite function bar's start position with 200.  The function entry
11119  // will not be found when searching for it by position and we should fall
11120  // back on eager compilation.
11121  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11122  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11123  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11124      200;
11125  compiled_script = Script::New(source, NULL, sd);
11126  CHECK(!try_catch.HasCaught());
11127
11128  delete sd;
11129}
11130
11131
11132// Verifies that the Handle<String> and const char* versions of the API produce
11133// the same results (at least for one trivial case).
11134TEST(PreCompileAPIVariationsAreSame) {
11135  v8::V8::Initialize();
11136  v8::HandleScope scope;
11137
11138  const char* cstring = "function foo(a) { return a+1; }";
11139
11140  v8::ScriptData* sd_from_cstring =
11141      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11142
11143  TestAsciiResource* resource = new TestAsciiResource(cstring);
11144  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
11145      v8::String::NewExternal(resource));
11146
11147  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11148      v8::String::New(cstring));
11149
11150  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
11151  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11152                     sd_from_external_string->Data(),
11153                     sd_from_cstring->Length()));
11154
11155  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11156  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11157                     sd_from_string->Data(),
11158                     sd_from_cstring->Length()));
11159
11160
11161  delete sd_from_cstring;
11162  delete sd_from_external_string;
11163  delete sd_from_string;
11164}
11165
11166
11167// This tests that we do not allow dictionary load/call inline caches
11168// to use functions that have not yet been compiled.  The potential
11169// problem of loading a function that has not yet been compiled can
11170// arise because we share code between contexts via the compilation
11171// cache.
11172THREADED_TEST(DictionaryICLoadedFunction) {
11173  v8::HandleScope scope;
11174  // Test LoadIC.
11175  for (int i = 0; i < 2; i++) {
11176    LocalContext context;
11177    context->Global()->Set(v8_str("tmp"), v8::True());
11178    context->Global()->Delete(v8_str("tmp"));
11179    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11180  }
11181  // Test CallIC.
11182  for (int i = 0; i < 2; i++) {
11183    LocalContext context;
11184    context->Global()->Set(v8_str("tmp"), v8::True());
11185    context->Global()->Delete(v8_str("tmp"));
11186    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11187  }
11188}
11189
11190
11191// Test that cross-context new calls use the context of the callee to
11192// create the new JavaScript object.
11193THREADED_TEST(CrossContextNew) {
11194  v8::HandleScope scope;
11195  v8::Persistent<Context> context0 = Context::New();
11196  v8::Persistent<Context> context1 = Context::New();
11197
11198  // Allow cross-domain access.
11199  Local<String> token = v8_str("<security token>");
11200  context0->SetSecurityToken(token);
11201  context1->SetSecurityToken(token);
11202
11203  // Set an 'x' property on the Object prototype and define a
11204  // constructor function in context0.
11205  context0->Enter();
11206  CompileRun("Object.prototype.x = 42; function C() {};");
11207  context0->Exit();
11208
11209  // Call the constructor function from context0 and check that the
11210  // result has the 'x' property.
11211  context1->Enter();
11212  context1->Global()->Set(v8_str("other"), context0->Global());
11213  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11214  CHECK(value->IsInt32());
11215  CHECK_EQ(42, value->Int32Value());
11216  context1->Exit();
11217
11218  // Dispose the contexts to allow them to be garbage collected.
11219  context0.Dispose();
11220  context1.Dispose();
11221}
11222
11223
11224class RegExpInterruptTest {
11225 public:
11226  RegExpInterruptTest() : block_(NULL) {}
11227  ~RegExpInterruptTest() { delete block_; }
11228  void RunTest() {
11229    block_ = i::OS::CreateSemaphore(0);
11230    gc_count_ = 0;
11231    gc_during_regexp_ = 0;
11232    regexp_success_ = false;
11233    gc_success_ = false;
11234    GCThread gc_thread(this);
11235    gc_thread.Start();
11236    v8::Locker::StartPreemption(1);
11237
11238    LongRunningRegExp();
11239    {
11240      v8::Unlocker unlock;
11241      gc_thread.Join();
11242    }
11243    v8::Locker::StopPreemption();
11244    CHECK(regexp_success_);
11245    CHECK(gc_success_);
11246  }
11247
11248 private:
11249  // Number of garbage collections required.
11250  static const int kRequiredGCs = 5;
11251
11252  class GCThread : public i::Thread {
11253   public:
11254    explicit GCThread(RegExpInterruptTest* test)
11255        : Thread("GCThread"), test_(test) {}
11256    virtual void Run() {
11257      test_->CollectGarbage();
11258    }
11259   private:
11260     RegExpInterruptTest* test_;
11261  };
11262
11263  void CollectGarbage() {
11264    block_->Wait();
11265    while (gc_during_regexp_ < kRequiredGCs) {
11266      {
11267        v8::Locker lock;
11268        // TODO(lrn): Perhaps create some garbage before collecting.
11269        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11270        gc_count_++;
11271      }
11272      i::OS::Sleep(1);
11273    }
11274    gc_success_ = true;
11275  }
11276
11277  void LongRunningRegExp() {
11278    block_->Signal();  // Enable garbage collection thread on next preemption.
11279    int rounds = 0;
11280    while (gc_during_regexp_ < kRequiredGCs) {
11281      int gc_before = gc_count_;
11282      {
11283        // Match 15-30 "a"'s against 14 and a "b".
11284        const char* c_source =
11285            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11286            ".exec('aaaaaaaaaaaaaaab') === null";
11287        Local<String> source = String::New(c_source);
11288        Local<Script> script = Script::Compile(source);
11289        Local<Value> result = script->Run();
11290        if (!result->BooleanValue()) {
11291          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
11292          return;
11293        }
11294      }
11295      {
11296        // Match 15-30 "a"'s against 15 and a "b".
11297        const char* c_source =
11298            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11299            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11300        Local<String> source = String::New(c_source);
11301        Local<Script> script = Script::Compile(source);
11302        Local<Value> result = script->Run();
11303        if (!result->BooleanValue()) {
11304          gc_during_regexp_ = kRequiredGCs;
11305          return;
11306        }
11307      }
11308      int gc_after = gc_count_;
11309      gc_during_regexp_ += gc_after - gc_before;
11310      rounds++;
11311      i::OS::Sleep(1);
11312    }
11313    regexp_success_ = true;
11314  }
11315
11316  i::Semaphore* block_;
11317  int gc_count_;
11318  int gc_during_regexp_;
11319  bool regexp_success_;
11320  bool gc_success_;
11321};
11322
11323
11324// Test that a regular expression execution can be interrupted and
11325// survive a garbage collection.
11326TEST(RegExpInterruption) {
11327  v8::Locker lock;
11328  v8::V8::Initialize();
11329  v8::HandleScope scope;
11330  Local<Context> local_env;
11331  {
11332    LocalContext env;
11333    local_env = env.local();
11334  }
11335
11336  // Local context should still be live.
11337  CHECK(!local_env.IsEmpty());
11338  local_env->Enter();
11339
11340  // Should complete without problems.
11341  RegExpInterruptTest().RunTest();
11342
11343  local_env->Exit();
11344}
11345
11346
11347class ApplyInterruptTest {
11348 public:
11349  ApplyInterruptTest() : block_(NULL) {}
11350  ~ApplyInterruptTest() { delete block_; }
11351  void RunTest() {
11352    block_ = i::OS::CreateSemaphore(0);
11353    gc_count_ = 0;
11354    gc_during_apply_ = 0;
11355    apply_success_ = false;
11356    gc_success_ = false;
11357    GCThread gc_thread(this);
11358    gc_thread.Start();
11359    v8::Locker::StartPreemption(1);
11360
11361    LongRunningApply();
11362    {
11363      v8::Unlocker unlock;
11364      gc_thread.Join();
11365    }
11366    v8::Locker::StopPreemption();
11367    CHECK(apply_success_);
11368    CHECK(gc_success_);
11369  }
11370
11371 private:
11372  // Number of garbage collections required.
11373  static const int kRequiredGCs = 2;
11374
11375  class GCThread : public i::Thread {
11376   public:
11377    explicit GCThread(ApplyInterruptTest* test)
11378        : Thread("GCThread"), test_(test) {}
11379    virtual void Run() {
11380      test_->CollectGarbage();
11381    }
11382   private:
11383     ApplyInterruptTest* test_;
11384  };
11385
11386  void CollectGarbage() {
11387    block_->Wait();
11388    while (gc_during_apply_ < kRequiredGCs) {
11389      {
11390        v8::Locker lock;
11391        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11392        gc_count_++;
11393      }
11394      i::OS::Sleep(1);
11395    }
11396    gc_success_ = true;
11397  }
11398
11399  void LongRunningApply() {
11400    block_->Signal();
11401    int rounds = 0;
11402    while (gc_during_apply_ < kRequiredGCs) {
11403      int gc_before = gc_count_;
11404      {
11405        const char* c_source =
11406            "function do_very_little(bar) {"
11407            "  this.foo = bar;"
11408            "}"
11409            "for (var i = 0; i < 100000; i++) {"
11410            "  do_very_little.apply(this, ['bar']);"
11411            "}";
11412        Local<String> source = String::New(c_source);
11413        Local<Script> script = Script::Compile(source);
11414        Local<Value> result = script->Run();
11415        // Check that no exception was thrown.
11416        CHECK(!result.IsEmpty());
11417      }
11418      int gc_after = gc_count_;
11419      gc_during_apply_ += gc_after - gc_before;
11420      rounds++;
11421    }
11422    apply_success_ = true;
11423  }
11424
11425  i::Semaphore* block_;
11426  int gc_count_;
11427  int gc_during_apply_;
11428  bool apply_success_;
11429  bool gc_success_;
11430};
11431
11432
11433// Test that nothing bad happens if we get a preemption just when we were
11434// about to do an apply().
11435TEST(ApplyInterruption) {
11436  v8::Locker lock;
11437  v8::V8::Initialize();
11438  v8::HandleScope scope;
11439  Local<Context> local_env;
11440  {
11441    LocalContext env;
11442    local_env = env.local();
11443  }
11444
11445  // Local context should still be live.
11446  CHECK(!local_env.IsEmpty());
11447  local_env->Enter();
11448
11449  // Should complete without problems.
11450  ApplyInterruptTest().RunTest();
11451
11452  local_env->Exit();
11453}
11454
11455
11456// Verify that we can clone an object
11457TEST(ObjectClone) {
11458  v8::HandleScope scope;
11459  LocalContext env;
11460
11461  const char* sample =
11462    "var rv = {};"      \
11463    "rv.alpha = 'hello';" \
11464    "rv.beta = 123;"     \
11465    "rv;";
11466
11467  // Create an object, verify basics.
11468  Local<Value> val = CompileRun(sample);
11469  CHECK(val->IsObject());
11470  Local<v8::Object> obj = val.As<v8::Object>();
11471  obj->Set(v8_str("gamma"), v8_str("cloneme"));
11472
11473  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11474  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11475  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11476
11477  // Clone it.
11478  Local<v8::Object> clone = obj->Clone();
11479  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11480  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11481  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11482
11483  // Set a property on the clone, verify each object.
11484  clone->Set(v8_str("beta"), v8::Integer::New(456));
11485  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11486  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11487}
11488
11489
11490class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11491 public:
11492  explicit AsciiVectorResource(i::Vector<const char> vector)
11493      : data_(vector) {}
11494  virtual ~AsciiVectorResource() {}
11495  virtual size_t length() const { return data_.length(); }
11496  virtual const char* data() const { return data_.start(); }
11497 private:
11498  i::Vector<const char> data_;
11499};
11500
11501
11502class UC16VectorResource : public v8::String::ExternalStringResource {
11503 public:
11504  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11505      : data_(vector) {}
11506  virtual ~UC16VectorResource() {}
11507  virtual size_t length() const { return data_.length(); }
11508  virtual const i::uc16* data() const { return data_.start(); }
11509 private:
11510  i::Vector<const i::uc16> data_;
11511};
11512
11513
11514static void MorphAString(i::String* string,
11515                         AsciiVectorResource* ascii_resource,
11516                         UC16VectorResource* uc16_resource) {
11517  CHECK(i::StringShape(string).IsExternal());
11518  if (string->IsAsciiRepresentation()) {
11519    // Check old map is not symbol or long.
11520    CHECK(string->map() == HEAP->external_ascii_string_map());
11521    // Morph external string to be TwoByte string.
11522    string->set_map(HEAP->external_string_map());
11523    i::ExternalTwoByteString* morphed =
11524         i::ExternalTwoByteString::cast(string);
11525    morphed->set_resource(uc16_resource);
11526  } else {
11527    // Check old map is not symbol or long.
11528    CHECK(string->map() == HEAP->external_string_map());
11529    // Morph external string to be ASCII string.
11530    string->set_map(HEAP->external_ascii_string_map());
11531    i::ExternalAsciiString* morphed =
11532         i::ExternalAsciiString::cast(string);
11533    morphed->set_resource(ascii_resource);
11534  }
11535}
11536
11537
11538// Test that we can still flatten a string if the components it is built up
11539// from have been turned into 16 bit strings in the mean time.
11540THREADED_TEST(MorphCompositeStringTest) {
11541  char utf_buffer[129];
11542  const char* c_string = "Now is the time for all good men"
11543                         " to come to the aid of the party";
11544  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11545  {
11546    v8::HandleScope scope;
11547    LocalContext env;
11548    AsciiVectorResource ascii_resource(
11549        i::Vector<const char>(c_string, i::StrLength(c_string)));
11550    UC16VectorResource uc16_resource(
11551        i::Vector<const uint16_t>(two_byte_string,
11552                                  i::StrLength(c_string)));
11553
11554    Local<String> lhs(v8::Utils::ToLocal(
11555        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11556    Local<String> rhs(v8::Utils::ToLocal(
11557        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11558
11559    env->Global()->Set(v8_str("lhs"), lhs);
11560    env->Global()->Set(v8_str("rhs"), rhs);
11561
11562    CompileRun(
11563        "var cons = lhs + rhs;"
11564        "var slice = lhs.substring(1, lhs.length - 1);"
11565        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11566
11567    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11568    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11569
11570    // This should UTF-8 without flattening, since everything is ASCII.
11571    Handle<String> cons = v8_compile("cons")->Run().As<String>();
11572    CHECK_EQ(128, cons->Utf8Length());
11573    int nchars = -1;
11574    CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11575    CHECK_EQ(128, nchars);
11576    CHECK_EQ(0, strcmp(
11577        utf_buffer,
11578        "Now is the time for all good men to come to the aid of the party"
11579        "Now is the time for all good men to come to the aid of the party"));
11580
11581    // Now do some stuff to make sure the strings are flattened, etc.
11582    CompileRun(
11583        "/[^a-z]/.test(cons);"
11584        "/[^a-z]/.test(slice);"
11585        "/[^a-z]/.test(slice_on_cons);");
11586    const char* expected_cons =
11587        "Now is the time for all good men to come to the aid of the party"
11588        "Now is the time for all good men to come to the aid of the party";
11589    const char* expected_slice =
11590        "ow is the time for all good men to come to the aid of the part";
11591    const char* expected_slice_on_cons =
11592        "ow is the time for all good men to come to the aid of the party"
11593        "Now is the time for all good men to come to the aid of the part";
11594    CHECK_EQ(String::New(expected_cons),
11595             env->Global()->Get(v8_str("cons")));
11596    CHECK_EQ(String::New(expected_slice),
11597             env->Global()->Get(v8_str("slice")));
11598    CHECK_EQ(String::New(expected_slice_on_cons),
11599             env->Global()->Get(v8_str("slice_on_cons")));
11600  }
11601  i::DeleteArray(two_byte_string);
11602}
11603
11604
11605TEST(CompileExternalTwoByteSource) {
11606  v8::HandleScope scope;
11607  LocalContext context;
11608
11609  // This is a very short list of sources, which currently is to check for a
11610  // regression caused by r2703.
11611  const char* ascii_sources[] = {
11612    "0.5",
11613    "-0.5",   // This mainly testes PushBack in the Scanner.
11614    "--0.5",  // This mainly testes PushBack in the Scanner.
11615    NULL
11616  };
11617
11618  // Compile the sources as external two byte strings.
11619  for (int i = 0; ascii_sources[i] != NULL; i++) {
11620    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11621    UC16VectorResource uc16_resource(
11622        i::Vector<const uint16_t>(two_byte_string,
11623                                  i::StrLength(ascii_sources[i])));
11624    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11625    v8::Script::Compile(source);
11626    i::DeleteArray(two_byte_string);
11627  }
11628}
11629
11630
11631class RegExpStringModificationTest {
11632 public:
11633  RegExpStringModificationTest()
11634      : block_(i::OS::CreateSemaphore(0)),
11635        morphs_(0),
11636        morphs_during_regexp_(0),
11637        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11638        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11639  ~RegExpStringModificationTest() { delete block_; }
11640  void RunTest() {
11641    regexp_success_ = false;
11642    morph_success_ = false;
11643
11644    // Initialize the contents of two_byte_content_ to be a uc16 representation
11645    // of "aaaaaaaaaaaaaab".
11646    for (int i = 0; i < 14; i++) {
11647      two_byte_content_[i] = 'a';
11648    }
11649    two_byte_content_[14] = 'b';
11650
11651    // Create the input string for the regexp - the one we are going to change
11652    // properties of.
11653    input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
11654
11655    // Inject the input as a global variable.
11656    i::Handle<i::String> input_name =
11657        FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11658    i::Isolate::Current()->global_context()->global()->SetProperty(
11659        *input_name,
11660        *input_,
11661        NONE,
11662        i::kNonStrictMode)->ToObjectChecked();
11663
11664    MorphThread morph_thread(this);
11665    morph_thread.Start();
11666    v8::Locker::StartPreemption(1);
11667    LongRunningRegExp();
11668    {
11669      v8::Unlocker unlock;
11670      morph_thread.Join();
11671    }
11672    v8::Locker::StopPreemption();
11673    CHECK(regexp_success_);
11674    CHECK(morph_success_);
11675  }
11676
11677 private:
11678  // Number of string modifications required.
11679  static const int kRequiredModifications = 5;
11680  static const int kMaxModifications = 100;
11681
11682  class MorphThread : public i::Thread {
11683   public:
11684    explicit MorphThread(RegExpStringModificationTest* test)
11685        : Thread("MorphThread"), test_(test) {}
11686    virtual void Run() {
11687      test_->MorphString();
11688    }
11689   private:
11690     RegExpStringModificationTest* test_;
11691  };
11692
11693  void MorphString() {
11694    block_->Wait();
11695    while (morphs_during_regexp_ < kRequiredModifications &&
11696           morphs_ < kMaxModifications) {
11697      {
11698        v8::Locker lock;
11699        // Swap string between ascii and two-byte representation.
11700        i::String* string = *input_;
11701        MorphAString(string, &ascii_resource_, &uc16_resource_);
11702        morphs_++;
11703      }
11704      i::OS::Sleep(1);
11705    }
11706    morph_success_ = true;
11707  }
11708
11709  void LongRunningRegExp() {
11710    block_->Signal();  // Enable morphing thread on next preemption.
11711    while (morphs_during_regexp_ < kRequiredModifications &&
11712           morphs_ < kMaxModifications) {
11713      int morphs_before = morphs_;
11714      {
11715        v8::HandleScope scope;
11716        // Match 15-30 "a"'s against 14 and a "b".
11717        const char* c_source =
11718            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11719            ".exec(input) === null";
11720        Local<String> source = String::New(c_source);
11721        Local<Script> script = Script::Compile(source);
11722        Local<Value> result = script->Run();
11723        CHECK(result->IsTrue());
11724      }
11725      int morphs_after = morphs_;
11726      morphs_during_regexp_ += morphs_after - morphs_before;
11727    }
11728    regexp_success_ = true;
11729  }
11730
11731  i::uc16 two_byte_content_[15];
11732  i::Semaphore* block_;
11733  int morphs_;
11734  int morphs_during_regexp_;
11735  bool regexp_success_;
11736  bool morph_success_;
11737  i::Handle<i::String> input_;
11738  AsciiVectorResource ascii_resource_;
11739  UC16VectorResource uc16_resource_;
11740};
11741
11742
11743// Test that a regular expression execution can be interrupted and
11744// the string changed without failing.
11745TEST(RegExpStringModification) {
11746  v8::Locker lock;
11747  v8::V8::Initialize();
11748  v8::HandleScope scope;
11749  Local<Context> local_env;
11750  {
11751    LocalContext env;
11752    local_env = env.local();
11753  }
11754
11755  // Local context should still be live.
11756  CHECK(!local_env.IsEmpty());
11757  local_env->Enter();
11758
11759  // Should complete without problems.
11760  RegExpStringModificationTest().RunTest();
11761
11762  local_env->Exit();
11763}
11764
11765
11766// Test that we can set a property on the global object even if there
11767// is a read-only property in the prototype chain.
11768TEST(ReadOnlyPropertyInGlobalProto) {
11769  v8::HandleScope scope;
11770  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11771  LocalContext context(0, templ);
11772  v8::Handle<v8::Object> global = context->Global();
11773  v8::Handle<v8::Object> global_proto =
11774      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11775  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11776  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11777  // Check without 'eval' or 'with'.
11778  v8::Handle<v8::Value> res =
11779      CompileRun("function f() { x = 42; return x; }; f()");
11780  // Check with 'eval'.
11781  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11782  CHECK_EQ(v8::Integer::New(42), res);
11783  // Check with 'with'.
11784  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11785  CHECK_EQ(v8::Integer::New(42), res);
11786}
11787
11788static int force_set_set_count = 0;
11789static int force_set_get_count = 0;
11790bool pass_on_get = false;
11791
11792static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11793                                            const v8::AccessorInfo& info) {
11794  force_set_get_count++;
11795  if (pass_on_get) {
11796    return v8::Handle<v8::Value>();
11797  } else {
11798    return v8::Int32::New(3);
11799  }
11800}
11801
11802static void ForceSetSetter(v8::Local<v8::String> name,
11803                           v8::Local<v8::Value> value,
11804                           const v8::AccessorInfo& info) {
11805  force_set_set_count++;
11806}
11807
11808static v8::Handle<v8::Value> ForceSetInterceptSetter(
11809    v8::Local<v8::String> name,
11810    v8::Local<v8::Value> value,
11811    const v8::AccessorInfo& info) {
11812  force_set_set_count++;
11813  return v8::Undefined();
11814}
11815
11816TEST(ForceSet) {
11817  force_set_get_count = 0;
11818  force_set_set_count = 0;
11819  pass_on_get = false;
11820
11821  v8::HandleScope scope;
11822  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11823  v8::Handle<v8::String> access_property = v8::String::New("a");
11824  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11825  LocalContext context(NULL, templ);
11826  v8::Handle<v8::Object> global = context->Global();
11827
11828  // Ordinary properties
11829  v8::Handle<v8::String> simple_property = v8::String::New("p");
11830  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11831  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11832  // This should fail because the property is read-only
11833  global->Set(simple_property, v8::Int32::New(5));
11834  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11835  // This should succeed even though the property is read-only
11836  global->ForceSet(simple_property, v8::Int32::New(6));
11837  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11838
11839  // Accessors
11840  CHECK_EQ(0, force_set_set_count);
11841  CHECK_EQ(0, force_set_get_count);
11842  CHECK_EQ(3, global->Get(access_property)->Int32Value());
11843  // CHECK_EQ the property shouldn't override it, just call the setter
11844  // which in this case does nothing.
11845  global->Set(access_property, v8::Int32::New(7));
11846  CHECK_EQ(3, global->Get(access_property)->Int32Value());
11847  CHECK_EQ(1, force_set_set_count);
11848  CHECK_EQ(2, force_set_get_count);
11849  // Forcing the property to be set should override the accessor without
11850  // calling it
11851  global->ForceSet(access_property, v8::Int32::New(8));
11852  CHECK_EQ(8, global->Get(access_property)->Int32Value());
11853  CHECK_EQ(1, force_set_set_count);
11854  CHECK_EQ(2, force_set_get_count);
11855}
11856
11857TEST(ForceSetWithInterceptor) {
11858  force_set_get_count = 0;
11859  force_set_set_count = 0;
11860  pass_on_get = false;
11861
11862  v8::HandleScope scope;
11863  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11864  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11865  LocalContext context(NULL, templ);
11866  v8::Handle<v8::Object> global = context->Global();
11867
11868  v8::Handle<v8::String> some_property = v8::String::New("a");
11869  CHECK_EQ(0, force_set_set_count);
11870  CHECK_EQ(0, force_set_get_count);
11871  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11872  // Setting the property shouldn't override it, just call the setter
11873  // which in this case does nothing.
11874  global->Set(some_property, v8::Int32::New(7));
11875  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11876  CHECK_EQ(1, force_set_set_count);
11877  CHECK_EQ(2, force_set_get_count);
11878  // Getting the property when the interceptor returns an empty handle
11879  // should yield undefined, since the property isn't present on the
11880  // object itself yet.
11881  pass_on_get = true;
11882  CHECK(global->Get(some_property)->IsUndefined());
11883  CHECK_EQ(1, force_set_set_count);
11884  CHECK_EQ(3, force_set_get_count);
11885  // Forcing the property to be set should cause the value to be
11886  // set locally without calling the interceptor.
11887  global->ForceSet(some_property, v8::Int32::New(8));
11888  CHECK_EQ(8, global->Get(some_property)->Int32Value());
11889  CHECK_EQ(1, force_set_set_count);
11890  CHECK_EQ(4, force_set_get_count);
11891  // Reenabling the interceptor should cause it to take precedence over
11892  // the property
11893  pass_on_get = false;
11894  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11895  CHECK_EQ(1, force_set_set_count);
11896  CHECK_EQ(5, force_set_get_count);
11897  // The interceptor should also work for other properties
11898  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11899  CHECK_EQ(1, force_set_set_count);
11900  CHECK_EQ(6, force_set_get_count);
11901}
11902
11903
11904THREADED_TEST(ForceDelete) {
11905  v8::HandleScope scope;
11906  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11907  LocalContext context(NULL, templ);
11908  v8::Handle<v8::Object> global = context->Global();
11909
11910  // Ordinary properties
11911  v8::Handle<v8::String> simple_property = v8::String::New("p");
11912  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11913  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11914  // This should fail because the property is dont-delete.
11915  CHECK(!global->Delete(simple_property));
11916  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11917  // This should succeed even though the property is dont-delete.
11918  CHECK(global->ForceDelete(simple_property));
11919  CHECK(global->Get(simple_property)->IsUndefined());
11920}
11921
11922
11923static int force_delete_interceptor_count = 0;
11924static bool pass_on_delete = false;
11925
11926
11927static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11928    v8::Local<v8::String> name,
11929    const v8::AccessorInfo& info) {
11930  force_delete_interceptor_count++;
11931  if (pass_on_delete) {
11932    return v8::Handle<v8::Boolean>();
11933  } else {
11934    return v8::True();
11935  }
11936}
11937
11938
11939THREADED_TEST(ForceDeleteWithInterceptor) {
11940  force_delete_interceptor_count = 0;
11941  pass_on_delete = false;
11942
11943  v8::HandleScope scope;
11944  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11945  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11946  LocalContext context(NULL, templ);
11947  v8::Handle<v8::Object> global = context->Global();
11948
11949  v8::Handle<v8::String> some_property = v8::String::New("a");
11950  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11951
11952  // Deleting a property should get intercepted and nothing should
11953  // happen.
11954  CHECK_EQ(0, force_delete_interceptor_count);
11955  CHECK(global->Delete(some_property));
11956  CHECK_EQ(1, force_delete_interceptor_count);
11957  CHECK_EQ(42, global->Get(some_property)->Int32Value());
11958  // Deleting the property when the interceptor returns an empty
11959  // handle should not delete the property since it is DontDelete.
11960  pass_on_delete = true;
11961  CHECK(!global->Delete(some_property));
11962  CHECK_EQ(2, force_delete_interceptor_count);
11963  CHECK_EQ(42, global->Get(some_property)->Int32Value());
11964  // Forcing the property to be deleted should delete the value
11965  // without calling the interceptor.
11966  CHECK(global->ForceDelete(some_property));
11967  CHECK(global->Get(some_property)->IsUndefined());
11968  CHECK_EQ(2, force_delete_interceptor_count);
11969}
11970
11971
11972// Make sure that forcing a delete invalidates any IC stubs, so we
11973// don't read the hole value.
11974THREADED_TEST(ForceDeleteIC) {
11975  v8::HandleScope scope;
11976  LocalContext context;
11977  // Create a DontDelete variable on the global object.
11978  CompileRun("this.__proto__ = { foo: 'horse' };"
11979             "var foo = 'fish';"
11980             "function f() { return foo.length; }");
11981  // Initialize the IC for foo in f.
11982  CompileRun("for (var i = 0; i < 4; i++) f();");
11983  // Make sure the value of foo is correct before the deletion.
11984  CHECK_EQ(4, CompileRun("f()")->Int32Value());
11985  // Force the deletion of foo.
11986  CHECK(context->Global()->ForceDelete(v8_str("foo")));
11987  // Make sure the value for foo is read from the prototype, and that
11988  // we don't get in trouble with reading the deleted cell value
11989  // sentinel.
11990  CHECK_EQ(5, CompileRun("f()")->Int32Value());
11991}
11992
11993
11994v8::Persistent<Context> calling_context0;
11995v8::Persistent<Context> calling_context1;
11996v8::Persistent<Context> calling_context2;
11997
11998
11999// Check that the call to the callback is initiated in
12000// calling_context2, the directly calling context is calling_context1
12001// and the callback itself is in calling_context0.
12002static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12003  ApiTestFuzzer::Fuzz();
12004  CHECK(Context::GetCurrent() == calling_context0);
12005  CHECK(Context::GetCalling() == calling_context1);
12006  CHECK(Context::GetEntered() == calling_context2);
12007  return v8::Integer::New(42);
12008}
12009
12010
12011THREADED_TEST(GetCallingContext) {
12012  v8::HandleScope scope;
12013
12014  calling_context0 = Context::New();
12015  calling_context1 = Context::New();
12016  calling_context2 = Context::New();
12017
12018  // Allow cross-domain access.
12019  Local<String> token = v8_str("<security token>");
12020  calling_context0->SetSecurityToken(token);
12021  calling_context1->SetSecurityToken(token);
12022  calling_context2->SetSecurityToken(token);
12023
12024  // Create an object with a C++ callback in context0.
12025  calling_context0->Enter();
12026  Local<v8::FunctionTemplate> callback_templ =
12027      v8::FunctionTemplate::New(GetCallingContextCallback);
12028  calling_context0->Global()->Set(v8_str("callback"),
12029                                  callback_templ->GetFunction());
12030  calling_context0->Exit();
12031
12032  // Expose context0 in context1 and setup a function that calls the
12033  // callback function.
12034  calling_context1->Enter();
12035  calling_context1->Global()->Set(v8_str("context0"),
12036                                  calling_context0->Global());
12037  CompileRun("function f() { context0.callback() }");
12038  calling_context1->Exit();
12039
12040  // Expose context1 in context2 and call the callback function in
12041  // context0 indirectly through f in context1.
12042  calling_context2->Enter();
12043  calling_context2->Global()->Set(v8_str("context1"),
12044                                  calling_context1->Global());
12045  CompileRun("context1.f()");
12046  calling_context2->Exit();
12047
12048  // Dispose the contexts to allow them to be garbage collected.
12049  calling_context0.Dispose();
12050  calling_context1.Dispose();
12051  calling_context2.Dispose();
12052  calling_context0.Clear();
12053  calling_context1.Clear();
12054  calling_context2.Clear();
12055}
12056
12057
12058// Check that a variable declaration with no explicit initialization
12059// value does not shadow an existing property in the prototype chain.
12060//
12061// This is consistent with Firefox and Safari.
12062//
12063// See http://crbug.com/12548.
12064THREADED_TEST(InitGlobalVarInProtoChain) {
12065  v8::HandleScope scope;
12066  LocalContext context;
12067  // Introduce a variable in the prototype chain.
12068  CompileRun("__proto__.x = 42");
12069  v8::Handle<v8::Value> result = CompileRun("var x; x");
12070  CHECK(!result->IsUndefined());
12071  CHECK_EQ(42, result->Int32Value());
12072}
12073
12074
12075// Regression test for issue 398.
12076// If a function is added to an object, creating a constant function
12077// field, and the result is cloned, replacing the constant function on the
12078// original should not affect the clone.
12079// See http://code.google.com/p/v8/issues/detail?id=398
12080THREADED_TEST(ReplaceConstantFunction) {
12081  v8::HandleScope scope;
12082  LocalContext context;
12083  v8::Handle<v8::Object> obj = v8::Object::New();
12084  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12085  v8::Handle<v8::String> foo_string = v8::String::New("foo");
12086  obj->Set(foo_string, func_templ->GetFunction());
12087  v8::Handle<v8::Object> obj_clone = obj->Clone();
12088  obj_clone->Set(foo_string, v8::String::New("Hello"));
12089  CHECK(!obj->Get(foo_string)->IsUndefined());
12090}
12091
12092
12093// Regression test for http://crbug.com/16276.
12094THREADED_TEST(Regress16276) {
12095  v8::HandleScope scope;
12096  LocalContext context;
12097  // Force the IC in f to be a dictionary load IC.
12098  CompileRun("function f(obj) { return obj.x; }\n"
12099             "var obj = { x: { foo: 42 }, y: 87 };\n"
12100             "var x = obj.x;\n"
12101             "delete obj.y;\n"
12102             "for (var i = 0; i < 5; i++) f(obj);");
12103  // Detach the global object to make 'this' refer directly to the
12104  // global object (not the proxy), and make sure that the dictionary
12105  // load IC doesn't mess up loading directly from the global object.
12106  context->DetachGlobal();
12107  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12108}
12109
12110
12111THREADED_TEST(PixelArray) {
12112  v8::HandleScope scope;
12113  LocalContext context;
12114  const int kElementCount = 260;
12115  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12116  i::Handle<i::ExternalPixelArray> pixels =
12117      i::Handle<i::ExternalPixelArray>::cast(
12118          FACTORY->NewExternalArray(kElementCount,
12119                                    v8::kExternalPixelArray,
12120                                    pixel_data));
12121  // Force GC to trigger verification.
12122  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12123  for (int i = 0; i < kElementCount; i++) {
12124    pixels->set(i, i % 256);
12125  }
12126  // Force GC to trigger verification.
12127  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12128  for (int i = 0; i < kElementCount; i++) {
12129    CHECK_EQ(i % 256, pixels->get_scalar(i));
12130    CHECK_EQ(i % 256, pixel_data[i]);
12131  }
12132
12133  v8::Handle<v8::Object> obj = v8::Object::New();
12134  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12135  // Set the elements to be the pixels.
12136  // jsobj->set_elements(*pixels);
12137  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12138  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12139  obj->Set(v8_str("field"), v8::Int32::New(1503));
12140  context->Global()->Set(v8_str("pixels"), obj);
12141  v8::Handle<v8::Value> result = CompileRun("pixels.field");
12142  CHECK_EQ(1503, result->Int32Value());
12143  result = CompileRun("pixels[1]");
12144  CHECK_EQ(1, result->Int32Value());
12145
12146  result = CompileRun("var sum = 0;"
12147                      "for (var i = 0; i < 8; i++) {"
12148                      "  sum += pixels[i] = pixels[i] = -i;"
12149                      "}"
12150                      "sum;");
12151  CHECK_EQ(-28, result->Int32Value());
12152
12153  result = CompileRun("var sum = 0;"
12154                      "for (var i = 0; i < 8; i++) {"
12155                      "  sum += pixels[i] = pixels[i] = 0;"
12156                      "}"
12157                      "sum;");
12158  CHECK_EQ(0, result->Int32Value());
12159
12160  result = CompileRun("var sum = 0;"
12161                      "for (var i = 0; i < 8; i++) {"
12162                      "  sum += pixels[i] = pixels[i] = 255;"
12163                      "}"
12164                      "sum;");
12165  CHECK_EQ(8 * 255, result->Int32Value());
12166
12167  result = CompileRun("var sum = 0;"
12168                      "for (var i = 0; i < 8; i++) {"
12169                      "  sum += pixels[i] = pixels[i] = 256 + i;"
12170                      "}"
12171                      "sum;");
12172  CHECK_EQ(2076, result->Int32Value());
12173
12174  result = CompileRun("var sum = 0;"
12175                      "for (var i = 0; i < 8; i++) {"
12176                      "  sum += pixels[i] = pixels[i] = i;"
12177                      "}"
12178                      "sum;");
12179  CHECK_EQ(28, result->Int32Value());
12180
12181  result = CompileRun("var sum = 0;"
12182                      "for (var i = 0; i < 8; i++) {"
12183                      "  sum += pixels[i];"
12184                      "}"
12185                      "sum;");
12186  CHECK_EQ(28, result->Int32Value());
12187
12188  i::Handle<i::Smi> value(i::Smi::FromInt(2));
12189  i::Handle<i::Object> no_failure;
12190  no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12191  ASSERT(!no_failure.is_null());
12192  i::USE(no_failure);
12193  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12194  *value.location() = i::Smi::FromInt(256);
12195  no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12196  ASSERT(!no_failure.is_null());
12197  i::USE(no_failure);
12198  CHECK_EQ(255,
12199           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12200  *value.location() = i::Smi::FromInt(-1);
12201  no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12202  ASSERT(!no_failure.is_null());
12203  i::USE(no_failure);
12204  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12205
12206  result = CompileRun("for (var i = 0; i < 8; i++) {"
12207                      "  pixels[i] = (i * 65) - 109;"
12208                      "}"
12209                      "pixels[1] + pixels[6];");
12210  CHECK_EQ(255, result->Int32Value());
12211  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12212  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12213  CHECK_EQ(21,
12214           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12215  CHECK_EQ(86,
12216           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12217  CHECK_EQ(151,
12218           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12219  CHECK_EQ(216,
12220           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12221  CHECK_EQ(255,
12222           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12223  CHECK_EQ(255,
12224           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12225  result = CompileRun("var sum = 0;"
12226                      "for (var i = 0; i < 8; i++) {"
12227                      "  sum += pixels[i];"
12228                      "}"
12229                      "sum;");
12230  CHECK_EQ(984, result->Int32Value());
12231
12232  result = CompileRun("for (var i = 0; i < 8; i++) {"
12233                      "  pixels[i] = (i * 1.1);"
12234                      "}"
12235                      "pixels[1] + pixels[6];");
12236  CHECK_EQ(8, result->Int32Value());
12237  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12238  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12239  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12240  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12241  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12242  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12243  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12244  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12245
12246  result = CompileRun("for (var i = 0; i < 8; i++) {"
12247                      "  pixels[7] = undefined;"
12248                      "}"
12249                      "pixels[7];");
12250  CHECK_EQ(0, result->Int32Value());
12251  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12252
12253  result = CompileRun("for (var i = 0; i < 8; i++) {"
12254                      "  pixels[6] = '2.3';"
12255                      "}"
12256                      "pixels[6];");
12257  CHECK_EQ(2, result->Int32Value());
12258  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12259
12260  result = CompileRun("for (var i = 0; i < 8; i++) {"
12261                      "  pixels[5] = NaN;"
12262                      "}"
12263                      "pixels[5];");
12264  CHECK_EQ(0, result->Int32Value());
12265  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12266
12267  result = CompileRun("for (var i = 0; i < 8; i++) {"
12268                      "  pixels[8] = Infinity;"
12269                      "}"
12270                      "pixels[8];");
12271  CHECK_EQ(255, result->Int32Value());
12272  CHECK_EQ(255,
12273           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
12274
12275  result = CompileRun("for (var i = 0; i < 8; i++) {"
12276                      "  pixels[9] = -Infinity;"
12277                      "}"
12278                      "pixels[9];");
12279  CHECK_EQ(0, result->Int32Value());
12280  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
12281
12282  result = CompileRun("pixels[3] = 33;"
12283                      "delete pixels[3];"
12284                      "pixels[3];");
12285  CHECK_EQ(33, result->Int32Value());
12286
12287  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12288                      "pixels[2] = 12; pixels[3] = 13;"
12289                      "pixels.__defineGetter__('2',"
12290                      "function() { return 120; });"
12291                      "pixels[2];");
12292  CHECK_EQ(12, result->Int32Value());
12293
12294  result = CompileRun("var js_array = new Array(40);"
12295                      "js_array[0] = 77;"
12296                      "js_array;");
12297  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12298
12299  result = CompileRun("pixels[1] = 23;"
12300                      "pixels.__proto__ = [];"
12301                      "js_array.__proto__ = pixels;"
12302                      "js_array.concat(pixels);");
12303  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12304  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12305
12306  result = CompileRun("pixels[1] = 23;");
12307  CHECK_EQ(23, result->Int32Value());
12308
12309  // Test for index greater than 255.  Regression test for:
12310  // http://code.google.com/p/chromium/issues/detail?id=26337.
12311  result = CompileRun("pixels[256] = 255;");
12312  CHECK_EQ(255, result->Int32Value());
12313  result = CompileRun("var i = 0;"
12314                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12315                      "i");
12316  CHECK_EQ(255, result->Int32Value());
12317
12318  // Make sure that pixel array ICs recognize when a non-pixel array
12319  // is passed to it.
12320  result = CompileRun("function pa_load(p) {"
12321                      "  var sum = 0;"
12322                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12323                      "  return sum;"
12324                      "}"
12325                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12326                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12327                      "just_ints = new Object();"
12328                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12329                      "for (var i = 0; i < 10; ++i) {"
12330                      "  result = pa_load(just_ints);"
12331                      "}"
12332                      "result");
12333  CHECK_EQ(32640, result->Int32Value());
12334
12335  // Make sure that pixel array ICs recognize out-of-bound accesses.
12336  result = CompileRun("function pa_load(p, start) {"
12337                      "  var sum = 0;"
12338                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12339                      "  return sum;"
12340                      "}"
12341                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12342                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12343                      "for (var i = 0; i < 10; ++i) {"
12344                      "  result = pa_load(pixels,-10);"
12345                      "}"
12346                      "result");
12347  CHECK_EQ(0, result->Int32Value());
12348
12349  // Make sure that generic ICs properly handles a pixel array.
12350  result = CompileRun("function pa_load(p) {"
12351                      "  var sum = 0;"
12352                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12353                      "  return sum;"
12354                      "}"
12355                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12356                      "just_ints = new Object();"
12357                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12358                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12359                      "for (var i = 0; i < 10; ++i) {"
12360                      "  result = pa_load(pixels);"
12361                      "}"
12362                      "result");
12363  CHECK_EQ(32640, result->Int32Value());
12364
12365  // Make sure that generic load ICs recognize out-of-bound accesses in
12366  // pixel arrays.
12367  result = CompileRun("function pa_load(p, start) {"
12368                      "  var sum = 0;"
12369                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12370                      "  return sum;"
12371                      "}"
12372                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12373                      "just_ints = new Object();"
12374                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12375                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12376                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12377                      "for (var i = 0; i < 10; ++i) {"
12378                      "  result = pa_load(pixels,-10);"
12379                      "}"
12380                      "result");
12381  CHECK_EQ(0, result->Int32Value());
12382
12383  // Make sure that generic ICs properly handles other types than pixel
12384  // arrays (that the inlined fast pixel array test leaves the right information
12385  // in the right registers).
12386  result = CompileRun("function pa_load(p) {"
12387                      "  var sum = 0;"
12388                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12389                      "  return sum;"
12390                      "}"
12391                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12392                      "just_ints = new Object();"
12393                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12394                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12395                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12396                      "sparse_array = new Object();"
12397                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12398                      "sparse_array[1000000] = 3;"
12399                      "for (var i = 0; i < 10; ++i) {"
12400                      "  result = pa_load(sparse_array);"
12401                      "}"
12402                      "result");
12403  CHECK_EQ(32640, result->Int32Value());
12404
12405  // Make sure that pixel array store ICs clamp values correctly.
12406  result = CompileRun("function pa_store(p) {"
12407                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12408                      "}"
12409                      "pa_store(pixels);"
12410                      "var sum = 0;"
12411                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12412                      "sum");
12413  CHECK_EQ(48896, result->Int32Value());
12414
12415  // Make sure that pixel array stores correctly handle accesses outside
12416  // of the pixel array..
12417  result = CompileRun("function pa_store(p,start) {"
12418                      "  for (var j = 0; j < 256; j++) {"
12419                      "    p[j+start] = j * 2;"
12420                      "  }"
12421                      "}"
12422                      "pa_store(pixels,0);"
12423                      "pa_store(pixels,-128);"
12424                      "var sum = 0;"
12425                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12426                      "sum");
12427  CHECK_EQ(65280, result->Int32Value());
12428
12429  // Make sure that the generic store stub correctly handle accesses outside
12430  // of the pixel array..
12431  result = CompileRun("function pa_store(p,start) {"
12432                      "  for (var j = 0; j < 256; j++) {"
12433                      "    p[j+start] = j * 2;"
12434                      "  }"
12435                      "}"
12436                      "pa_store(pixels,0);"
12437                      "just_ints = new Object();"
12438                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12439                      "pa_store(just_ints, 0);"
12440                      "pa_store(pixels,-128);"
12441                      "var sum = 0;"
12442                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12443                      "sum");
12444  CHECK_EQ(65280, result->Int32Value());
12445
12446  // Make sure that the generic keyed store stub clamps pixel array values
12447  // correctly.
12448  result = CompileRun("function pa_store(p) {"
12449                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12450                      "}"
12451                      "pa_store(pixels);"
12452                      "just_ints = new Object();"
12453                      "pa_store(just_ints);"
12454                      "pa_store(pixels);"
12455                      "var sum = 0;"
12456                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12457                      "sum");
12458  CHECK_EQ(48896, result->Int32Value());
12459
12460  // Make sure that pixel array loads are optimized by crankshaft.
12461  result = CompileRun("function pa_load(p) {"
12462                      "  var sum = 0;"
12463                      "  for (var i=0; i<256; ++i) {"
12464                      "    sum += p[i];"
12465                      "  }"
12466                      "  return sum; "
12467                      "}"
12468                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12469                      "for (var i = 0; i < 5000; ++i) {"
12470                      "  result = pa_load(pixels);"
12471                      "}"
12472                      "result");
12473  CHECK_EQ(32640, result->Int32Value());
12474
12475  // Make sure that pixel array stores are optimized by crankshaft.
12476  result = CompileRun("function pa_init(p) {"
12477                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12478                      "}"
12479                      "function pa_load(p) {"
12480                      "  var sum = 0;"
12481                      "  for (var i=0; i<256; ++i) {"
12482                      "    sum += p[i];"
12483                      "  }"
12484                      "  return sum; "
12485                      "}"
12486                      "for (var i = 0; i < 5000; ++i) {"
12487                      "  pa_init(pixels);"
12488                      "}"
12489                      "result = pa_load(pixels);"
12490                      "result");
12491  CHECK_EQ(32640, result->Int32Value());
12492
12493  free(pixel_data);
12494}
12495
12496
12497THREADED_TEST(PixelArrayInfo) {
12498  v8::HandleScope scope;
12499  LocalContext context;
12500  for (int size = 0; size < 100; size += 10) {
12501    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12502    v8::Handle<v8::Object> obj = v8::Object::New();
12503    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12504    CHECK(obj->HasIndexedPropertiesInPixelData());
12505    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12506    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12507    free(pixel_data);
12508  }
12509}
12510
12511
12512static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12513    uint32_t index,
12514    const AccessorInfo& info) {
12515  ApiTestFuzzer::Fuzz();
12516  return v8::Handle<Value>();
12517}
12518
12519
12520static v8::Handle<Value> NotHandledIndexedPropertySetter(
12521    uint32_t index,
12522    Local<Value> value,
12523    const AccessorInfo& info) {
12524  ApiTestFuzzer::Fuzz();
12525  return v8::Handle<Value>();
12526}
12527
12528
12529THREADED_TEST(PixelArrayWithInterceptor) {
12530  v8::HandleScope scope;
12531  LocalContext context;
12532  const int kElementCount = 260;
12533  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12534  i::Handle<i::ExternalPixelArray> pixels =
12535      i::Handle<i::ExternalPixelArray>::cast(
12536          FACTORY->NewExternalArray(kElementCount,
12537                                    v8::kExternalPixelArray,
12538                                    pixel_data));
12539  for (int i = 0; i < kElementCount; i++) {
12540    pixels->set(i, i % 256);
12541  }
12542  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12543  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12544                                   NotHandledIndexedPropertySetter);
12545  v8::Handle<v8::Object> obj = templ->NewInstance();
12546  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12547  context->Global()->Set(v8_str("pixels"), obj);
12548  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12549  CHECK_EQ(1, result->Int32Value());
12550  result = CompileRun("var sum = 0;"
12551                      "for (var i = 0; i < 8; i++) {"
12552                      "  sum += pixels[i] = pixels[i] = -i;"
12553                      "}"
12554                      "sum;");
12555  CHECK_EQ(-28, result->Int32Value());
12556  result = CompileRun("pixels.hasOwnProperty('1')");
12557  CHECK(result->BooleanValue());
12558  free(pixel_data);
12559}
12560
12561
12562static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12563  switch (array_type) {
12564    case v8::kExternalByteArray:
12565    case v8::kExternalUnsignedByteArray:
12566    case v8::kExternalPixelArray:
12567      return 1;
12568      break;
12569    case v8::kExternalShortArray:
12570    case v8::kExternalUnsignedShortArray:
12571      return 2;
12572      break;
12573    case v8::kExternalIntArray:
12574    case v8::kExternalUnsignedIntArray:
12575    case v8::kExternalFloatArray:
12576      return 4;
12577      break;
12578    case v8::kExternalDoubleArray:
12579      return 8;
12580      break;
12581    default:
12582      UNREACHABLE();
12583      return -1;
12584  }
12585  UNREACHABLE();
12586  return -1;
12587}
12588
12589
12590template <class ExternalArrayClass, class ElementType>
12591static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12592                                    int64_t low,
12593                                    int64_t high) {
12594  v8::HandleScope scope;
12595  LocalContext context;
12596  const int kElementCount = 40;
12597  int element_size = ExternalArrayElementSize(array_type);
12598  ElementType* array_data =
12599      static_cast<ElementType*>(malloc(kElementCount * element_size));
12600  i::Handle<ExternalArrayClass> array =
12601      i::Handle<ExternalArrayClass>::cast(
12602          FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12603  // Force GC to trigger verification.
12604  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12605  for (int i = 0; i < kElementCount; i++) {
12606    array->set(i, static_cast<ElementType>(i));
12607  }
12608  // Force GC to trigger verification.
12609  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12610  for (int i = 0; i < kElementCount; i++) {
12611    CHECK_EQ(static_cast<int64_t>(i),
12612             static_cast<int64_t>(array->get_scalar(i)));
12613    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12614  }
12615
12616  v8::Handle<v8::Object> obj = v8::Object::New();
12617  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12618  // Set the elements to be the external array.
12619  obj->SetIndexedPropertiesToExternalArrayData(array_data,
12620                                               array_type,
12621                                               kElementCount);
12622  CHECK_EQ(
12623      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
12624  obj->Set(v8_str("field"), v8::Int32::New(1503));
12625  context->Global()->Set(v8_str("ext_array"), obj);
12626  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12627  CHECK_EQ(1503, result->Int32Value());
12628  result = CompileRun("ext_array[1]");
12629  CHECK_EQ(1, result->Int32Value());
12630
12631  // Check pass through of assigned smis
12632  result = CompileRun("var sum = 0;"
12633                      "for (var i = 0; i < 8; i++) {"
12634                      "  sum += ext_array[i] = ext_array[i] = -i;"
12635                      "}"
12636                      "sum;");
12637  CHECK_EQ(-28, result->Int32Value());
12638
12639  // Check assigned smis
12640  result = CompileRun("for (var i = 0; i < 8; i++) {"
12641                      "  ext_array[i] = i;"
12642                      "}"
12643                      "var sum = 0;"
12644                      "for (var i = 0; i < 8; i++) {"
12645                      "  sum += ext_array[i];"
12646                      "}"
12647                      "sum;");
12648  CHECK_EQ(28, result->Int32Value());
12649
12650  // Check assigned smis in reverse order
12651  result = CompileRun("for (var i = 8; --i >= 0; ) {"
12652                      "  ext_array[i] = i;"
12653                      "}"
12654                      "var sum = 0;"
12655                      "for (var i = 0; i < 8; i++) {"
12656                      "  sum += ext_array[i];"
12657                      "}"
12658                      "sum;");
12659  CHECK_EQ(28, result->Int32Value());
12660
12661  // Check pass through of assigned HeapNumbers
12662  result = CompileRun("var sum = 0;"
12663                      "for (var i = 0; i < 16; i+=2) {"
12664                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12665                      "}"
12666                      "sum;");
12667  CHECK_EQ(-28, result->Int32Value());
12668
12669  // Check assigned HeapNumbers
12670  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12671                      "  ext_array[i] = (i * 0.5);"
12672                      "}"
12673                      "var sum = 0;"
12674                      "for (var i = 0; i < 16; i+=2) {"
12675                      "  sum += ext_array[i];"
12676                      "}"
12677                      "sum;");
12678  CHECK_EQ(28, result->Int32Value());
12679
12680  // Check assigned HeapNumbers in reverse order
12681  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12682                      "  ext_array[i] = (i * 0.5);"
12683                      "}"
12684                      "var sum = 0;"
12685                      "for (var i = 0; i < 16; i+=2) {"
12686                      "  sum += ext_array[i];"
12687                      "}"
12688                      "sum;");
12689  CHECK_EQ(28, result->Int32Value());
12690
12691  i::ScopedVector<char> test_buf(1024);
12692
12693  // Check legal boundary conditions.
12694  // The repeated loads and stores ensure the ICs are exercised.
12695  const char* boundary_program =
12696      "var res = 0;"
12697      "for (var i = 0; i < 16; i++) {"
12698      "  ext_array[i] = %lld;"
12699      "  if (i > 8) {"
12700      "    res = ext_array[i];"
12701      "  }"
12702      "}"
12703      "res;";
12704  i::OS::SNPrintF(test_buf,
12705                  boundary_program,
12706                  low);
12707  result = CompileRun(test_buf.start());
12708  CHECK_EQ(low, result->IntegerValue());
12709
12710  i::OS::SNPrintF(test_buf,
12711                  boundary_program,
12712                  high);
12713  result = CompileRun(test_buf.start());
12714  CHECK_EQ(high, result->IntegerValue());
12715
12716  // Check misprediction of type in IC.
12717  result = CompileRun("var tmp_array = ext_array;"
12718                      "var sum = 0;"
12719                      "for (var i = 0; i < 8; i++) {"
12720                      "  tmp_array[i] = i;"
12721                      "  sum += tmp_array[i];"
12722                      "  if (i == 4) {"
12723                      "    tmp_array = {};"
12724                      "  }"
12725                      "}"
12726                      "sum;");
12727  // Force GC to trigger verification.
12728  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12729  CHECK_EQ(28, result->Int32Value());
12730
12731  // Make sure out-of-range loads do not throw.
12732  i::OS::SNPrintF(test_buf,
12733                  "var caught_exception = false;"
12734                  "try {"
12735                  "  ext_array[%d];"
12736                  "} catch (e) {"
12737                  "  caught_exception = true;"
12738                  "}"
12739                  "caught_exception;",
12740                  kElementCount);
12741  result = CompileRun(test_buf.start());
12742  CHECK_EQ(false, result->BooleanValue());
12743
12744  // Make sure out-of-range stores do not throw.
12745  i::OS::SNPrintF(test_buf,
12746                  "var caught_exception = false;"
12747                  "try {"
12748                  "  ext_array[%d] = 1;"
12749                  "} catch (e) {"
12750                  "  caught_exception = true;"
12751                  "}"
12752                  "caught_exception;",
12753                  kElementCount);
12754  result = CompileRun(test_buf.start());
12755  CHECK_EQ(false, result->BooleanValue());
12756
12757  // Check other boundary conditions, values and operations.
12758  result = CompileRun("for (var i = 0; i < 8; i++) {"
12759                      "  ext_array[7] = undefined;"
12760                      "}"
12761                      "ext_array[7];");
12762  CHECK_EQ(0, result->Int32Value());
12763  CHECK_EQ(
12764      0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
12765
12766  result = CompileRun("for (var i = 0; i < 8; i++) {"
12767                      "  ext_array[6] = '2.3';"
12768                      "}"
12769                      "ext_array[6];");
12770  CHECK_EQ(2, result->Int32Value());
12771  CHECK_EQ(
12772      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
12773
12774  if (array_type != v8::kExternalFloatArray &&
12775      array_type != v8::kExternalDoubleArray) {
12776    // Though the specification doesn't state it, be explicit about
12777    // converting NaNs and +/-Infinity to zero.
12778    result = CompileRun("for (var i = 0; i < 8; i++) {"
12779                        "  ext_array[i] = 5;"
12780                        "}"
12781                        "for (var i = 0; i < 8; i++) {"
12782                        "  ext_array[i] = NaN;"
12783                        "}"
12784                        "ext_array[5];");
12785    CHECK_EQ(0, result->Int32Value());
12786    CHECK_EQ(0,
12787             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12788
12789    result = CompileRun("for (var i = 0; i < 8; i++) {"
12790                        "  ext_array[i] = 5;"
12791                        "}"
12792                        "for (var i = 0; i < 8; i++) {"
12793                        "  ext_array[i] = Infinity;"
12794                        "}"
12795                        "ext_array[5];");
12796    int expected_value =
12797        (array_type == v8::kExternalPixelArray) ? 255 : 0;
12798    CHECK_EQ(expected_value, result->Int32Value());
12799    CHECK_EQ(expected_value,
12800             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12801
12802    result = CompileRun("for (var i = 0; i < 8; i++) {"
12803                        "  ext_array[i] = 5;"
12804                        "}"
12805                        "for (var i = 0; i < 8; i++) {"
12806                        "  ext_array[i] = -Infinity;"
12807                        "}"
12808                        "ext_array[5];");
12809    CHECK_EQ(0, result->Int32Value());
12810    CHECK_EQ(0,
12811             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12812
12813    // Check truncation behavior of integral arrays.
12814    const char* unsigned_data =
12815        "var source_data = [0.6, 10.6];"
12816        "var expected_results = [0, 10];";
12817    const char* signed_data =
12818        "var source_data = [0.6, 10.6, -0.6, -10.6];"
12819        "var expected_results = [0, 10, 0, -10];";
12820    const char* pixel_data =
12821        "var source_data = [0.6, 10.6];"
12822        "var expected_results = [1, 11];";
12823    bool is_unsigned =
12824        (array_type == v8::kExternalUnsignedByteArray ||
12825         array_type == v8::kExternalUnsignedShortArray ||
12826         array_type == v8::kExternalUnsignedIntArray);
12827    bool is_pixel_data = array_type == v8::kExternalPixelArray;
12828
12829    i::OS::SNPrintF(test_buf,
12830                    "%s"
12831                    "var all_passed = true;"
12832                    "for (var i = 0; i < source_data.length; i++) {"
12833                    "  for (var j = 0; j < 8; j++) {"
12834                    "    ext_array[j] = source_data[i];"
12835                    "  }"
12836                    "  all_passed = all_passed &&"
12837                    "               (ext_array[5] == expected_results[i]);"
12838                    "}"
12839                    "all_passed;",
12840                    (is_unsigned ?
12841                         unsigned_data :
12842                         (is_pixel_data ? pixel_data : signed_data)));
12843    result = CompileRun(test_buf.start());
12844    CHECK_EQ(true, result->BooleanValue());
12845  }
12846
12847  for (int i = 0; i < kElementCount; i++) {
12848    array->set(i, static_cast<ElementType>(i));
12849  }
12850  // Test complex assignments
12851  result = CompileRun("function ee_op_test_complex_func(sum) {"
12852                      " for (var i = 0; i < 40; ++i) {"
12853                      "   sum += (ext_array[i] += 1);"
12854                      "   sum += (ext_array[i] -= 1);"
12855                      " } "
12856                      " return sum;"
12857                      "}"
12858                      "sum=0;"
12859                      "for (var i=0;i<10000;++i) {"
12860                      "  sum=ee_op_test_complex_func(sum);"
12861                      "}"
12862                      "sum;");
12863  CHECK_EQ(16000000, result->Int32Value());
12864
12865  // Test count operations
12866  result = CompileRun("function ee_op_test_count_func(sum) {"
12867                      " for (var i = 0; i < 40; ++i) {"
12868                      "   sum += (++ext_array[i]);"
12869                      "   sum += (--ext_array[i]);"
12870                      " } "
12871                      " return sum;"
12872                      "}"
12873                      "sum=0;"
12874                      "for (var i=0;i<10000;++i) {"
12875                      "  sum=ee_op_test_count_func(sum);"
12876                      "}"
12877                      "sum;");
12878  CHECK_EQ(16000000, result->Int32Value());
12879
12880  result = CompileRun("ext_array[3] = 33;"
12881                      "delete ext_array[3];"
12882                      "ext_array[3];");
12883  CHECK_EQ(33, result->Int32Value());
12884
12885  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12886                      "ext_array[2] = 12; ext_array[3] = 13;"
12887                      "ext_array.__defineGetter__('2',"
12888                      "function() { return 120; });"
12889                      "ext_array[2];");
12890  CHECK_EQ(12, result->Int32Value());
12891
12892  result = CompileRun("var js_array = new Array(40);"
12893                      "js_array[0] = 77;"
12894                      "js_array;");
12895  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12896
12897  result = CompileRun("ext_array[1] = 23;"
12898                      "ext_array.__proto__ = [];"
12899                      "js_array.__proto__ = ext_array;"
12900                      "js_array.concat(ext_array);");
12901  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12902  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12903
12904  result = CompileRun("ext_array[1] = 23;");
12905  CHECK_EQ(23, result->Int32Value());
12906
12907  // Test more complex manipulations which cause eax to contain values
12908  // that won't be completely overwritten by loads from the arrays.
12909  // This catches bugs in the instructions used for the KeyedLoadIC
12910  // for byte and word types.
12911  {
12912    const int kXSize = 300;
12913    const int kYSize = 300;
12914    const int kLargeElementCount = kXSize * kYSize * 4;
12915    ElementType* large_array_data =
12916        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12917    i::Handle<ExternalArrayClass> large_array(
12918        i::Handle<ExternalArrayClass>::cast(
12919            FACTORY->NewExternalArray(kLargeElementCount,
12920                                      array_type,
12921                                      array_data)));
12922    v8::Handle<v8::Object> large_obj = v8::Object::New();
12923    // Set the elements to be the external array.
12924    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12925                                                       array_type,
12926                                                       kLargeElementCount);
12927    context->Global()->Set(v8_str("large_array"), large_obj);
12928    // Initialize contents of a few rows.
12929    for (int x = 0; x < 300; x++) {
12930      int row = 0;
12931      int offset = row * 300 * 4;
12932      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12933      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12934      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12935      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12936      row = 150;
12937      offset = row * 300 * 4;
12938      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12939      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12940      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12941      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12942      row = 298;
12943      offset = row * 300 * 4;
12944      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12945      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12946      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12947      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12948    }
12949    // The goal of the code below is to make "offset" large enough
12950    // that the computation of the index (which goes into eax) has
12951    // high bits set which will not be overwritten by a byte or short
12952    // load.
12953    result = CompileRun("var failed = false;"
12954                        "var offset = 0;"
12955                        "for (var i = 0; i < 300; i++) {"
12956                        "  if (large_array[4 * i] != 127 ||"
12957                        "      large_array[4 * i + 1] != 0 ||"
12958                        "      large_array[4 * i + 2] != 0 ||"
12959                        "      large_array[4 * i + 3] != 127) {"
12960                        "    failed = true;"
12961                        "  }"
12962                        "}"
12963                        "offset = 150 * 300 * 4;"
12964                        "for (var i = 0; i < 300; i++) {"
12965                        "  if (large_array[offset + 4 * i] != 127 ||"
12966                        "      large_array[offset + 4 * i + 1] != 0 ||"
12967                        "      large_array[offset + 4 * i + 2] != 0 ||"
12968                        "      large_array[offset + 4 * i + 3] != 127) {"
12969                        "    failed = true;"
12970                        "  }"
12971                        "}"
12972                        "offset = 298 * 300 * 4;"
12973                        "for (var i = 0; i < 300; i++) {"
12974                        "  if (large_array[offset + 4 * i] != 127 ||"
12975                        "      large_array[offset + 4 * i + 1] != 0 ||"
12976                        "      large_array[offset + 4 * i + 2] != 0 ||"
12977                        "      large_array[offset + 4 * i + 3] != 127) {"
12978                        "    failed = true;"
12979                        "  }"
12980                        "}"
12981                        "!failed;");
12982    CHECK_EQ(true, result->BooleanValue());
12983    free(large_array_data);
12984  }
12985
12986  // The "" property descriptor is overloaded to store information about
12987  // the external array. Ensure that setting and accessing the "" property
12988  // works (it should overwrite the information cached about the external
12989  // array in the DescriptorArray) in various situations.
12990  result = CompileRun("ext_array[''] = 23; ext_array['']");
12991  CHECK_EQ(23, result->Int32Value());
12992
12993  // Property "" set after the external array is associated with the object.
12994  {
12995    v8::Handle<v8::Object> obj2 = v8::Object::New();
12996    obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12997    obj2->Set(v8_str(""), v8::Int32::New(1503));
12998    // Set the elements to be the external array.
12999    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13000                                                  array_type,
13001                                                  kElementCount);
13002    context->Global()->Set(v8_str("ext_array"), obj2);
13003    result = CompileRun("ext_array['']");
13004    CHECK_EQ(1503, result->Int32Value());
13005  }
13006
13007  // Property "" set after the external array is associated with the object.
13008  {
13009    v8::Handle<v8::Object> obj2 = v8::Object::New();
13010    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13011    // Set the elements to be the external array.
13012    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13013                                                  array_type,
13014                                                  kElementCount);
13015    obj2->Set(v8_str(""), v8::Int32::New(1503));
13016    context->Global()->Set(v8_str("ext_array"), obj2);
13017    result = CompileRun("ext_array['']");
13018    CHECK_EQ(1503, result->Int32Value());
13019  }
13020
13021  // Should reuse the map from previous test.
13022  {
13023    v8::Handle<v8::Object> obj2 = v8::Object::New();
13024    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13025    // Set the elements to be the external array. Should re-use the map
13026    // from previous test.
13027    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13028                                                  array_type,
13029                                                  kElementCount);
13030    context->Global()->Set(v8_str("ext_array"), obj2);
13031    result = CompileRun("ext_array['']");
13032  }
13033
13034  // Property "" is a constant function that shouldn't not be interfered with
13035  // when an external array is set.
13036  {
13037    v8::Handle<v8::Object> obj2 = v8::Object::New();
13038    // Start
13039    obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13040
13041    // Add a constant function to an object.
13042    context->Global()->Set(v8_str("ext_array"), obj2);
13043    result = CompileRun("ext_array[''] = function() {return 1503;};"
13044                        "ext_array['']();");
13045
13046    // Add an external array transition to the same map that
13047    // has the constant transition.
13048    v8::Handle<v8::Object> obj3 = v8::Object::New();
13049    obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13050    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13051                                                  array_type,
13052                                                  kElementCount);
13053    context->Global()->Set(v8_str("ext_array"), obj3);
13054  }
13055
13056  // If a external array transition is in the map, it should get clobbered
13057  // by a constant function.
13058  {
13059    // Add an external array transition.
13060    v8::Handle<v8::Object> obj3 = v8::Object::New();
13061    obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13062    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13063                                                  array_type,
13064                                                  kElementCount);
13065
13066    // Add a constant function to the same map that just got an external array
13067    // transition.
13068    v8::Handle<v8::Object> obj2 = v8::Object::New();
13069    obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13070    context->Global()->Set(v8_str("ext_array"), obj2);
13071    result = CompileRun("ext_array[''] = function() {return 1503;};"
13072                        "ext_array['']();");
13073  }
13074
13075  free(array_data);
13076}
13077
13078
13079THREADED_TEST(ExternalByteArray) {
13080  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
13081      v8::kExternalByteArray,
13082      -128,
13083      127);
13084}
13085
13086
13087THREADED_TEST(ExternalUnsignedByteArray) {
13088  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
13089      v8::kExternalUnsignedByteArray,
13090      0,
13091      255);
13092}
13093
13094
13095THREADED_TEST(ExternalPixelArray) {
13096  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13097      v8::kExternalPixelArray,
13098      0,
13099      255);
13100}
13101
13102
13103THREADED_TEST(ExternalShortArray) {
13104  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
13105      v8::kExternalShortArray,
13106      -32768,
13107      32767);
13108}
13109
13110
13111THREADED_TEST(ExternalUnsignedShortArray) {
13112  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
13113      v8::kExternalUnsignedShortArray,
13114      0,
13115      65535);
13116}
13117
13118
13119THREADED_TEST(ExternalIntArray) {
13120  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
13121      v8::kExternalIntArray,
13122      INT_MIN,   // -2147483648
13123      INT_MAX);  //  2147483647
13124}
13125
13126
13127THREADED_TEST(ExternalUnsignedIntArray) {
13128  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
13129      v8::kExternalUnsignedIntArray,
13130      0,
13131      UINT_MAX);  // 4294967295
13132}
13133
13134
13135THREADED_TEST(ExternalFloatArray) {
13136  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
13137      v8::kExternalFloatArray,
13138      -500,
13139      500);
13140}
13141
13142
13143THREADED_TEST(ExternalDoubleArray) {
13144  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13145      v8::kExternalDoubleArray,
13146      -500,
13147      500);
13148}
13149
13150
13151THREADED_TEST(ExternalArrays) {
13152  TestExternalByteArray();
13153  TestExternalUnsignedByteArray();
13154  TestExternalShortArray();
13155  TestExternalUnsignedShortArray();
13156  TestExternalIntArray();
13157  TestExternalUnsignedIntArray();
13158  TestExternalFloatArray();
13159}
13160
13161
13162void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13163  v8::HandleScope scope;
13164  LocalContext context;
13165  for (int size = 0; size < 100; size += 10) {
13166    int element_size = ExternalArrayElementSize(array_type);
13167    void* external_data = malloc(size * element_size);
13168    v8::Handle<v8::Object> obj = v8::Object::New();
13169    obj->SetIndexedPropertiesToExternalArrayData(
13170        external_data, array_type, size);
13171    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13172    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13173    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13174    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13175    free(external_data);
13176  }
13177}
13178
13179
13180THREADED_TEST(ExternalArrayInfo) {
13181  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13182  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13183  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13184  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13185  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13186  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13187  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
13188  ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
13189  ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
13190}
13191
13192
13193THREADED_TEST(ScriptContextDependence) {
13194  v8::HandleScope scope;
13195  LocalContext c1;
13196  const char *source = "foo";
13197  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13198  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13199  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13200  CHECK_EQ(dep->Run()->Int32Value(), 100);
13201  CHECK_EQ(indep->Run()->Int32Value(), 100);
13202  LocalContext c2;
13203  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13204  CHECK_EQ(dep->Run()->Int32Value(), 100);
13205  CHECK_EQ(indep->Run()->Int32Value(), 101);
13206}
13207
13208
13209THREADED_TEST(StackTrace) {
13210  v8::HandleScope scope;
13211  LocalContext context;
13212  v8::TryCatch try_catch;
13213  const char *source = "function foo() { FAIL.FAIL; }; foo();";
13214  v8::Handle<v8::String> src = v8::String::New(source);
13215  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13216  v8::Script::New(src, origin)->Run();
13217  CHECK(try_catch.HasCaught());
13218  v8::String::Utf8Value stack(try_catch.StackTrace());
13219  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13220}
13221
13222
13223// Checks that a StackFrame has certain expected values.
13224void checkStackFrame(const char* expected_script_name,
13225    const char* expected_func_name, int expected_line_number,
13226    int expected_column, bool is_eval, bool is_constructor,
13227    v8::Handle<v8::StackFrame> frame) {
13228  v8::HandleScope scope;
13229  v8::String::Utf8Value func_name(frame->GetFunctionName());
13230  v8::String::Utf8Value script_name(frame->GetScriptName());
13231  if (*script_name == NULL) {
13232    // The situation where there is no associated script, like for evals.
13233    CHECK(expected_script_name == NULL);
13234  } else {
13235    CHECK(strstr(*script_name, expected_script_name) != NULL);
13236  }
13237  CHECK(strstr(*func_name, expected_func_name) != NULL);
13238  CHECK_EQ(expected_line_number, frame->GetLineNumber());
13239  CHECK_EQ(expected_column, frame->GetColumn());
13240  CHECK_EQ(is_eval, frame->IsEval());
13241  CHECK_EQ(is_constructor, frame->IsConstructor());
13242}
13243
13244
13245v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13246  v8::HandleScope scope;
13247  const char* origin = "capture-stack-trace-test";
13248  const int kOverviewTest = 1;
13249  const int kDetailedTest = 2;
13250
13251  ASSERT(args.Length() == 1);
13252
13253  int testGroup = args[0]->Int32Value();
13254  if (testGroup == kOverviewTest) {
13255    v8::Handle<v8::StackTrace> stackTrace =
13256        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13257    CHECK_EQ(4, stackTrace->GetFrameCount());
13258    checkStackFrame(origin, "bar", 2, 10, false, false,
13259                    stackTrace->GetFrame(0));
13260    checkStackFrame(origin, "foo", 6, 3, false, false,
13261                    stackTrace->GetFrame(1));
13262    // This is the source string inside the eval which has the call to foo.
13263    checkStackFrame(NULL, "", 1, 5, false, false,
13264                    stackTrace->GetFrame(2));
13265    // The last frame is an anonymous function which has the initial eval call.
13266    checkStackFrame(origin, "", 8, 7, false, false,
13267                    stackTrace->GetFrame(3));
13268
13269    CHECK(stackTrace->AsArray()->IsArray());
13270  } else if (testGroup == kDetailedTest) {
13271    v8::Handle<v8::StackTrace> stackTrace =
13272        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13273    CHECK_EQ(4, stackTrace->GetFrameCount());
13274    checkStackFrame(origin, "bat", 4, 22, false, false,
13275                    stackTrace->GetFrame(0));
13276    checkStackFrame(origin, "baz", 8, 3, false, true,
13277                    stackTrace->GetFrame(1));
13278#ifdef ENABLE_DEBUGGER_SUPPORT
13279    bool is_eval = true;
13280#else  // ENABLE_DEBUGGER_SUPPORT
13281    bool is_eval = false;
13282#endif  // ENABLE_DEBUGGER_SUPPORT
13283
13284    // This is the source string inside the eval which has the call to baz.
13285    checkStackFrame(NULL, "", 1, 5, is_eval, false,
13286                    stackTrace->GetFrame(2));
13287    // The last frame is an anonymous function which has the initial eval call.
13288    checkStackFrame(origin, "", 10, 1, false, false,
13289                    stackTrace->GetFrame(3));
13290
13291    CHECK(stackTrace->AsArray()->IsArray());
13292  }
13293  return v8::Undefined();
13294}
13295
13296
13297// Tests the C++ StackTrace API.
13298// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13299// THREADED_TEST(CaptureStackTrace) {
13300TEST(CaptureStackTrace) {
13301  v8::HandleScope scope;
13302  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13303  Local<ObjectTemplate> templ = ObjectTemplate::New();
13304  templ->Set(v8_str("AnalyzeStackInNativeCode"),
13305             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13306  LocalContext context(0, templ);
13307
13308  // Test getting OVERVIEW information. Should ignore information that is not
13309  // script name, function name, line number, and column offset.
13310  const char *overview_source =
13311    "function bar() {\n"
13312    "  var y; AnalyzeStackInNativeCode(1);\n"
13313    "}\n"
13314    "function foo() {\n"
13315    "\n"
13316    "  bar();\n"
13317    "}\n"
13318    "var x;eval('new foo();');";
13319  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
13320  v8::Handle<Value> overview_result(
13321      v8::Script::New(overview_src, origin)->Run());
13322  ASSERT(!overview_result.IsEmpty());
13323  ASSERT(overview_result->IsObject());
13324
13325  // Test getting DETAILED information.
13326  const char *detailed_source =
13327    "function bat() {AnalyzeStackInNativeCode(2);\n"
13328    "}\n"
13329    "\n"
13330    "function baz() {\n"
13331    "  bat();\n"
13332    "}\n"
13333    "eval('new baz();');";
13334  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13335  // Make the script using a non-zero line and column offset.
13336  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13337  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13338  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13339  v8::Handle<v8::Script> detailed_script(
13340      v8::Script::New(detailed_src, &detailed_origin));
13341  v8::Handle<Value> detailed_result(detailed_script->Run());
13342  ASSERT(!detailed_result.IsEmpty());
13343  ASSERT(detailed_result->IsObject());
13344}
13345
13346
13347static void StackTraceForUncaughtExceptionListener(
13348    v8::Handle<v8::Message> message,
13349    v8::Handle<Value>) {
13350  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13351  CHECK_EQ(2, stack_trace->GetFrameCount());
13352  checkStackFrame("origin", "foo", 2, 3, false, false,
13353                  stack_trace->GetFrame(0));
13354  checkStackFrame("origin", "bar", 5, 3, false, false,
13355                  stack_trace->GetFrame(1));
13356}
13357
13358TEST(CaptureStackTraceForUncaughtException) {
13359  report_count = 0;
13360  v8::HandleScope scope;
13361  LocalContext env;
13362  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13363  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13364
13365  Script::Compile(v8_str("function foo() {\n"
13366                         "  throw 1;\n"
13367                         "};\n"
13368                         "function bar() {\n"
13369                         "  foo();\n"
13370                         "};"),
13371                  v8_str("origin"))->Run();
13372  v8::Local<v8::Object> global = env->Global();
13373  Local<Value> trouble = global->Get(v8_str("bar"));
13374  CHECK(trouble->IsFunction());
13375  Function::Cast(*trouble)->Call(global, 0, NULL);
13376  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13377  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13378}
13379
13380
13381TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13382  v8::HandleScope scope;
13383  LocalContext env;
13384  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13385                                                    1024,
13386                                                    v8::StackTrace::kDetailed);
13387
13388  CompileRun(
13389      "var setters = ['column', 'lineNumber', 'scriptName',\n"
13390      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13391      "    'isConstructor'];\n"
13392      "for (var i = 0; i < setters.length; i++) {\n"
13393      "  var prop = setters[i];\n"
13394      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13395      "}\n");
13396  CompileRun("throw 'exception';");
13397  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13398}
13399
13400
13401v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13402  v8::HandleScope scope;
13403  v8::Handle<v8::StackTrace> stackTrace =
13404      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13405  CHECK_EQ(5, stackTrace->GetFrameCount());
13406  v8::Handle<v8::String> url = v8_str("eval_url");
13407  for (int i = 0; i < 3; i++) {
13408    v8::Handle<v8::String> name =
13409        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13410    CHECK(!name.IsEmpty());
13411    CHECK_EQ(url, name);
13412  }
13413  return v8::Undefined();
13414}
13415
13416
13417TEST(SourceURLInStackTrace) {
13418  v8::HandleScope scope;
13419  Local<ObjectTemplate> templ = ObjectTemplate::New();
13420  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13421             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13422  LocalContext context(0, templ);
13423
13424  const char *source =
13425    "function outer() {\n"
13426    "function bar() {\n"
13427    "  AnalyzeStackOfEvalWithSourceURL();\n"
13428    "}\n"
13429    "function foo() {\n"
13430    "\n"
13431    "  bar();\n"
13432    "}\n"
13433    "foo();\n"
13434    "}\n"
13435    "eval('(' + outer +')()//@ sourceURL=eval_url');";
13436  CHECK(CompileRun(source)->IsUndefined());
13437}
13438
13439
13440// Test that idle notification can be handled and eventually returns true.
13441THREADED_TEST(IdleNotification) {
13442  bool rv = false;
13443  for (int i = 0; i < 100; i++) {
13444    rv = v8::V8::IdleNotification();
13445    if (rv)
13446      break;
13447  }
13448  CHECK(rv == true);
13449}
13450
13451
13452static uint32_t* stack_limit;
13453
13454static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
13455  stack_limit = reinterpret_cast<uint32_t*>(
13456      i::Isolate::Current()->stack_guard()->real_climit());
13457  return v8::Undefined();
13458}
13459
13460
13461// Uses the address of a local variable to determine the stack top now.
13462// Given a size, returns an address that is that far from the current
13463// top of stack.
13464static uint32_t* ComputeStackLimit(uint32_t size) {
13465  uint32_t* answer = &size - (size / sizeof(size));
13466  // If the size is very large and the stack is very near the bottom of
13467  // memory then the calculation above may wrap around and give an address
13468  // that is above the (downwards-growing) stack.  In that case we return
13469  // a very low address.
13470  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13471  return answer;
13472}
13473
13474
13475TEST(SetResourceConstraints) {
13476  static const int K = 1024;
13477  uint32_t* set_limit = ComputeStackLimit(128 * K);
13478
13479  // Set stack limit.
13480  v8::ResourceConstraints constraints;
13481  constraints.set_stack_limit(set_limit);
13482  CHECK(v8::SetResourceConstraints(&constraints));
13483
13484  // Execute a script.
13485  v8::HandleScope scope;
13486  LocalContext env;
13487  Local<v8::FunctionTemplate> fun_templ =
13488      v8::FunctionTemplate::New(GetStackLimitCallback);
13489  Local<Function> fun = fun_templ->GetFunction();
13490  env->Global()->Set(v8_str("get_stack_limit"), fun);
13491  CompileRun("get_stack_limit();");
13492
13493  CHECK(stack_limit == set_limit);
13494}
13495
13496
13497TEST(SetResourceConstraintsInThread) {
13498  uint32_t* set_limit;
13499  {
13500    v8::Locker locker;
13501    static const int K = 1024;
13502    set_limit = ComputeStackLimit(128 * K);
13503
13504    // Set stack limit.
13505    v8::ResourceConstraints constraints;
13506    constraints.set_stack_limit(set_limit);
13507    CHECK(v8::SetResourceConstraints(&constraints));
13508
13509    // Execute a script.
13510    v8::HandleScope scope;
13511    LocalContext env;
13512    Local<v8::FunctionTemplate> fun_templ =
13513        v8::FunctionTemplate::New(GetStackLimitCallback);
13514    Local<Function> fun = fun_templ->GetFunction();
13515    env->Global()->Set(v8_str("get_stack_limit"), fun);
13516    CompileRun("get_stack_limit();");
13517
13518    CHECK(stack_limit == set_limit);
13519  }
13520  {
13521    v8::Locker locker;
13522    CHECK(stack_limit == set_limit);
13523  }
13524}
13525
13526
13527THREADED_TEST(GetHeapStatistics) {
13528  v8::HandleScope scope;
13529  LocalContext c1;
13530  v8::HeapStatistics heap_statistics;
13531  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13532  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
13533  v8::V8::GetHeapStatistics(&heap_statistics);
13534  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13535  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13536}
13537
13538
13539static double DoubleFromBits(uint64_t value) {
13540  double target;
13541  memcpy(&target, &value, sizeof(target));
13542  return target;
13543}
13544
13545
13546static uint64_t DoubleToBits(double value) {
13547  uint64_t target;
13548  memcpy(&target, &value, sizeof(target));
13549  return target;
13550}
13551
13552
13553static double DoubleToDateTime(double input) {
13554  double date_limit = 864e13;
13555  if (IsNaN(input) || input < -date_limit || input > date_limit) {
13556    return i::OS::nan_value();
13557  }
13558  return (input < 0) ? -(floor(-input)) : floor(input);
13559}
13560
13561// We don't have a consistent way to write 64-bit constants syntactically, so we
13562// split them into two 32-bit constants and combine them programmatically.
13563static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13564  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13565}
13566
13567
13568THREADED_TEST(QuietSignalingNaNs) {
13569  v8::HandleScope scope;
13570  LocalContext context;
13571  v8::TryCatch try_catch;
13572
13573  // Special double values.
13574  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13575  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13576  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13577  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13578  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13579  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13580  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13581
13582  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13583  // on either side of the epoch.
13584  double date_limit = 864e13;
13585
13586  double test_values[] = {
13587      snan,
13588      qnan,
13589      infinity,
13590      max_normal,
13591      date_limit + 1,
13592      date_limit,
13593      min_normal,
13594      max_denormal,
13595      min_denormal,
13596      0,
13597      -0,
13598      -min_denormal,
13599      -max_denormal,
13600      -min_normal,
13601      -date_limit,
13602      -date_limit - 1,
13603      -max_normal,
13604      -infinity,
13605      -qnan,
13606      -snan
13607  };
13608  int num_test_values = 20;
13609
13610  for (int i = 0; i < num_test_values; i++) {
13611    double test_value = test_values[i];
13612
13613    // Check that Number::New preserves non-NaNs and quiets SNaNs.
13614    v8::Handle<v8::Value> number = v8::Number::New(test_value);
13615    double stored_number = number->NumberValue();
13616    if (!IsNaN(test_value)) {
13617      CHECK_EQ(test_value, stored_number);
13618    } else {
13619      uint64_t stored_bits = DoubleToBits(stored_number);
13620      // Check if quiet nan (bits 51..62 all set).
13621#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13622      // Most significant fraction bit for quiet nan is set to 0
13623      // on MIPS architecture. Allowed by IEEE-754.
13624      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13625#else
13626      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13627#endif
13628    }
13629
13630    // Check that Date::New preserves non-NaNs in the date range and
13631    // quiets SNaNs.
13632    v8::Handle<v8::Value> date = v8::Date::New(test_value);
13633    double expected_stored_date = DoubleToDateTime(test_value);
13634    double stored_date = date->NumberValue();
13635    if (!IsNaN(expected_stored_date)) {
13636      CHECK_EQ(expected_stored_date, stored_date);
13637    } else {
13638      uint64_t stored_bits = DoubleToBits(stored_date);
13639      // Check if quiet nan (bits 51..62 all set).
13640#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
13641      // Most significant fraction bit for quiet nan is set to 0
13642      // on MIPS architecture. Allowed by IEEE-754.
13643      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
13644#else
13645      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13646#endif
13647    }
13648  }
13649}
13650
13651
13652static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13653  v8::HandleScope scope;
13654  v8::TryCatch tc;
13655  v8::Handle<v8::String> str(args[0]->ToString());
13656  if (tc.HasCaught())
13657    return tc.ReThrow();
13658  return v8::Undefined();
13659}
13660
13661
13662// Test that an exception can be propagated down through a spaghetti
13663// stack using ReThrow.
13664THREADED_TEST(SpaghettiStackReThrow) {
13665  v8::HandleScope scope;
13666  LocalContext context;
13667  context->Global()->Set(
13668      v8::String::New("s"),
13669      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13670  v8::TryCatch try_catch;
13671  CompileRun(
13672      "var i = 0;"
13673      "var o = {"
13674      "  toString: function () {"
13675      "    if (i == 10) {"
13676      "      throw 'Hey!';"
13677      "    } else {"
13678      "      i++;"
13679      "      return s(o);"
13680      "    }"
13681      "  }"
13682      "};"
13683      "s(o);");
13684  CHECK(try_catch.HasCaught());
13685  v8::String::Utf8Value value(try_catch.Exception());
13686  CHECK_EQ(0, strcmp(*value, "Hey!"));
13687}
13688
13689
13690TEST(Regress528) {
13691  v8::V8::Initialize();
13692
13693  v8::HandleScope scope;
13694  v8::Persistent<Context> context;
13695  v8::Persistent<Context> other_context;
13696  int gc_count;
13697
13698  // Create a context used to keep the code from aging in the compilation
13699  // cache.
13700  other_context = Context::New();
13701
13702  // Context-dependent context data creates reference from the compilation
13703  // cache to the global object.
13704  const char* source_simple = "1";
13705  context = Context::New();
13706  {
13707    v8::HandleScope scope;
13708
13709    context->Enter();
13710    Local<v8::String> obj = v8::String::New("");
13711    context->SetData(obj);
13712    CompileRun(source_simple);
13713    context->Exit();
13714  }
13715  context.Dispose();
13716  for (gc_count = 1; gc_count < 10; gc_count++) {
13717    other_context->Enter();
13718    CompileRun(source_simple);
13719    other_context->Exit();
13720    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13721    if (GetGlobalObjectsCount() == 1) break;
13722  }
13723  CHECK_GE(2, gc_count);
13724  CHECK_EQ(1, GetGlobalObjectsCount());
13725
13726  // Eval in a function creates reference from the compilation cache to the
13727  // global object.
13728  const char* source_eval = "function f(){eval('1')}; f()";
13729  context = Context::New();
13730  {
13731    v8::HandleScope scope;
13732
13733    context->Enter();
13734    CompileRun(source_eval);
13735    context->Exit();
13736  }
13737  context.Dispose();
13738  for (gc_count = 1; gc_count < 10; gc_count++) {
13739    other_context->Enter();
13740    CompileRun(source_eval);
13741    other_context->Exit();
13742    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13743    if (GetGlobalObjectsCount() == 1) break;
13744  }
13745  CHECK_GE(2, gc_count);
13746  CHECK_EQ(1, GetGlobalObjectsCount());
13747
13748  // Looking up the line number for an exception creates reference from the
13749  // compilation cache to the global object.
13750  const char* source_exception = "function f(){throw 1;} f()";
13751  context = Context::New();
13752  {
13753    v8::HandleScope scope;
13754
13755    context->Enter();
13756    v8::TryCatch try_catch;
13757    CompileRun(source_exception);
13758    CHECK(try_catch.HasCaught());
13759    v8::Handle<v8::Message> message = try_catch.Message();
13760    CHECK(!message.IsEmpty());
13761    CHECK_EQ(1, message->GetLineNumber());
13762    context->Exit();
13763  }
13764  context.Dispose();
13765  for (gc_count = 1; gc_count < 10; gc_count++) {
13766    other_context->Enter();
13767    CompileRun(source_exception);
13768    other_context->Exit();
13769    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13770    if (GetGlobalObjectsCount() == 1) break;
13771  }
13772  CHECK_GE(2, gc_count);
13773  CHECK_EQ(1, GetGlobalObjectsCount());
13774
13775  other_context.Dispose();
13776}
13777
13778
13779THREADED_TEST(ScriptOrigin) {
13780  v8::HandleScope scope;
13781  LocalContext env;
13782  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13783  v8::Handle<v8::String> script = v8::String::New(
13784      "function f() {}\n\nfunction g() {}");
13785  v8::Script::Compile(script, &origin)->Run();
13786  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13787      env->Global()->Get(v8::String::New("f")));
13788  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13789      env->Global()->Get(v8::String::New("g")));
13790
13791  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13792  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13793  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13794
13795  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13796  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13797  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13798}
13799
13800
13801THREADED_TEST(ScriptLineNumber) {
13802  v8::HandleScope scope;
13803  LocalContext env;
13804  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13805  v8::Handle<v8::String> script = v8::String::New(
13806      "function f() {}\n\nfunction g() {}");
13807  v8::Script::Compile(script, &origin)->Run();
13808  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13809      env->Global()->Get(v8::String::New("f")));
13810  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13811      env->Global()->Get(v8::String::New("g")));
13812  CHECK_EQ(0, f->GetScriptLineNumber());
13813  CHECK_EQ(2, g->GetScriptLineNumber());
13814}
13815
13816
13817THREADED_TEST(ScriptColumnNumber) {
13818  v8::HandleScope scope;
13819  LocalContext env;
13820  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13821      v8::Integer::New(3), v8::Integer::New(2));
13822  v8::Handle<v8::String> script = v8::String::New(
13823      "function foo() {}\n\n     function bar() {}");
13824  v8::Script::Compile(script, &origin)->Run();
13825  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13826      env->Global()->Get(v8::String::New("foo")));
13827  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13828      env->Global()->Get(v8::String::New("bar")));
13829  CHECK_EQ(14, foo->GetScriptColumnNumber());
13830  CHECK_EQ(17, bar->GetScriptColumnNumber());
13831}
13832
13833
13834THREADED_TEST(FunctionGetScriptId) {
13835  v8::HandleScope scope;
13836  LocalContext env;
13837  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
13838      v8::Integer::New(3), v8::Integer::New(2));
13839  v8::Handle<v8::String> scriptSource = v8::String::New(
13840      "function foo() {}\n\n     function bar() {}");
13841  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
13842  script->Run();
13843  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
13844      env->Global()->Get(v8::String::New("foo")));
13845  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
13846      env->Global()->Get(v8::String::New("bar")));
13847  CHECK_EQ(script->Id(), foo->GetScriptId());
13848  CHECK_EQ(script->Id(), bar->GetScriptId());
13849}
13850
13851
13852static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13853                                              const AccessorInfo& info) {
13854  return v8_num(42);
13855}
13856
13857
13858static void SetterWhichSetsYOnThisTo23(Local<String> name,
13859                                       Local<Value> value,
13860                                       const AccessorInfo& info) {
13861  info.This()->Set(v8_str("y"), v8_num(23));
13862}
13863
13864
13865TEST(SetterOnConstructorPrototype) {
13866  v8::HandleScope scope;
13867  Local<ObjectTemplate> templ = ObjectTemplate::New();
13868  templ->SetAccessor(v8_str("x"),
13869                     GetterWhichReturns42,
13870                     SetterWhichSetsYOnThisTo23);
13871  LocalContext context;
13872  context->Global()->Set(v8_str("P"), templ->NewInstance());
13873  CompileRun("function C1() {"
13874             "  this.x = 23;"
13875             "};"
13876             "C1.prototype = P;"
13877             "function C2() {"
13878             "  this.x = 23"
13879             "};"
13880             "C2.prototype = { };"
13881             "C2.prototype.__proto__ = P;");
13882
13883  v8::Local<v8::Script> script;
13884  script = v8::Script::Compile(v8_str("new C1();"));
13885  for (int i = 0; i < 10; i++) {
13886    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13887    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13888    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13889  }
13890
13891  script = v8::Script::Compile(v8_str("new C2();"));
13892  for (int i = 0; i < 10; i++) {
13893    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13894    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13895    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13896  }
13897}
13898
13899
13900static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13901    Local<String> name, const AccessorInfo& info) {
13902  return v8_num(42);
13903}
13904
13905
13906static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13907    Local<String> name, Local<Value> value, const AccessorInfo& info) {
13908  if (name->Equals(v8_str("x"))) {
13909    info.This()->Set(v8_str("y"), v8_num(23));
13910  }
13911  return v8::Handle<Value>();
13912}
13913
13914
13915THREADED_TEST(InterceptorOnConstructorPrototype) {
13916  v8::HandleScope scope;
13917  Local<ObjectTemplate> templ = ObjectTemplate::New();
13918  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13919                                 NamedPropertySetterWhichSetsYOnThisTo23);
13920  LocalContext context;
13921  context->Global()->Set(v8_str("P"), templ->NewInstance());
13922  CompileRun("function C1() {"
13923             "  this.x = 23;"
13924             "};"
13925             "C1.prototype = P;"
13926             "function C2() {"
13927             "  this.x = 23"
13928             "};"
13929             "C2.prototype = { };"
13930             "C2.prototype.__proto__ = P;");
13931
13932  v8::Local<v8::Script> script;
13933  script = v8::Script::Compile(v8_str("new C1();"));
13934  for (int i = 0; i < 10; i++) {
13935    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13936    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13937    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13938  }
13939
13940  script = v8::Script::Compile(v8_str("new C2();"));
13941  for (int i = 0; i < 10; i++) {
13942    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13943    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13944    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13945  }
13946}
13947
13948
13949TEST(Bug618) {
13950  const char* source = "function C1() {"
13951                       "  this.x = 23;"
13952                       "};"
13953                       "C1.prototype = P;";
13954
13955  v8::HandleScope scope;
13956  LocalContext context;
13957  v8::Local<v8::Script> script;
13958
13959  // Use a simple object as prototype.
13960  v8::Local<v8::Object> prototype = v8::Object::New();
13961  prototype->Set(v8_str("y"), v8_num(42));
13962  context->Global()->Set(v8_str("P"), prototype);
13963
13964  // This compile will add the code to the compilation cache.
13965  CompileRun(source);
13966
13967  script = v8::Script::Compile(v8_str("new C1();"));
13968  // Allow enough iterations for the inobject slack tracking logic
13969  // to finalize instance size and install the fast construct stub.
13970  for (int i = 0; i < 256; i++) {
13971    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13972    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13973    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13974  }
13975
13976  // Use an API object with accessors as prototype.
13977  Local<ObjectTemplate> templ = ObjectTemplate::New();
13978  templ->SetAccessor(v8_str("x"),
13979                     GetterWhichReturns42,
13980                     SetterWhichSetsYOnThisTo23);
13981  context->Global()->Set(v8_str("P"), templ->NewInstance());
13982
13983  // This compile will get the code from the compilation cache.
13984  CompileRun(source);
13985
13986  script = v8::Script::Compile(v8_str("new C1();"));
13987  for (int i = 0; i < 10; i++) {
13988    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13989    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13990    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13991  }
13992}
13993
13994int prologue_call_count = 0;
13995int epilogue_call_count = 0;
13996int prologue_call_count_second = 0;
13997int epilogue_call_count_second = 0;
13998
13999void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
14000  ++prologue_call_count;
14001}
14002
14003void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
14004  ++epilogue_call_count;
14005}
14006
14007void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14008  ++prologue_call_count_second;
14009}
14010
14011void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
14012  ++epilogue_call_count_second;
14013}
14014
14015TEST(GCCallbacks) {
14016  LocalContext context;
14017
14018  v8::V8::AddGCPrologueCallback(PrologueCallback);
14019  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
14020  CHECK_EQ(0, prologue_call_count);
14021  CHECK_EQ(0, epilogue_call_count);
14022  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14023  CHECK_EQ(1, prologue_call_count);
14024  CHECK_EQ(1, epilogue_call_count);
14025  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
14026  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
14027  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14028  CHECK_EQ(2, prologue_call_count);
14029  CHECK_EQ(2, epilogue_call_count);
14030  CHECK_EQ(1, prologue_call_count_second);
14031  CHECK_EQ(1, epilogue_call_count_second);
14032  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
14033  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
14034  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14035  CHECK_EQ(2, prologue_call_count);
14036  CHECK_EQ(2, epilogue_call_count);
14037  CHECK_EQ(2, prologue_call_count_second);
14038  CHECK_EQ(2, epilogue_call_count_second);
14039  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
14040  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
14041  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14042  CHECK_EQ(2, prologue_call_count);
14043  CHECK_EQ(2, epilogue_call_count);
14044  CHECK_EQ(2, prologue_call_count_second);
14045  CHECK_EQ(2, epilogue_call_count_second);
14046}
14047
14048
14049THREADED_TEST(AddToJSFunctionResultCache) {
14050  i::FLAG_allow_natives_syntax = true;
14051  v8::HandleScope scope;
14052
14053  LocalContext context;
14054
14055  const char* code =
14056      "(function() {"
14057      "  var key0 = 'a';"
14058      "  var key1 = 'b';"
14059      "  var r0 = %_GetFromCache(0, key0);"
14060      "  var r1 = %_GetFromCache(0, key1);"
14061      "  var r0_ = %_GetFromCache(0, key0);"
14062      "  if (r0 !== r0_)"
14063      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
14064      "  var r1_ = %_GetFromCache(0, key1);"
14065      "  if (r1 !== r1_)"
14066      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
14067      "  return 'PASSED';"
14068      "})()";
14069  HEAP->ClearJSFunctionResultCaches();
14070  ExpectString(code, "PASSED");
14071}
14072
14073
14074static const int k0CacheSize = 16;
14075
14076THREADED_TEST(FillJSFunctionResultCache) {
14077  i::FLAG_allow_natives_syntax = true;
14078  v8::HandleScope scope;
14079
14080  LocalContext context;
14081
14082  const char* code =
14083      "(function() {"
14084      "  var k = 'a';"
14085      "  var r = %_GetFromCache(0, k);"
14086      "  for (var i = 0; i < 16; i++) {"
14087      "    %_GetFromCache(0, 'a' + i);"
14088      "  };"
14089      "  if (r === %_GetFromCache(0, k))"
14090      "    return 'FAILED: k0CacheSize is too small';"
14091      "  return 'PASSED';"
14092      "})()";
14093  HEAP->ClearJSFunctionResultCaches();
14094  ExpectString(code, "PASSED");
14095}
14096
14097
14098THREADED_TEST(RoundRobinGetFromCache) {
14099  i::FLAG_allow_natives_syntax = true;
14100  v8::HandleScope scope;
14101
14102  LocalContext context;
14103
14104  const char* code =
14105      "(function() {"
14106      "  var keys = [];"
14107      "  for (var i = 0; i < 16; i++) keys.push(i);"
14108      "  var values = [];"
14109      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14110      "  for (var i = 0; i < 16; i++) {"
14111      "    var v = %_GetFromCache(0, keys[i]);"
14112      "    if (v !== values[i])"
14113      "      return 'Wrong value for ' + "
14114      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14115      "  };"
14116      "  return 'PASSED';"
14117      "})()";
14118  HEAP->ClearJSFunctionResultCaches();
14119  ExpectString(code, "PASSED");
14120}
14121
14122
14123THREADED_TEST(ReverseGetFromCache) {
14124  i::FLAG_allow_natives_syntax = true;
14125  v8::HandleScope scope;
14126
14127  LocalContext context;
14128
14129  const char* code =
14130      "(function() {"
14131      "  var keys = [];"
14132      "  for (var i = 0; i < 16; i++) keys.push(i);"
14133      "  var values = [];"
14134      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14135      "  for (var i = 15; i >= 16; i--) {"
14136      "    var v = %_GetFromCache(0, keys[i]);"
14137      "    if (v !== values[i])"
14138      "      return 'Wrong value for ' + "
14139      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14140      "  };"
14141      "  return 'PASSED';"
14142      "})()";
14143  HEAP->ClearJSFunctionResultCaches();
14144  ExpectString(code, "PASSED");
14145}
14146
14147
14148THREADED_TEST(TestEviction) {
14149  i::FLAG_allow_natives_syntax = true;
14150  v8::HandleScope scope;
14151
14152  LocalContext context;
14153
14154  const char* code =
14155      "(function() {"
14156      "  for (var i = 0; i < 2*16; i++) {"
14157      "    %_GetFromCache(0, 'a' + i);"
14158      "  };"
14159      "  return 'PASSED';"
14160      "})()";
14161  HEAP->ClearJSFunctionResultCaches();
14162  ExpectString(code, "PASSED");
14163}
14164
14165
14166THREADED_TEST(TwoByteStringInAsciiCons) {
14167  // See Chromium issue 47824.
14168  v8::HandleScope scope;
14169
14170  LocalContext context;
14171  const char* init_code =
14172      "var str1 = 'abelspendabel';"
14173      "var str2 = str1 + str1 + str1;"
14174      "str2;";
14175  Local<Value> result = CompileRun(init_code);
14176
14177  Local<Value> indexof = CompileRun("str2.indexOf('els')");
14178  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14179
14180  CHECK(result->IsString());
14181  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14182  int length = string->length();
14183  CHECK(string->IsAsciiRepresentation());
14184
14185  FlattenString(string);
14186  i::Handle<i::String> flat_string = FlattenGetString(string);
14187
14188  CHECK(string->IsAsciiRepresentation());
14189  CHECK(flat_string->IsAsciiRepresentation());
14190
14191  // Create external resource.
14192  uint16_t* uc16_buffer = new uint16_t[length + 1];
14193
14194  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14195  uc16_buffer[length] = 0;
14196
14197  TestResource resource(uc16_buffer);
14198
14199  flat_string->MakeExternal(&resource);
14200
14201  CHECK(flat_string->IsTwoByteRepresentation());
14202
14203  // At this point, we should have a Cons string which is flat and ASCII,
14204  // with a first half that is a two-byte string (although it only contains
14205  // ASCII characters). This is a valid sequence of steps, and it can happen
14206  // in real pages.
14207
14208  CHECK(string->IsAsciiRepresentation());
14209  i::ConsString* cons = i::ConsString::cast(*string);
14210  CHECK_EQ(0, cons->second()->length());
14211  CHECK(cons->first()->IsTwoByteRepresentation());
14212
14213  // Check that some string operations work.
14214
14215  // Atom RegExp.
14216  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14217  CHECK_EQ(6, reresult->Int32Value());
14218
14219  // Nonatom RegExp.
14220  reresult = CompileRun("str2.match(/abe./g).length;");
14221  CHECK_EQ(6, reresult->Int32Value());
14222
14223  reresult = CompileRun("str2.search(/bel/g);");
14224  CHECK_EQ(1, reresult->Int32Value());
14225
14226  reresult = CompileRun("str2.search(/be./g);");
14227  CHECK_EQ(1, reresult->Int32Value());
14228
14229  ExpectTrue("/bel/g.test(str2);");
14230
14231  ExpectTrue("/be./g.test(str2);");
14232
14233  reresult = CompileRun("/bel/g.exec(str2);");
14234  CHECK(!reresult->IsNull());
14235
14236  reresult = CompileRun("/be./g.exec(str2);");
14237  CHECK(!reresult->IsNull());
14238
14239  ExpectString("str2.substring(2, 10);", "elspenda");
14240
14241  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14242
14243  ExpectString("str2.charAt(2);", "e");
14244
14245  ExpectObject("str2.indexOf('els');", indexof);
14246
14247  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14248
14249  reresult = CompileRun("str2.charCodeAt(2);");
14250  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14251}
14252
14253
14254// Failed access check callback that performs a GC on each invocation.
14255void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14256                                 v8::AccessType type,
14257                                 Local<v8::Value> data) {
14258  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14259}
14260
14261
14262TEST(GCInFailedAccessCheckCallback) {
14263  // Install a failed access check callback that performs a GC on each
14264  // invocation. Then force the callback to be called from va
14265
14266  v8::V8::Initialize();
14267  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14268
14269  v8::HandleScope scope;
14270
14271  // Create an ObjectTemplate for global objects and install access
14272  // check callbacks that will block access.
14273  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14274  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14275                                           IndexedGetAccessBlocker,
14276                                           v8::Handle<v8::Value>(),
14277                                           false);
14278
14279  // Create a context and set an x property on it's global object.
14280  LocalContext context0(NULL, global_template);
14281  context0->Global()->Set(v8_str("x"), v8_num(42));
14282  v8::Handle<v8::Object> global0 = context0->Global();
14283
14284  // Create a context with a different security token so that the
14285  // failed access check callback will be called on each access.
14286  LocalContext context1(NULL, global_template);
14287  context1->Global()->Set(v8_str("other"), global0);
14288
14289  // Get property with failed access check.
14290  ExpectUndefined("other.x");
14291
14292  // Get element with failed access check.
14293  ExpectUndefined("other[0]");
14294
14295  // Set property with failed access check.
14296  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14297  CHECK(result->IsObject());
14298
14299  // Set element with failed access check.
14300  result = CompileRun("other[0] = new Object()");
14301  CHECK(result->IsObject());
14302
14303  // Get property attribute with failed access check.
14304  ExpectFalse("\'x\' in other");
14305
14306  // Get property attribute for element with failed access check.
14307  ExpectFalse("0 in other");
14308
14309  // Delete property.
14310  ExpectFalse("delete other.x");
14311
14312  // Delete element.
14313  CHECK_EQ(false, global0->Delete(0));
14314
14315  // DefineAccessor.
14316  CHECK_EQ(false,
14317           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14318
14319  // Define JavaScript accessor.
14320  ExpectUndefined("Object.prototype.__defineGetter__.call("
14321                  "    other, \'x\', function() { return 42; })");
14322
14323  // LookupAccessor.
14324  ExpectUndefined("Object.prototype.__lookupGetter__.call("
14325                  "    other, \'x\')");
14326
14327  // HasLocalElement.
14328  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14329
14330  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14331  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14332  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14333
14334  // Reset the failed access check callback so it does not influence
14335  // the other tests.
14336  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14337}
14338
14339TEST(DefaultIsolateGetCurrent) {
14340  CHECK(v8::Isolate::GetCurrent() != NULL);
14341  v8::Isolate* isolate = v8::Isolate::GetCurrent();
14342  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14343  printf("*** %s\n", "DefaultIsolateGetCurrent success");
14344}
14345
14346TEST(IsolateNewDispose) {
14347  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14348  v8::Isolate* isolate = v8::Isolate::New();
14349  CHECK(isolate != NULL);
14350  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14351  CHECK(current_isolate != isolate);
14352  CHECK(current_isolate == v8::Isolate::GetCurrent());
14353
14354  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14355  last_location = last_message = NULL;
14356  isolate->Dispose();
14357  CHECK_EQ(last_location, NULL);
14358  CHECK_EQ(last_message, NULL);
14359}
14360
14361TEST(IsolateEnterExitDefault) {
14362  v8::HandleScope scope;
14363  LocalContext context;
14364  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14365  CHECK(current_isolate != NULL);  // Default isolate.
14366  ExpectString("'hello'", "hello");
14367  current_isolate->Enter();
14368  ExpectString("'still working'", "still working");
14369  current_isolate->Exit();
14370  ExpectString("'still working 2'", "still working 2");
14371  current_isolate->Exit();
14372  // Default isolate is always, well, 'default current'.
14373  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14374  // Still working since default isolate is auto-entering any thread
14375  // that has no isolate and attempts to execute V8 APIs.
14376  ExpectString("'still working 3'", "still working 3");
14377}
14378
14379TEST(DisposeDefaultIsolate) {
14380  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14381
14382  // Run some V8 code to trigger default isolate to become 'current'.
14383  v8::HandleScope scope;
14384  LocalContext context;
14385  ExpectString("'run some V8'", "run some V8");
14386
14387  v8::Isolate* isolate = v8::Isolate::GetCurrent();
14388  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14389  last_location = last_message = NULL;
14390  isolate->Dispose();
14391  // It is not possible to dispose default isolate via Isolate API.
14392  CHECK_NE(last_location, NULL);
14393  CHECK_NE(last_message, NULL);
14394}
14395
14396TEST(RunDefaultAndAnotherIsolate) {
14397  v8::HandleScope scope;
14398  LocalContext context;
14399
14400  // Enter new isolate.
14401  v8::Isolate* isolate = v8::Isolate::New();
14402  CHECK(isolate);
14403  isolate->Enter();
14404  { // Need this block because subsequent Exit() will deallocate Heap,
14405    // so we need all scope objects to be deconstructed when it happens.
14406    v8::HandleScope scope_new;
14407    LocalContext context_new;
14408
14409    // Run something in new isolate.
14410    CompileRun("var foo = 153;");
14411    ExpectTrue("function f() { return foo == 153; }; f()");
14412  }
14413  isolate->Exit();
14414
14415  // This runs automatically in default isolate.
14416  // Variables in another isolate should be not available.
14417  ExpectTrue("function f() {"
14418             "  try {"
14419             "    foo;"
14420             "    return false;"
14421             "  } catch(e) {"
14422             "    return true;"
14423             "  }"
14424             "};"
14425             "var bar = 371;"
14426             "f()");
14427
14428  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14429  last_location = last_message = NULL;
14430  isolate->Dispose();
14431  CHECK_EQ(last_location, NULL);
14432  CHECK_EQ(last_message, NULL);
14433
14434  // Check that default isolate still runs.
14435  ExpectTrue("function f() { return bar == 371; }; f()");
14436}
14437
14438TEST(DisposeIsolateWhenInUse) {
14439  v8::Isolate* isolate = v8::Isolate::New();
14440  CHECK(isolate);
14441  isolate->Enter();
14442  v8::HandleScope scope;
14443  LocalContext context;
14444  // Run something in this isolate.
14445  ExpectTrue("true");
14446  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14447  last_location = last_message = NULL;
14448  // Still entered, should fail.
14449  isolate->Dispose();
14450  CHECK_NE(last_location, NULL);
14451  CHECK_NE(last_message, NULL);
14452}
14453
14454TEST(RunTwoIsolatesOnSingleThread) {
14455  // Run isolate 1.
14456  v8::Isolate* isolate1 = v8::Isolate::New();
14457  isolate1->Enter();
14458  v8::Persistent<v8::Context> context1 = v8::Context::New();
14459
14460  {
14461    v8::Context::Scope cscope(context1);
14462    v8::HandleScope scope;
14463    // Run something in new isolate.
14464    CompileRun("var foo = 'isolate 1';");
14465    ExpectString("function f() { return foo; }; f()", "isolate 1");
14466  }
14467
14468  // Run isolate 2.
14469  v8::Isolate* isolate2 = v8::Isolate::New();
14470  v8::Persistent<v8::Context> context2;
14471
14472  {
14473    v8::Isolate::Scope iscope(isolate2);
14474    context2 = v8::Context::New();
14475    v8::Context::Scope cscope(context2);
14476    v8::HandleScope scope;
14477
14478    // Run something in new isolate.
14479    CompileRun("var foo = 'isolate 2';");
14480    ExpectString("function f() { return foo; }; f()", "isolate 2");
14481  }
14482
14483  {
14484    v8::Context::Scope cscope(context1);
14485    v8::HandleScope scope;
14486    // Now again in isolate 1
14487    ExpectString("function f() { return foo; }; f()", "isolate 1");
14488  }
14489
14490  isolate1->Exit();
14491
14492  // Run some stuff in default isolate.
14493  v8::Persistent<v8::Context> context_default = v8::Context::New();
14494
14495  {
14496    v8::Context::Scope cscope(context_default);
14497    v8::HandleScope scope;
14498    // Variables in other isolates should be not available, verify there
14499    // is an exception.
14500    ExpectTrue("function f() {"
14501               "  try {"
14502               "    foo;"
14503               "    return false;"
14504               "  } catch(e) {"
14505               "    return true;"
14506               "  }"
14507               "};"
14508               "var isDefaultIsolate = true;"
14509               "f()");
14510  }
14511
14512  isolate1->Enter();
14513
14514  {
14515    v8::Isolate::Scope iscope(isolate2);
14516    v8::Context::Scope cscope(context2);
14517    v8::HandleScope scope;
14518    ExpectString("function f() { return foo; }; f()", "isolate 2");
14519  }
14520
14521  {
14522    v8::Context::Scope cscope(context1);
14523    v8::HandleScope scope;
14524    ExpectString("function f() { return foo; }; f()", "isolate 1");
14525  }
14526
14527  {
14528    v8::Isolate::Scope iscope(isolate2);
14529    context2.Dispose();
14530  }
14531
14532  context1.Dispose();
14533  isolate1->Exit();
14534
14535  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14536  last_location = last_message = NULL;
14537
14538  isolate1->Dispose();
14539  CHECK_EQ(last_location, NULL);
14540  CHECK_EQ(last_message, NULL);
14541
14542  isolate2->Dispose();
14543  CHECK_EQ(last_location, NULL);
14544  CHECK_EQ(last_message, NULL);
14545
14546  // Check that default isolate still runs.
14547  {
14548    v8::Context::Scope cscope(context_default);
14549    v8::HandleScope scope;
14550    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14551  }
14552}
14553
14554static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14555  v8::Isolate::Scope isolate_scope(isolate);
14556  v8::HandleScope scope;
14557  LocalContext context;
14558  i::ScopedVector<char> code(1024);
14559  i::OS::SNPrintF(code, "function fib(n) {"
14560                        "  if (n <= 2) return 1;"
14561                        "  return fib(n-1) + fib(n-2);"
14562                        "}"
14563                        "fib(%d)", limit);
14564  Local<Value> value = CompileRun(code.start());
14565  CHECK(value->IsNumber());
14566  return static_cast<int>(value->NumberValue());
14567}
14568
14569class IsolateThread : public v8::internal::Thread {
14570 public:
14571  IsolateThread(v8::Isolate* isolate, int fib_limit)
14572      : Thread("IsolateThread"),
14573        isolate_(isolate),
14574        fib_limit_(fib_limit),
14575        result_(0) { }
14576
14577  void Run() {
14578    result_ = CalcFibonacci(isolate_, fib_limit_);
14579  }
14580
14581  int result() { return result_; }
14582
14583 private:
14584  v8::Isolate* isolate_;
14585  int fib_limit_;
14586  int result_;
14587};
14588
14589TEST(MultipleIsolatesOnIndividualThreads) {
14590  v8::Isolate* isolate1 = v8::Isolate::New();
14591  v8::Isolate* isolate2 = v8::Isolate::New();
14592
14593  IsolateThread thread1(isolate1, 21);
14594  IsolateThread thread2(isolate2, 12);
14595
14596  // Compute some fibonacci numbers on 3 threads in 3 isolates.
14597  thread1.Start();
14598  thread2.Start();
14599
14600  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14601  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14602
14603  thread1.Join();
14604  thread2.Join();
14605
14606  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14607  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14608  CHECK_EQ(result1, 10946);
14609  CHECK_EQ(result2, 144);
14610  CHECK_EQ(result1, thread1.result());
14611  CHECK_EQ(result2, thread2.result());
14612
14613  isolate1->Dispose();
14614  isolate2->Dispose();
14615}
14616
14617TEST(IsolateDifferentContexts) {
14618  v8::Isolate* isolate = v8::Isolate::New();
14619  Persistent<v8::Context> context;
14620  {
14621    v8::Isolate::Scope isolate_scope(isolate);
14622    v8::HandleScope handle_scope;
14623    context = v8::Context::New();
14624    v8::Context::Scope context_scope(context);
14625    Local<Value> v = CompileRun("2");
14626    CHECK(v->IsNumber());
14627    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14628  }
14629  {
14630    v8::Isolate::Scope isolate_scope(isolate);
14631    v8::HandleScope handle_scope;
14632    context = v8::Context::New();
14633    v8::Context::Scope context_scope(context);
14634    Local<Value> v = CompileRun("22");
14635    CHECK(v->IsNumber());
14636    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14637  }
14638}
14639
14640class InitDefaultIsolateThread : public v8::internal::Thread {
14641 public:
14642  enum TestCase {
14643    IgnoreOOM,
14644    SetResourceConstraints,
14645    SetFatalHandler,
14646    SetCounterFunction,
14647    SetCreateHistogramFunction,
14648    SetAddHistogramSampleFunction
14649  };
14650
14651  explicit InitDefaultIsolateThread(TestCase testCase)
14652      : Thread("InitDefaultIsolateThread"),
14653        testCase_(testCase),
14654        result_(false) { }
14655
14656  void Run() {
14657    switch (testCase_) {
14658    case IgnoreOOM:
14659      v8::V8::IgnoreOutOfMemoryException();
14660      break;
14661
14662    case SetResourceConstraints: {
14663      static const int K = 1024;
14664      v8::ResourceConstraints constraints;
14665      constraints.set_max_young_space_size(256 * K);
14666      constraints.set_max_old_space_size(4 * K * K);
14667      v8::SetResourceConstraints(&constraints);
14668      break;
14669    }
14670
14671    case SetFatalHandler:
14672      v8::V8::SetFatalErrorHandler(NULL);
14673      break;
14674
14675    case SetCounterFunction:
14676      v8::V8::SetCounterFunction(NULL);
14677      break;
14678
14679    case SetCreateHistogramFunction:
14680      v8::V8::SetCreateHistogramFunction(NULL);
14681      break;
14682
14683    case SetAddHistogramSampleFunction:
14684      v8::V8::SetAddHistogramSampleFunction(NULL);
14685      break;
14686    }
14687    result_ = true;
14688  }
14689
14690  bool result() { return result_; }
14691
14692 private:
14693  TestCase testCase_;
14694  bool result_;
14695};
14696
14697
14698static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14699  InitDefaultIsolateThread thread(testCase);
14700  thread.Start();
14701  thread.Join();
14702  CHECK_EQ(thread.result(), true);
14703}
14704
14705TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14706  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14707}
14708
14709TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14710  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14711}
14712
14713TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14714  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14715}
14716
14717TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14718  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14719}
14720
14721TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14722  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14723}
14724
14725TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14726  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14727}
14728
14729
14730TEST(StringCheckMultipleContexts) {
14731  const char* code =
14732      "(function() { return \"a\".charAt(0); })()";
14733
14734  {
14735    // Run the code twice in the first context to initialize the call IC.
14736    v8::HandleScope scope;
14737    LocalContext context1;
14738    ExpectString(code, "a");
14739    ExpectString(code, "a");
14740  }
14741
14742  {
14743    // Change the String.prototype in the second context and check
14744    // that the right function gets called.
14745    v8::HandleScope scope;
14746    LocalContext context2;
14747    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14748    ExpectString(code, "not a");
14749  }
14750}
14751
14752
14753TEST(NumberCheckMultipleContexts) {
14754  const char* code =
14755      "(function() { return (42).toString(); })()";
14756
14757  {
14758    // Run the code twice in the first context to initialize the call IC.
14759    v8::HandleScope scope;
14760    LocalContext context1;
14761    ExpectString(code, "42");
14762    ExpectString(code, "42");
14763  }
14764
14765  {
14766    // Change the Number.prototype in the second context and check
14767    // that the right function gets called.
14768    v8::HandleScope scope;
14769    LocalContext context2;
14770    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14771    ExpectString(code, "not 42");
14772  }
14773}
14774
14775
14776TEST(BooleanCheckMultipleContexts) {
14777  const char* code =
14778      "(function() { return true.toString(); })()";
14779
14780  {
14781    // Run the code twice in the first context to initialize the call IC.
14782    v8::HandleScope scope;
14783    LocalContext context1;
14784    ExpectString(code, "true");
14785    ExpectString(code, "true");
14786  }
14787
14788  {
14789    // Change the Boolean.prototype in the second context and check
14790    // that the right function gets called.
14791    v8::HandleScope scope;
14792    LocalContext context2;
14793    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14794    ExpectString(code, "");
14795  }
14796}
14797
14798
14799TEST(DontDeleteCellLoadIC) {
14800  const char* function_code =
14801      "function readCell() { while (true) { return cell; } }";
14802
14803  {
14804    // Run the code twice in the first context to initialize the load
14805    // IC for a don't delete cell.
14806    v8::HandleScope scope;
14807    LocalContext context1;
14808    CompileRun("var cell = \"first\";");
14809    ExpectBoolean("delete cell", false);
14810    CompileRun(function_code);
14811    ExpectString("readCell()", "first");
14812    ExpectString("readCell()", "first");
14813  }
14814
14815  {
14816    // Use a deletable cell in the second context.
14817    v8::HandleScope scope;
14818    LocalContext context2;
14819    CompileRun("cell = \"second\";");
14820    CompileRun(function_code);
14821    ExpectString("readCell()", "second");
14822    ExpectBoolean("delete cell", true);
14823    ExpectString("(function() {"
14824                 "  try {"
14825                 "    return readCell();"
14826                 "  } catch(e) {"
14827                 "    return e.toString();"
14828                 "  }"
14829                 "})()",
14830                 "ReferenceError: cell is not defined");
14831    CompileRun("cell = \"new_second\";");
14832    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14833    ExpectString("readCell()", "new_second");
14834    ExpectString("readCell()", "new_second");
14835  }
14836}
14837
14838
14839TEST(DontDeleteCellLoadICForceDelete) {
14840  const char* function_code =
14841      "function readCell() { while (true) { return cell; } }";
14842
14843  // Run the code twice to initialize the load IC for a don't delete
14844  // cell.
14845  v8::HandleScope scope;
14846  LocalContext context;
14847  CompileRun("var cell = \"value\";");
14848  ExpectBoolean("delete cell", false);
14849  CompileRun(function_code);
14850  ExpectString("readCell()", "value");
14851  ExpectString("readCell()", "value");
14852
14853  // Delete the cell using the API and check the inlined code works
14854  // correctly.
14855  CHECK(context->Global()->ForceDelete(v8_str("cell")));
14856  ExpectString("(function() {"
14857               "  try {"
14858               "    return readCell();"
14859               "  } catch(e) {"
14860               "    return e.toString();"
14861               "  }"
14862               "})()",
14863               "ReferenceError: cell is not defined");
14864}
14865
14866
14867TEST(DontDeleteCellLoadICAPI) {
14868  const char* function_code =
14869      "function readCell() { while (true) { return cell; } }";
14870
14871  // Run the code twice to initialize the load IC for a don't delete
14872  // cell created using the API.
14873  v8::HandleScope scope;
14874  LocalContext context;
14875  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14876  ExpectBoolean("delete cell", false);
14877  CompileRun(function_code);
14878  ExpectString("readCell()", "value");
14879  ExpectString("readCell()", "value");
14880
14881  // Delete the cell using the API and check the inlined code works
14882  // correctly.
14883  CHECK(context->Global()->ForceDelete(v8_str("cell")));
14884  ExpectString("(function() {"
14885               "  try {"
14886               "    return readCell();"
14887               "  } catch(e) {"
14888               "    return e.toString();"
14889               "  }"
14890               "})()",
14891               "ReferenceError: cell is not defined");
14892}
14893
14894
14895TEST(RegExp) {
14896  v8::HandleScope scope;
14897  LocalContext context;
14898
14899  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14900  CHECK(re->IsRegExp());
14901  CHECK(re->GetSource()->Equals(v8_str("foo")));
14902  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14903
14904  re = v8::RegExp::New(v8_str("bar"),
14905                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14906                                                      v8::RegExp::kGlobal));
14907  CHECK(re->IsRegExp());
14908  CHECK(re->GetSource()->Equals(v8_str("bar")));
14909  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
14910           static_cast<int>(re->GetFlags()));
14911
14912  re = v8::RegExp::New(v8_str("baz"),
14913                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14914                                                      v8::RegExp::kMultiline));
14915  CHECK(re->IsRegExp());
14916  CHECK(re->GetSource()->Equals(v8_str("baz")));
14917  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14918           static_cast<int>(re->GetFlags()));
14919
14920  re = CompileRun("/quux/").As<v8::RegExp>();
14921  CHECK(re->IsRegExp());
14922  CHECK(re->GetSource()->Equals(v8_str("quux")));
14923  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14924
14925  re = CompileRun("/quux/gm").As<v8::RegExp>();
14926  CHECK(re->IsRegExp());
14927  CHECK(re->GetSource()->Equals(v8_str("quux")));
14928  CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
14929           static_cast<int>(re->GetFlags()));
14930
14931  // Override the RegExp constructor and check the API constructor
14932  // still works.
14933  CompileRun("RegExp = function() {}");
14934
14935  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14936  CHECK(re->IsRegExp());
14937  CHECK(re->GetSource()->Equals(v8_str("foobar")));
14938  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14939
14940  re = v8::RegExp::New(v8_str("foobarbaz"),
14941                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14942                                                      v8::RegExp::kMultiline));
14943  CHECK(re->IsRegExp());
14944  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14945  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14946           static_cast<int>(re->GetFlags()));
14947
14948  context->Global()->Set(v8_str("re"), re);
14949  ExpectTrue("re.test('FoobarbaZ')");
14950
14951  // RegExps are objects on which you can set properties.
14952  re->Set(v8_str("property"), v8::Integer::New(32));
14953  v8::Handle<v8::Value> value(CompileRun("re.property"));
14954  ASSERT_EQ(32, value->Int32Value());
14955
14956  v8::TryCatch try_catch;
14957  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14958  CHECK(re.IsEmpty());
14959  CHECK(try_catch.HasCaught());
14960  context->Global()->Set(v8_str("ex"), try_catch.Exception());
14961  ExpectTrue("ex instanceof SyntaxError");
14962}
14963
14964
14965THREADED_TEST(Equals) {
14966  v8::HandleScope handleScope;
14967  LocalContext localContext;
14968
14969  v8::Handle<v8::Object> globalProxy = localContext->Global();
14970  v8::Handle<Value> global = globalProxy->GetPrototype();
14971
14972  CHECK(global->StrictEquals(global));
14973  CHECK(!global->StrictEquals(globalProxy));
14974  CHECK(!globalProxy->StrictEquals(global));
14975  CHECK(globalProxy->StrictEquals(globalProxy));
14976
14977  CHECK(global->Equals(global));
14978  CHECK(!global->Equals(globalProxy));
14979  CHECK(!globalProxy->Equals(global));
14980  CHECK(globalProxy->Equals(globalProxy));
14981}
14982
14983
14984static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14985                                    const v8::AccessorInfo& info ) {
14986  return v8_str("42!");
14987}
14988
14989
14990static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14991  v8::Handle<v8::Array> result = v8::Array::New();
14992  result->Set(0, v8_str("universalAnswer"));
14993  return result;
14994}
14995
14996
14997TEST(NamedEnumeratorAndForIn) {
14998  v8::HandleScope handle_scope;
14999  LocalContext context;
15000  v8::Context::Scope context_scope(context.local());
15001
15002  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
15003  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
15004  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
15005  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
15006        "var result = []; for (var k in o) result.push(k); result"));
15007  CHECK_EQ(1, result->Length());
15008  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
15009}
15010
15011
15012TEST(DefinePropertyPostDetach) {
15013  v8::HandleScope scope;
15014  LocalContext context;
15015  v8::Handle<v8::Object> proxy = context->Global();
15016  v8::Handle<v8::Function> define_property =
15017      CompileRun("(function() {"
15018                 "  Object.defineProperty("
15019                 "    this,"
15020                 "    1,"
15021                 "    { configurable: true, enumerable: true, value: 3 });"
15022                 "})").As<Function>();
15023  context->DetachGlobal();
15024  define_property->Call(proxy, 0, NULL);
15025}
15026
15027
15028static void InstallContextId(v8::Handle<Context> context, int id) {
15029  Context::Scope scope(context);
15030  CompileRun("Object.prototype").As<Object>()->
15031      Set(v8_str("context_id"), v8::Integer::New(id));
15032}
15033
15034
15035static void CheckContextId(v8::Handle<Object> object, int expected) {
15036  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
15037}
15038
15039
15040THREADED_TEST(CreationContext) {
15041  HandleScope handle_scope;
15042  Persistent<Context> context1 = Context::New();
15043  InstallContextId(context1, 1);
15044  Persistent<Context> context2 = Context::New();
15045  InstallContextId(context2, 2);
15046  Persistent<Context> context3 = Context::New();
15047  InstallContextId(context3, 3);
15048
15049  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
15050
15051  Local<Object> object1;
15052  Local<Function> func1;
15053  {
15054    Context::Scope scope(context1);
15055    object1 = Object::New();
15056    func1 = tmpl->GetFunction();
15057  }
15058
15059  Local<Object> object2;
15060  Local<Function> func2;
15061  {
15062    Context::Scope scope(context2);
15063    object2 = Object::New();
15064    func2 = tmpl->GetFunction();
15065  }
15066
15067  Local<Object> instance1;
15068  Local<Object> instance2;
15069
15070  {
15071    Context::Scope scope(context3);
15072    instance1 = func1->NewInstance();
15073    instance2 = func2->NewInstance();
15074  }
15075
15076  CHECK(object1->CreationContext() == context1);
15077  CheckContextId(object1, 1);
15078  CHECK(func1->CreationContext() == context1);
15079  CheckContextId(func1, 1);
15080  CHECK(instance1->CreationContext() == context1);
15081  CheckContextId(instance1, 1);
15082  CHECK(object2->CreationContext() == context2);
15083  CheckContextId(object2, 2);
15084  CHECK(func2->CreationContext() == context2);
15085  CheckContextId(func2, 2);
15086  CHECK(instance2->CreationContext() == context2);
15087  CheckContextId(instance2, 2);
15088
15089  {
15090    Context::Scope scope(context1);
15091    CHECK(object1->CreationContext() == context1);
15092    CheckContextId(object1, 1);
15093    CHECK(func1->CreationContext() == context1);
15094    CheckContextId(func1, 1);
15095    CHECK(instance1->CreationContext() == context1);
15096    CheckContextId(instance1, 1);
15097    CHECK(object2->CreationContext() == context2);
15098    CheckContextId(object2, 2);
15099    CHECK(func2->CreationContext() == context2);
15100    CheckContextId(func2, 2);
15101    CHECK(instance2->CreationContext() == context2);
15102    CheckContextId(instance2, 2);
15103  }
15104
15105  {
15106    Context::Scope scope(context2);
15107    CHECK(object1->CreationContext() == context1);
15108    CheckContextId(object1, 1);
15109    CHECK(func1->CreationContext() == context1);
15110    CheckContextId(func1, 1);
15111    CHECK(instance1->CreationContext() == context1);
15112    CheckContextId(instance1, 1);
15113    CHECK(object2->CreationContext() == context2);
15114    CheckContextId(object2, 2);
15115    CHECK(func2->CreationContext() == context2);
15116    CheckContextId(func2, 2);
15117    CHECK(instance2->CreationContext() == context2);
15118    CheckContextId(instance2, 2);
15119  }
15120
15121  context1.Dispose();
15122  context2.Dispose();
15123  context3.Dispose();
15124}
15125
15126
15127THREADED_TEST(CreationContextOfJsFunction) {
15128  HandleScope handle_scope;
15129  Persistent<Context> context = Context::New();
15130  InstallContextId(context, 1);
15131
15132  Local<Object> function;
15133  {
15134    Context::Scope scope(context);
15135    function = CompileRun("function foo() {}; foo").As<Object>();
15136  }
15137
15138  CHECK(function->CreationContext() == context);
15139  CheckContextId(function, 1);
15140
15141  context.Dispose();
15142}
15143
15144
15145Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15146                                                  const AccessorInfo& info) {
15147  if (index == 42) return v8_str("yes");
15148  return Handle<v8::Integer>();
15149}
15150
15151
15152Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15153                                                const AccessorInfo& info) {
15154  if (property->Equals(v8_str("foo"))) return v8_str("yes");
15155  return Handle<Value>();
15156}
15157
15158
15159Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15160    uint32_t index, const AccessorInfo& info) {
15161  if (index == 42) return v8_num(1).As<v8::Integer>();
15162  return Handle<v8::Integer>();
15163}
15164
15165
15166Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15167    Local<String> property, const AccessorInfo& info) {
15168  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15169  return Handle<v8::Integer>();
15170}
15171
15172
15173Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15174    Local<String> property, const AccessorInfo& info) {
15175  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15176  return Handle<v8::Integer>();
15177}
15178
15179
15180Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15181                                           const AccessorInfo& info) {
15182  return v8_str("yes");
15183}
15184
15185
15186TEST(HasOwnProperty) {
15187  v8::HandleScope scope;
15188  LocalContext env;
15189  { // Check normal properties and defined getters.
15190    Handle<Value> value = CompileRun(
15191        "function Foo() {"
15192        "    this.foo = 11;"
15193        "    this.__defineGetter__('baz', function() { return 1; });"
15194        "};"
15195        "function Bar() { "
15196        "    this.bar = 13;"
15197        "    this.__defineGetter__('bla', function() { return 2; });"
15198        "};"
15199        "Bar.prototype = new Foo();"
15200        "new Bar();");
15201    CHECK(value->IsObject());
15202    Handle<Object> object = value->ToObject();
15203    CHECK(object->Has(v8_str("foo")));
15204    CHECK(!object->HasOwnProperty(v8_str("foo")));
15205    CHECK(object->HasOwnProperty(v8_str("bar")));
15206    CHECK(object->Has(v8_str("baz")));
15207    CHECK(!object->HasOwnProperty(v8_str("baz")));
15208    CHECK(object->HasOwnProperty(v8_str("bla")));
15209  }
15210  { // Check named getter interceptors.
15211    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15212    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15213    Handle<Object> instance = templ->NewInstance();
15214    CHECK(!instance->HasOwnProperty(v8_str("42")));
15215    CHECK(instance->HasOwnProperty(v8_str("foo")));
15216    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15217  }
15218  { // Check indexed getter interceptors.
15219    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15220    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15221    Handle<Object> instance = templ->NewInstance();
15222    CHECK(instance->HasOwnProperty(v8_str("42")));
15223    CHECK(!instance->HasOwnProperty(v8_str("43")));
15224    CHECK(!instance->HasOwnProperty(v8_str("foo")));
15225  }
15226  { // Check named query interceptors.
15227    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15228    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15229    Handle<Object> instance = templ->NewInstance();
15230    CHECK(instance->HasOwnProperty(v8_str("foo")));
15231    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15232  }
15233  { // Check indexed query interceptors.
15234    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15235    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15236    Handle<Object> instance = templ->NewInstance();
15237    CHECK(instance->HasOwnProperty(v8_str("42")));
15238    CHECK(!instance->HasOwnProperty(v8_str("41")));
15239  }
15240  { // Check callbacks.
15241    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15242    templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15243    Handle<Object> instance = templ->NewInstance();
15244    CHECK(instance->HasOwnProperty(v8_str("foo")));
15245    CHECK(!instance->HasOwnProperty(v8_str("bar")));
15246  }
15247  { // Check that query wins on disagreement.
15248    Handle<ObjectTemplate> templ = ObjectTemplate::New();
15249    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15250                                   0,
15251                                   HasOwnPropertyNamedPropertyQuery2);
15252    Handle<Object> instance = templ->NewInstance();
15253    CHECK(!instance->HasOwnProperty(v8_str("foo")));
15254    CHECK(instance->HasOwnProperty(v8_str("bar")));
15255  }
15256}
15257
15258
15259void CheckCodeGenerationAllowed() {
15260  Handle<Value> result = CompileRun("eval('42')");
15261  CHECK_EQ(42, result->Int32Value());
15262  result = CompileRun("(function(e) { return e('42'); })(eval)");
15263  CHECK_EQ(42, result->Int32Value());
15264  result = CompileRun("var f = new Function('return 42'); f()");
15265  CHECK_EQ(42, result->Int32Value());
15266}
15267
15268
15269void CheckCodeGenerationDisallowed() {
15270  TryCatch try_catch;
15271
15272  Handle<Value> result = CompileRun("eval('42')");
15273  CHECK(result.IsEmpty());
15274  CHECK(try_catch.HasCaught());
15275  try_catch.Reset();
15276
15277  result = CompileRun("(function(e) { return e('42'); })(eval)");
15278  CHECK(result.IsEmpty());
15279  CHECK(try_catch.HasCaught());
15280  try_catch.Reset();
15281
15282  result = CompileRun("var f = new Function('return 42'); f()");
15283  CHECK(result.IsEmpty());
15284  CHECK(try_catch.HasCaught());
15285}
15286
15287
15288bool CodeGenerationAllowed(Local<Context> context) {
15289  ApiTestFuzzer::Fuzz();
15290  return true;
15291}
15292
15293
15294bool CodeGenerationDisallowed(Local<Context> context) {
15295  ApiTestFuzzer::Fuzz();
15296  return false;
15297}
15298
15299
15300THREADED_TEST(AllowCodeGenFromStrings) {
15301  v8::HandleScope scope;
15302  LocalContext context;
15303
15304  // eval and the Function constructor allowed by default.
15305  CheckCodeGenerationAllowed();
15306
15307  // Disallow eval and the Function constructor.
15308  context->AllowCodeGenerationFromStrings(false);
15309  CheckCodeGenerationDisallowed();
15310
15311  // Allow again.
15312  context->AllowCodeGenerationFromStrings(true);
15313  CheckCodeGenerationAllowed();
15314
15315  // Disallow but setting a global callback that will allow the calls.
15316  context->AllowCodeGenerationFromStrings(false);
15317  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15318  CheckCodeGenerationAllowed();
15319
15320  // Set a callback that disallows the code generation.
15321  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15322  CheckCodeGenerationDisallowed();
15323}
15324
15325
15326static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15327  return v8::Undefined();
15328}
15329
15330
15331THREADED_TEST(CallAPIFunctionOnNonObject) {
15332  v8::HandleScope scope;
15333  LocalContext context;
15334  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15335  Handle<Function> function = templ->GetFunction();
15336  context->Global()->Set(v8_str("f"), function);
15337  TryCatch try_catch;
15338  CompileRun("f.call(2)");
15339}
15340
15341
15342// Regression test for issue 1470.
15343THREADED_TEST(ReadOnlyIndexedProperties) {
15344  v8::HandleScope scope;
15345  Local<ObjectTemplate> templ = ObjectTemplate::New();
15346
15347  LocalContext context;
15348  Local<v8::Object> obj = templ->NewInstance();
15349  context->Global()->Set(v8_str("obj"), obj);
15350  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15351  obj->Set(v8_str("1"), v8_str("foobar"));
15352  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15353  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15354  obj->Set(v8_num(2), v8_str("foobar"));
15355  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15356
15357  // Test non-smi case.
15358  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15359  obj->Set(v8_str("2000000000"), v8_str("foobar"));
15360  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15361}
15362
15363
15364THREADED_TEST(Regress1516) {
15365  v8::HandleScope scope;
15366
15367  LocalContext context;
15368  { v8::HandleScope temp_scope;
15369    CompileRun("({'a': 0})");
15370  }
15371
15372  int elements;
15373  { i::MapCache* map_cache =
15374        i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15375    elements = map_cache->NumberOfElements();
15376    CHECK_LE(1, elements);
15377  }
15378
15379  i::Isolate::Current()->heap()->CollectAllGarbage(true);
15380  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15381    if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15382      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15383      CHECK_GT(elements, map_cache->NumberOfElements());
15384    }
15385  }
15386}
15387
15388
15389static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15390                                                Local<Value> name,
15391                                                v8::AccessType type,
15392                                                Local<Value> data) {
15393  // Only block read access to __proto__.
15394  if (type == v8::ACCESS_GET &&
15395      name->IsString() &&
15396      name->ToString()->Length() == 9 &&
15397      name->ToString()->Utf8Length() == 9) {
15398    char buffer[10];
15399    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15400    return strncmp(buffer, "__proto__", 9) != 0;
15401  }
15402
15403  return true;
15404}
15405
15406
15407THREADED_TEST(Regress93759) {
15408  HandleScope scope;
15409
15410  // Template for object with security check.
15411  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15412  // We don't do indexing, so any callback can be used for that.
15413  no_proto_template->SetAccessCheckCallbacks(
15414      BlockProtoNamedSecurityTestCallback,
15415      IndexedSecurityTestCallback);
15416
15417  // Templates for objects with hidden prototypes and possibly security check.
15418  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15419  hidden_proto_template->SetHiddenPrototype(true);
15420
15421  Local<FunctionTemplate> protected_hidden_proto_template =
15422      v8::FunctionTemplate::New();
15423  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15424      BlockProtoNamedSecurityTestCallback,
15425      IndexedSecurityTestCallback);
15426  protected_hidden_proto_template->SetHiddenPrototype(true);
15427
15428  // Context for "foreign" objects used in test.
15429  Persistent<Context> context = v8::Context::New();
15430  context->Enter();
15431
15432  // Plain object, no security check.
15433  Local<Object> simple_object = Object::New();
15434
15435  // Object with explicit security check.
15436  Local<Object> protected_object =
15437      no_proto_template->NewInstance();
15438
15439  // JSGlobalProxy object, always have security check.
15440  Local<Object> proxy_object =
15441      context->Global();
15442
15443  // Global object, the  prototype of proxy_object. No security checks.
15444  Local<Object> global_object =
15445      proxy_object->GetPrototype()->ToObject();
15446
15447  // Hidden prototype without security check.
15448  Local<Object> hidden_prototype =
15449      hidden_proto_template->GetFunction()->NewInstance();
15450  Local<Object> object_with_hidden =
15451    Object::New();
15452  object_with_hidden->SetPrototype(hidden_prototype);
15453
15454  // Hidden prototype with security check on the hidden prototype.
15455  Local<Object> protected_hidden_prototype =
15456      protected_hidden_proto_template->GetFunction()->NewInstance();
15457  Local<Object> object_with_protected_hidden =
15458    Object::New();
15459  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15460
15461  context->Exit();
15462
15463  // Template for object for second context. Values to test are put on it as
15464  // properties.
15465  Local<ObjectTemplate> global_template = ObjectTemplate::New();
15466  global_template->Set(v8_str("simple"), simple_object);
15467  global_template->Set(v8_str("protected"), protected_object);
15468  global_template->Set(v8_str("global"), global_object);
15469  global_template->Set(v8_str("proxy"), proxy_object);
15470  global_template->Set(v8_str("hidden"), object_with_hidden);
15471  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15472
15473  LocalContext context2(NULL, global_template);
15474
15475  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15476  CHECK(result1->Equals(simple_object->GetPrototype()));
15477
15478  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15479  CHECK(result2->Equals(Undefined()));
15480
15481  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15482  CHECK(result3->Equals(global_object->GetPrototype()));
15483
15484  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15485  CHECK(result4->Equals(Undefined()));
15486
15487  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15488  CHECK(result5->Equals(
15489      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15490
15491  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15492  CHECK(result6->Equals(Undefined()));
15493
15494  context.Dispose();
15495}
15496
15497
15498static void TestReceiver(Local<Value> expected_result,
15499                         Local<Value> expected_receiver,
15500                         const char* code) {
15501  Local<Value> result = CompileRun(code);
15502  CHECK(result->IsObject());
15503  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15504  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15505}
15506
15507
15508THREADED_TEST(ForeignFunctionReceiver) {
15509  HandleScope scope;
15510
15511  // Create two contexts with different "id" properties ('i' and 'o').
15512  // Call a function both from its own context and from a the foreign
15513  // context, and see what "this" is bound to (returning both "this"
15514  // and "this.id" for comparison).
15515
15516  Persistent<Context> foreign_context = v8::Context::New();
15517  foreign_context->Enter();
15518  Local<Value> foreign_function =
15519    CompileRun("function func() { return { 0: this.id, "
15520               "                           1: this, "
15521               "                           toString: function() { "
15522               "                               return this[0];"
15523               "                           }"
15524               "                         };"
15525               "}"
15526               "var id = 'i';"
15527               "func;");
15528  CHECK(foreign_function->IsFunction());
15529  foreign_context->Exit();
15530
15531  LocalContext context;
15532
15533  Local<String> password = v8_str("Password");
15534  // Don't get hit by security checks when accessing foreign_context's
15535  // global receiver (aka. global proxy).
15536  context->SetSecurityToken(password);
15537  foreign_context->SetSecurityToken(password);
15538
15539  Local<String> i = v8_str("i");
15540  Local<String> o = v8_str("o");
15541  Local<String> id = v8_str("id");
15542
15543  CompileRun("function ownfunc() { return { 0: this.id, "
15544             "                              1: this, "
15545             "                              toString: function() { "
15546             "                                  return this[0];"
15547             "                              }"
15548             "                             };"
15549             "}"
15550             "var id = 'o';"
15551             "ownfunc");
15552  context->Global()->Set(v8_str("func"), foreign_function);
15553
15554  // Sanity check the contexts.
15555  CHECK(i->Equals(foreign_context->Global()->Get(id)));
15556  CHECK(o->Equals(context->Global()->Get(id)));
15557
15558  // Checking local function's receiver.
15559  // Calling function using its call/apply methods.
15560  TestReceiver(o, context->Global(), "ownfunc.call()");
15561  TestReceiver(o, context->Global(), "ownfunc.apply()");
15562  // Making calls through built-in functions.
15563  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15564  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15565  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15566  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15567  // Calling with environment record as base.
15568  TestReceiver(o, context->Global(), "ownfunc()");
15569  // Calling with no base.
15570  TestReceiver(o, context->Global(), "(1,ownfunc)()");
15571
15572  // Checking foreign function return value.
15573  // Calling function using its call/apply methods.
15574  TestReceiver(i, foreign_context->Global(), "func.call()");
15575  TestReceiver(i, foreign_context->Global(), "func.apply()");
15576  // Calling function using another context's call/apply methods.
15577  TestReceiver(i, foreign_context->Global(),
15578               "Function.prototype.call.call(func)");
15579  TestReceiver(i, foreign_context->Global(),
15580               "Function.prototype.call.apply(func)");
15581  TestReceiver(i, foreign_context->Global(),
15582               "Function.prototype.apply.call(func)");
15583  TestReceiver(i, foreign_context->Global(),
15584               "Function.prototype.apply.apply(func)");
15585  // Making calls through built-in functions.
15586  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15587  // ToString(func()) is func()[0], i.e., the returned this.id.
15588  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15589  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15590  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15591
15592  // TODO(1547): Make the following also return "i".
15593  // Calling with environment record as base.
15594  TestReceiver(o, context->Global(), "func()");
15595  // Calling with no base.
15596  TestReceiver(o, context->Global(), "(1,func)()");
15597
15598  foreign_context.Dispose();
15599}
15600