test-api.cc revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
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
75namespace i = ::i;
76
77
78static void ExpectString(const char* code, const char* expected) {
79  Local<Value> result = CompileRun(code);
80  CHECK(result->IsString());
81  String::AsciiValue ascii(result);
82  CHECK_EQ(expected, *ascii);
83}
84
85
86static void ExpectBoolean(const char* code, bool expected) {
87  Local<Value> result = CompileRun(code);
88  CHECK(result->IsBoolean());
89  CHECK_EQ(expected, result->BooleanValue());
90}
91
92
93static void ExpectTrue(const char* code) {
94  ExpectBoolean(code, true);
95}
96
97
98static void ExpectFalse(const char* code) {
99  ExpectBoolean(code, false);
100}
101
102
103static void ExpectObject(const char* code, Local<Value> expected) {
104  Local<Value> result = CompileRun(code);
105  CHECK(result->Equals(expected));
106}
107
108
109static void ExpectUndefined(const char* code) {
110  Local<Value> result = CompileRun(code);
111  CHECK(result->IsUndefined());
112}
113
114
115static int signature_callback_count;
116static v8::Handle<Value> IncrementingSignatureCallback(
117    const v8::Arguments& args) {
118  ApiTestFuzzer::Fuzz();
119  signature_callback_count++;
120  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
121  for (int i = 0; i < args.Length(); i++)
122    result->Set(v8::Integer::New(i), args[i]);
123  return result;
124}
125
126
127static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
128  ApiTestFuzzer::Fuzz();
129  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130  for (int i = 0; i < args.Length(); i++) {
131    result->Set(v8::Integer::New(i), args[i]);
132  }
133  return result;
134}
135
136
137THREADED_TEST(Handles) {
138  v8::HandleScope scope;
139  Local<Context> local_env;
140  {
141    LocalContext env;
142    local_env = env.local();
143  }
144
145  // Local context should still be live.
146  CHECK(!local_env.IsEmpty());
147  local_env->Enter();
148
149  v8::Handle<v8::Primitive> undef = v8::Undefined();
150  CHECK(!undef.IsEmpty());
151  CHECK(undef->IsUndefined());
152
153  const char* c_source = "1 + 2 + 3";
154  Local<String> source = String::New(c_source);
155  Local<Script> script = Script::Compile(source);
156  CHECK_EQ(6, script->Run()->Int32Value());
157
158  local_env->Exit();
159}
160
161
162THREADED_TEST(ReceiverSignature) {
163  v8::HandleScope scope;
164  LocalContext env;
165  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
166  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
167  fun->PrototypeTemplate()->Set(
168      v8_str("m"),
169      v8::FunctionTemplate::New(IncrementingSignatureCallback,
170                                v8::Handle<Value>(),
171                                sig));
172  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
173  signature_callback_count = 0;
174  CompileRun(
175      "var o = new Fun();"
176      "o.m();");
177  CHECK_EQ(1, signature_callback_count);
178  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
179  sub_fun->Inherit(fun);
180  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
181  CompileRun(
182      "var o = new SubFun();"
183      "o.m();");
184  CHECK_EQ(2, signature_callback_count);
185
186  v8::TryCatch try_catch;
187  CompileRun(
188      "var o = { };"
189      "o.m = Fun.prototype.m;"
190      "o.m();");
191  CHECK_EQ(2, signature_callback_count);
192  CHECK(try_catch.HasCaught());
193  try_catch.Reset();
194  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
195  sub_fun->Inherit(fun);
196  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
197  CompileRun(
198      "var o = new UnrelFun();"
199      "o.m = Fun.prototype.m;"
200      "o.m();");
201  CHECK_EQ(2, signature_callback_count);
202  CHECK(try_catch.HasCaught());
203}
204
205
206THREADED_TEST(ArgumentSignature) {
207  v8::HandleScope scope;
208  LocalContext env;
209  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
210  cons->SetClassName(v8_str("Cons"));
211  v8::Handle<v8::Signature> sig =
212      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
213  v8::Handle<v8::FunctionTemplate> fun =
214      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
215  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
216  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
217
218  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
219  CHECK(value1->IsTrue());
220
221  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
222  CHECK(value2->IsTrue());
223
224  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
225  CHECK(value3->IsTrue());
226
227  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
228  cons1->SetClassName(v8_str("Cons1"));
229  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
230  cons2->SetClassName(v8_str("Cons2"));
231  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
232  cons3->SetClassName(v8_str("Cons3"));
233
234  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
235  v8::Handle<v8::Signature> wsig =
236      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
237  v8::Handle<v8::FunctionTemplate> fun2 =
238      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
239
240  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
241  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
242  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
243  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
244  v8::Handle<Value> value4 = CompileRun(
245      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
246      "'[object Cons1],[object Cons2],[object Cons3]'");
247  CHECK(value4->IsTrue());
248
249  v8::Handle<Value> value5 = CompileRun(
250      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
251  CHECK(value5->IsTrue());
252
253  v8::Handle<Value> value6 = CompileRun(
254      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
255  CHECK(value6->IsTrue());
256
257  v8::Handle<Value> value7 = CompileRun(
258      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
259      "'[object Cons1],[object Cons2],[object Cons3],d';");
260  CHECK(value7->IsTrue());
261
262  v8::Handle<Value> value8 = CompileRun(
263      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
264  CHECK(value8->IsTrue());
265}
266
267
268THREADED_TEST(HulIgennem) {
269  v8::HandleScope scope;
270  LocalContext env;
271  v8::Handle<v8::Primitive> undef = v8::Undefined();
272  Local<String> undef_str = undef->ToString();
273  char* value = i::NewArray<char>(undef_str->Length() + 1);
274  undef_str->WriteAscii(value);
275  CHECK_EQ(0, strcmp(value, "undefined"));
276  i::DeleteArray(value);
277}
278
279
280THREADED_TEST(Access) {
281  v8::HandleScope scope;
282  LocalContext env;
283  Local<v8::Object> obj = v8::Object::New();
284  Local<Value> foo_before = obj->Get(v8_str("foo"));
285  CHECK(foo_before->IsUndefined());
286  Local<String> bar_str = v8_str("bar");
287  obj->Set(v8_str("foo"), bar_str);
288  Local<Value> foo_after = obj->Get(v8_str("foo"));
289  CHECK(!foo_after->IsUndefined());
290  CHECK(foo_after->IsString());
291  CHECK_EQ(bar_str, foo_after);
292}
293
294
295THREADED_TEST(AccessElement) {
296  v8::HandleScope scope;
297  LocalContext env;
298  Local<v8::Object> obj = v8::Object::New();
299  Local<Value> before = obj->Get(1);
300  CHECK(before->IsUndefined());
301  Local<String> bar_str = v8_str("bar");
302  obj->Set(1, bar_str);
303  Local<Value> after = obj->Get(1);
304  CHECK(!after->IsUndefined());
305  CHECK(after->IsString());
306  CHECK_EQ(bar_str, after);
307
308  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
309  CHECK_EQ(v8_str("a"), value->Get(0));
310  CHECK_EQ(v8_str("b"), value->Get(1));
311}
312
313
314THREADED_TEST(Script) {
315  v8::HandleScope scope;
316  LocalContext env;
317  const char* c_source = "1 + 2 + 3";
318  Local<String> source = String::New(c_source);
319  Local<Script> script = Script::Compile(source);
320  CHECK_EQ(6, script->Run()->Int32Value());
321}
322
323
324static uint16_t* AsciiToTwoByteString(const char* source) {
325  int array_length = i::StrLength(source) + 1;
326  uint16_t* converted = i::NewArray<uint16_t>(array_length);
327  for (int i = 0; i < array_length; i++) converted[i] = source[i];
328  return converted;
329}
330
331
332class TestResource: public String::ExternalStringResource {
333 public:
334  static int dispose_count;
335
336  explicit TestResource(uint16_t* data)
337      : data_(data), length_(0) {
338    while (data[length_]) ++length_;
339  }
340
341  ~TestResource() {
342    i::DeleteArray(data_);
343    ++dispose_count;
344  }
345
346  const uint16_t* data() const {
347    return data_;
348  }
349
350  size_t length() const {
351    return length_;
352  }
353 private:
354  uint16_t* data_;
355  size_t length_;
356};
357
358
359int TestResource::dispose_count = 0;
360
361
362class TestAsciiResource: public String::ExternalAsciiStringResource {
363 public:
364  static int dispose_count;
365
366  explicit TestAsciiResource(const char* data)
367      : data_(data),
368        length_(strlen(data)) { }
369
370  ~TestAsciiResource() {
371    i::DeleteArray(data_);
372    ++dispose_count;
373  }
374
375  const char* data() const {
376    return data_;
377  }
378
379  size_t length() const {
380    return length_;
381  }
382 private:
383  const char* data_;
384  size_t length_;
385};
386
387
388int TestAsciiResource::dispose_count = 0;
389
390
391THREADED_TEST(ScriptUsingStringResource) {
392  TestResource::dispose_count = 0;
393  const char* c_source = "1 + 2 * 3";
394  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
395  {
396    v8::HandleScope scope;
397    LocalContext env;
398    TestResource* resource = new TestResource(two_byte_source);
399    Local<String> source = String::NewExternal(resource);
400    Local<Script> script = Script::Compile(source);
401    Local<Value> value = script->Run();
402    CHECK(value->IsNumber());
403    CHECK_EQ(7, value->Int32Value());
404    CHECK(source->IsExternal());
405    CHECK_EQ(resource,
406             static_cast<TestResource*>(source->GetExternalStringResource()));
407    HEAP->CollectAllGarbage(false);
408    CHECK_EQ(0, TestResource::dispose_count);
409  }
410  v8::internal::Isolate::Current()->compilation_cache()->Clear();
411  HEAP->CollectAllGarbage(false);
412  CHECK_EQ(1, TestResource::dispose_count);
413}
414
415
416THREADED_TEST(ScriptUsingAsciiStringResource) {
417  TestAsciiResource::dispose_count = 0;
418  const char* c_source = "1 + 2 * 3";
419  {
420    v8::HandleScope scope;
421    LocalContext env;
422    Local<String> source =
423        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
424    Local<Script> script = Script::Compile(source);
425    Local<Value> value = script->Run();
426    CHECK(value->IsNumber());
427    CHECK_EQ(7, value->Int32Value());
428    HEAP->CollectAllGarbage(false);
429    CHECK_EQ(0, TestAsciiResource::dispose_count);
430  }
431  i::Isolate::Current()->compilation_cache()->Clear();
432  HEAP->CollectAllGarbage(false);
433  CHECK_EQ(1, TestAsciiResource::dispose_count);
434}
435
436
437THREADED_TEST(ScriptMakingExternalString) {
438  TestResource::dispose_count = 0;
439  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
440  {
441    v8::HandleScope scope;
442    LocalContext env;
443    Local<String> source = String::New(two_byte_source);
444    // Trigger GCs so that the newly allocated string moves to old gen.
445    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
446    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
447    bool success = source->MakeExternal(new TestResource(two_byte_source));
448    CHECK(success);
449    Local<Script> script = Script::Compile(source);
450    Local<Value> value = script->Run();
451    CHECK(value->IsNumber());
452    CHECK_EQ(7, value->Int32Value());
453    HEAP->CollectAllGarbage(false);
454    CHECK_EQ(0, TestResource::dispose_count);
455  }
456  i::Isolate::Current()->compilation_cache()->Clear();
457  HEAP->CollectAllGarbage(false);
458  CHECK_EQ(1, TestResource::dispose_count);
459}
460
461
462THREADED_TEST(ScriptMakingExternalAsciiString) {
463  TestAsciiResource::dispose_count = 0;
464  const char* c_source = "1 + 2 * 3";
465  {
466    v8::HandleScope scope;
467    LocalContext env;
468    Local<String> source = v8_str(c_source);
469    // Trigger GCs so that the newly allocated string moves to old gen.
470    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
471    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
472    bool success = source->MakeExternal(
473        new TestAsciiResource(i::StrDup(c_source)));
474    CHECK(success);
475    Local<Script> script = Script::Compile(source);
476    Local<Value> value = script->Run();
477    CHECK(value->IsNumber());
478    CHECK_EQ(7, value->Int32Value());
479    HEAP->CollectAllGarbage(false);
480    CHECK_EQ(0, TestAsciiResource::dispose_count);
481  }
482  i::Isolate::Current()->compilation_cache()->Clear();
483  HEAP->CollectAllGarbage(false);
484  CHECK_EQ(1, TestAsciiResource::dispose_count);
485}
486
487
488TEST(MakingExternalStringConditions) {
489  v8::HandleScope scope;
490  LocalContext env;
491
492  // Free some space in the new space so that we can check freshness.
493  HEAP->CollectGarbage(i::NEW_SPACE);
494  HEAP->CollectGarbage(i::NEW_SPACE);
495
496  uint16_t* two_byte_string = AsciiToTwoByteString("small");
497  Local<String> small_string = String::New(two_byte_string);
498  i::DeleteArray(two_byte_string);
499
500  // We should refuse to externalize newly created small string.
501  CHECK(!small_string->CanMakeExternal());
502  // Trigger GCs so that the newly allocated string moves to old gen.
503  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
504  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
505  // Old space strings should be accepted.
506  CHECK(small_string->CanMakeExternal());
507
508  two_byte_string = AsciiToTwoByteString("small 2");
509  small_string = String::New(two_byte_string);
510  i::DeleteArray(two_byte_string);
511
512  // We should refuse externalizing newly created small string.
513  CHECK(!small_string->CanMakeExternal());
514  for (int i = 0; i < 100; i++) {
515    String::Value value(small_string);
516  }
517  // Frequently used strings should be accepted.
518  CHECK(small_string->CanMakeExternal());
519
520  const int buf_size = 10 * 1024;
521  char* buf = i::NewArray<char>(buf_size);
522  memset(buf, 'a', buf_size);
523  buf[buf_size - 1] = '\0';
524
525  two_byte_string = AsciiToTwoByteString(buf);
526  Local<String> large_string = String::New(two_byte_string);
527  i::DeleteArray(buf);
528  i::DeleteArray(two_byte_string);
529  // Large strings should be immediately accepted.
530  CHECK(large_string->CanMakeExternal());
531}
532
533
534TEST(MakingExternalAsciiStringConditions) {
535  v8::HandleScope scope;
536  LocalContext env;
537
538  // Free some space in the new space so that we can check freshness.
539  HEAP->CollectGarbage(i::NEW_SPACE);
540  HEAP->CollectGarbage(i::NEW_SPACE);
541
542  Local<String> small_string = String::New("small");
543  // We should refuse to externalize newly created small string.
544  CHECK(!small_string->CanMakeExternal());
545  // Trigger GCs so that the newly allocated string moves to old gen.
546  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
547  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
548  // Old space strings should be accepted.
549  CHECK(small_string->CanMakeExternal());
550
551  small_string = String::New("small 2");
552  // We should refuse externalizing newly created small string.
553  CHECK(!small_string->CanMakeExternal());
554  for (int i = 0; i < 100; i++) {
555    String::Value value(small_string);
556  }
557  // Frequently used strings should be accepted.
558  CHECK(small_string->CanMakeExternal());
559
560  const int buf_size = 10 * 1024;
561  char* buf = i::NewArray<char>(buf_size);
562  memset(buf, 'a', buf_size);
563  buf[buf_size - 1] = '\0';
564  Local<String> large_string = String::New(buf);
565  i::DeleteArray(buf);
566  // Large strings should be immediately accepted.
567  CHECK(large_string->CanMakeExternal());
568}
569
570
571THREADED_TEST(UsingExternalString) {
572  {
573    v8::HandleScope scope;
574    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
575    Local<String> string =
576        String::NewExternal(new TestResource(two_byte_string));
577    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
578    // Trigger GCs so that the newly allocated string moves to old gen.
579    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
580    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
581    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
582    CHECK(isymbol->IsSymbol());
583  }
584  HEAP->CollectAllGarbage(false);
585  HEAP->CollectAllGarbage(false);
586}
587
588
589THREADED_TEST(UsingExternalAsciiString) {
590  {
591    v8::HandleScope scope;
592    const char* one_byte_string = "test string";
593    Local<String> string = String::NewExternal(
594        new TestAsciiResource(i::StrDup(one_byte_string)));
595    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596    // Trigger GCs so that the newly allocated string moves to old gen.
597    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
598    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
599    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
600    CHECK(isymbol->IsSymbol());
601  }
602  HEAP->CollectAllGarbage(false);
603  HEAP->CollectAllGarbage(false);
604}
605
606
607THREADED_TEST(ScavengeExternalString) {
608  TestResource::dispose_count = 0;
609  bool in_new_space = false;
610  {
611    v8::HandleScope scope;
612    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
613    Local<String> string =
614        String::NewExternal(new TestResource(two_byte_string));
615    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
616    HEAP->CollectGarbage(i::NEW_SPACE);
617    in_new_space = HEAP->InNewSpace(*istring);
618    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
619    CHECK_EQ(0, TestResource::dispose_count);
620  }
621  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
622  CHECK_EQ(1, TestResource::dispose_count);
623}
624
625
626THREADED_TEST(ScavengeExternalAsciiString) {
627  TestAsciiResource::dispose_count = 0;
628  bool in_new_space = false;
629  {
630    v8::HandleScope scope;
631    const char* one_byte_string = "test string";
632    Local<String> string = String::NewExternal(
633        new TestAsciiResource(i::StrDup(one_byte_string)));
634    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
635    HEAP->CollectGarbage(i::NEW_SPACE);
636    in_new_space = HEAP->InNewSpace(*istring);
637    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
638    CHECK_EQ(0, TestAsciiResource::dispose_count);
639  }
640  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
641  CHECK_EQ(1, TestAsciiResource::dispose_count);
642}
643
644
645class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
646 public:
647  static int dispose_calls;
648
649  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
650      : TestAsciiResource(data),
651        dispose_(dispose) { }
652
653  void Dispose() {
654    ++dispose_calls;
655    if (dispose_) delete this;
656  }
657 private:
658  bool dispose_;
659};
660
661
662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
663
664
665TEST(ExternalStringWithDisposeHandling) {
666  const char* c_source = "1 + 2 * 3";
667
668  // Use a stack allocated external string resource allocated object.
669  TestAsciiResource::dispose_count = 0;
670  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
672  {
673    v8::HandleScope scope;
674    LocalContext env;
675    Local<String> source =  String::NewExternal(&res_stack);
676    Local<Script> script = Script::Compile(source);
677    Local<Value> value = script->Run();
678    CHECK(value->IsNumber());
679    CHECK_EQ(7, value->Int32Value());
680    HEAP->CollectAllGarbage(false);
681    CHECK_EQ(0, TestAsciiResource::dispose_count);
682  }
683  i::Isolate::Current()->compilation_cache()->Clear();
684  HEAP->CollectAllGarbage(false);
685  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
686  CHECK_EQ(0, TestAsciiResource::dispose_count);
687
688  // Use a heap allocated external string resource allocated object.
689  TestAsciiResource::dispose_count = 0;
690  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691  TestAsciiResource* res_heap =
692      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
693  {
694    v8::HandleScope scope;
695    LocalContext env;
696    Local<String> source =  String::NewExternal(res_heap);
697    Local<Script> script = Script::Compile(source);
698    Local<Value> value = script->Run();
699    CHECK(value->IsNumber());
700    CHECK_EQ(7, value->Int32Value());
701    HEAP->CollectAllGarbage(false);
702    CHECK_EQ(0, TestAsciiResource::dispose_count);
703  }
704  i::Isolate::Current()->compilation_cache()->Clear();
705  HEAP->CollectAllGarbage(false);
706  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
707  CHECK_EQ(1, TestAsciiResource::dispose_count);
708}
709
710
711THREADED_TEST(StringConcat) {
712  {
713    v8::HandleScope scope;
714    LocalContext env;
715    const char* one_byte_string_1 = "function a_times_t";
716    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722    Local<String> left = v8_str(one_byte_string_1);
723
724    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725    Local<String> right = String::New(two_byte_source);
726    i::DeleteArray(two_byte_source);
727
728    Local<String> source = String::Concat(left, right);
729    right = String::NewExternal(
730        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731    source = String::Concat(source, right);
732    right = String::NewExternal(
733        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734    source = String::Concat(source, right);
735    right = v8_str(one_byte_string_2);
736    source = String::Concat(source, right);
737
738    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739    right = String::New(two_byte_source);
740    i::DeleteArray(two_byte_source);
741
742    source = String::Concat(source, right);
743    right = String::NewExternal(
744        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745    source = String::Concat(source, right);
746    Local<Script> script = Script::Compile(source);
747    Local<Value> value = script->Run();
748    CHECK(value->IsNumber());
749    CHECK_EQ(68, value->Int32Value());
750  }
751  i::Isolate::Current()->compilation_cache()->Clear();
752  HEAP->CollectAllGarbage(false);
753  HEAP->CollectAllGarbage(false);
754}
755
756
757THREADED_TEST(GlobalProperties) {
758  v8::HandleScope scope;
759  LocalContext env;
760  v8::Handle<v8::Object> global = env->Global();
761  global->Set(v8_str("pi"), v8_num(3.1415926));
762  Local<Value> pi = global->Get(v8_str("pi"));
763  CHECK_EQ(3.1415926, pi->NumberValue());
764}
765
766
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768  ApiTestFuzzer::Fuzz();
769  return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774  ApiTestFuzzer::Fuzz();
775  args.This()->Set(v8_str("x"), v8_num(1));
776  args.This()->Set(v8_str("y"), v8_num(2));
777  return args.This();
778}
779
780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781  ApiTestFuzzer::Fuzz();
782  return v8_num(239);
783}
784
785
786THREADED_TEST(FunctionTemplate) {
787  v8::HandleScope scope;
788  LocalContext env;
789  {
790    Local<v8::FunctionTemplate> fun_templ =
791        v8::FunctionTemplate::New(handle_call);
792    Local<Function> fun = fun_templ->GetFunction();
793    env->Global()->Set(v8_str("obj"), fun);
794    Local<Script> script = v8_compile("obj()");
795    CHECK_EQ(102, script->Run()->Int32Value());
796  }
797  // Use SetCallHandler to initialize a function template, should work like the
798  // previous one.
799  {
800    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801    fun_templ->SetCallHandler(handle_call);
802    Local<Function> fun = fun_templ->GetFunction();
803    env->Global()->Set(v8_str("obj"), fun);
804    Local<Script> script = v8_compile("obj()");
805    CHECK_EQ(102, script->Run()->Int32Value());
806  }
807  // Test constructor calls.
808  {
809    Local<v8::FunctionTemplate> fun_templ =
810        v8::FunctionTemplate::New(construct_call);
811    fun_templ->SetClassName(v8_str("funky"));
812    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
813    Local<Function> fun = fun_templ->GetFunction();
814    env->Global()->Set(v8_str("obj"), fun);
815    Local<Script> script = v8_compile("var s = new obj(); s.x");
816    CHECK_EQ(1, script->Run()->Int32Value());
817
818    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819    CHECK_EQ(v8_str("[object funky]"), result);
820
821    result = v8_compile("(new obj()).m")->Run();
822    CHECK_EQ(239, result->Int32Value());
823  }
824}
825
826
827static void* expected_ptr;
828static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829  void* ptr = v8::External::Unwrap(args.Data());
830  CHECK_EQ(expected_ptr, ptr);
831  return v8::Boolean::New(true);
832}
833
834
835static void TestExternalPointerWrapping() {
836  v8::HandleScope scope;
837  LocalContext env;
838
839  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841  v8::Handle<v8::Object> obj = v8::Object::New();
842  obj->Set(v8_str("func"),
843           v8::FunctionTemplate::New(callback, data)->GetFunction());
844  env->Global()->Set(v8_str("obj"), obj);
845
846  CHECK(CompileRun(
847        "function foo() {\n"
848        "  for (var i = 0; i < 13; i++) obj.func();\n"
849        "}\n"
850        "foo(), true")->BooleanValue());
851}
852
853
854THREADED_TEST(ExternalWrap) {
855  // Check heap allocated object.
856  int* ptr = new int;
857  expected_ptr = ptr;
858  TestExternalPointerWrapping();
859  delete ptr;
860
861  // Check stack allocated object.
862  int foo;
863  expected_ptr = &foo;
864  TestExternalPointerWrapping();
865
866  // Check not aligned addresses.
867  const int n = 100;
868  char* s = new char[n];
869  for (int i = 0; i < n; i++) {
870    expected_ptr = s + i;
871    TestExternalPointerWrapping();
872  }
873
874  delete[] s;
875
876  // Check several invalid addresses.
877  expected_ptr = reinterpret_cast<void*>(1);
878  TestExternalPointerWrapping();
879
880  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881  TestExternalPointerWrapping();
882
883  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884  TestExternalPointerWrapping();
885
886#if defined(V8_HOST_ARCH_X64)
887  // Check a value with a leading 1 bit in x64 Smi encoding.
888  expected_ptr = reinterpret_cast<void*>(0x400000000);
889  TestExternalPointerWrapping();
890
891  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892  TestExternalPointerWrapping();
893
894  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895  TestExternalPointerWrapping();
896#endif
897}
898
899
900THREADED_TEST(FindInstanceInPrototypeChain) {
901  v8::HandleScope scope;
902  LocalContext env;
903
904  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907  derived->Inherit(base);
908
909  Local<v8::Function> base_function = base->GetFunction();
910  Local<v8::Function> derived_function = derived->GetFunction();
911  Local<v8::Function> other_function = other->GetFunction();
912
913  Local<v8::Object> base_instance = base_function->NewInstance();
914  Local<v8::Object> derived_instance = derived_function->NewInstance();
915  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916  Local<v8::Object> other_instance = other_function->NewInstance();
917  derived_instance2->Set(v8_str("__proto__"), derived_instance);
918  other_instance->Set(v8_str("__proto__"), derived_instance2);
919
920  // base_instance is only an instance of base.
921  CHECK_EQ(base_instance,
922           base_instance->FindInstanceInPrototypeChain(base));
923  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925
926  // derived_instance is an instance of base and derived.
927  CHECK_EQ(derived_instance,
928           derived_instance->FindInstanceInPrototypeChain(base));
929  CHECK_EQ(derived_instance,
930           derived_instance->FindInstanceInPrototypeChain(derived));
931  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932
933  // other_instance is an instance of other and its immediate
934  // prototype derived_instance2 is an instance of base and derived.
935  // Note, derived_instance is an instance of base and derived too,
936  // but it comes after derived_instance2 in the prototype chain of
937  // other_instance.
938  CHECK_EQ(derived_instance2,
939           other_instance->FindInstanceInPrototypeChain(base));
940  CHECK_EQ(derived_instance2,
941           other_instance->FindInstanceInPrototypeChain(derived));
942  CHECK_EQ(other_instance,
943           other_instance->FindInstanceInPrototypeChain(other));
944}
945
946
947THREADED_TEST(TinyInteger) {
948  v8::HandleScope scope;
949  LocalContext env;
950  int32_t value = 239;
951  Local<v8::Integer> value_obj = v8::Integer::New(value);
952  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953}
954
955
956THREADED_TEST(BigSmiInteger) {
957  v8::HandleScope scope;
958  LocalContext env;
959  int32_t value = i::Smi::kMaxValue;
960  // We cannot add one to a Smi::kMaxValue without wrapping.
961  if (i::kSmiValueSize < 32) {
962    CHECK(i::Smi::IsValid(value));
963    CHECK(!i::Smi::IsValid(value + 1));
964    Local<v8::Integer> value_obj = v8::Integer::New(value);
965    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966  }
967}
968
969
970THREADED_TEST(BigInteger) {
971  v8::HandleScope scope;
972  LocalContext env;
973  // We cannot add one to a Smi::kMaxValue without wrapping.
974  if (i::kSmiValueSize < 32) {
975    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976    // The code will not be run in that case, due to the "if" guard.
977    int32_t value =
978        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979    CHECK(value > i::Smi::kMaxValue);
980    CHECK(!i::Smi::IsValid(value));
981    Local<v8::Integer> value_obj = v8::Integer::New(value);
982    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983  }
984}
985
986
987THREADED_TEST(TinyUnsignedInteger) {
988  v8::HandleScope scope;
989  LocalContext env;
990  uint32_t value = 239;
991  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993}
994
995
996THREADED_TEST(BigUnsignedSmiInteger) {
997  v8::HandleScope scope;
998  LocalContext env;
999  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000  CHECK(i::Smi::IsValid(value));
1001  CHECK(!i::Smi::IsValid(value + 1));
1002  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004}
1005
1006
1007THREADED_TEST(BigUnsignedInteger) {
1008  v8::HandleScope scope;
1009  LocalContext env;
1010  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012  CHECK(!i::Smi::IsValid(value));
1013  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015}
1016
1017
1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019  v8::HandleScope scope;
1020  LocalContext env;
1021  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022  uint32_t value = INT32_MAX_AS_UINT + 1;
1023  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1024  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026}
1027
1028
1029THREADED_TEST(IsNativeError) {
1030  v8::HandleScope scope;
1031  LocalContext env;
1032  v8::Handle<Value> syntax_error = CompileRun(
1033      "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034  CHECK(syntax_error->IsNativeError());
1035  v8::Handle<Value> not_error = CompileRun("{a:42}");
1036  CHECK(!not_error->IsNativeError());
1037  v8::Handle<Value> not_object = CompileRun("42");
1038  CHECK(!not_object->IsNativeError());
1039}
1040
1041
1042THREADED_TEST(StringObject) {
1043  v8::HandleScope scope;
1044  LocalContext env;
1045  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046  CHECK(boxed_string->IsStringObject());
1047  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048  CHECK(!unboxed_string->IsStringObject());
1049  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050  CHECK(!boxed_not_string->IsStringObject());
1051  v8::Handle<Value> not_object = CompileRun("0");
1052  CHECK(!not_object->IsStringObject());
1053  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054  CHECK(!as_boxed.IsEmpty());
1055  Local<v8::String> the_string = as_boxed->StringValue();
1056  CHECK(!the_string.IsEmpty());
1057  ExpectObject("\"test\"", the_string);
1058  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059  CHECK(new_boxed_string->IsStringObject());
1060  as_boxed = new_boxed_string.As<v8::StringObject>();
1061  the_string = as_boxed->StringValue();
1062  CHECK(!the_string.IsEmpty());
1063  ExpectObject("\"test\"", the_string);
1064}
1065
1066
1067THREADED_TEST(NumberObject) {
1068  v8::HandleScope scope;
1069  LocalContext env;
1070  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071  CHECK(boxed_number->IsNumberObject());
1072  v8::Handle<Value> unboxed_number = CompileRun("42");
1073  CHECK(!unboxed_number->IsNumberObject());
1074  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075  CHECK(!boxed_not_number->IsNumberObject());
1076  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077  CHECK(!as_boxed.IsEmpty());
1078  double the_number = as_boxed->NumberValue();
1079  CHECK_EQ(42.0, the_number);
1080  v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081  CHECK(new_boxed_number->IsNumberObject());
1082  as_boxed = new_boxed_number.As<v8::NumberObject>();
1083  the_number = as_boxed->NumberValue();
1084  CHECK_EQ(43.0, the_number);
1085}
1086
1087
1088THREADED_TEST(BooleanObject) {
1089  v8::HandleScope scope;
1090  LocalContext env;
1091  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092  CHECK(boxed_boolean->IsBooleanObject());
1093  v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094  CHECK(!unboxed_boolean->IsBooleanObject());
1095  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096  CHECK(!boxed_not_boolean->IsBooleanObject());
1097  v8::Handle<v8::BooleanObject> as_boxed =
1098      boxed_boolean.As<v8::BooleanObject>();
1099  CHECK(!as_boxed.IsEmpty());
1100  bool the_boolean = as_boxed->BooleanValue();
1101  CHECK_EQ(true, the_boolean);
1102  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104  CHECK(boxed_true->IsBooleanObject());
1105  CHECK(boxed_false->IsBooleanObject());
1106  as_boxed = boxed_true.As<v8::BooleanObject>();
1107  CHECK_EQ(true, as_boxed->BooleanValue());
1108  as_boxed = boxed_false.As<v8::BooleanObject>();
1109  CHECK_EQ(false, as_boxed->BooleanValue());
1110}
1111
1112
1113THREADED_TEST(Number) {
1114  v8::HandleScope scope;
1115  LocalContext env;
1116  double PI = 3.1415926;
1117  Local<v8::Number> pi_obj = v8::Number::New(PI);
1118  CHECK_EQ(PI, pi_obj->NumberValue());
1119}
1120
1121
1122THREADED_TEST(ToNumber) {
1123  v8::HandleScope scope;
1124  LocalContext env;
1125  Local<String> str = v8_str("3.1415926");
1126  CHECK_EQ(3.1415926, str->NumberValue());
1127  v8::Handle<v8::Boolean> t = v8::True();
1128  CHECK_EQ(1.0, t->NumberValue());
1129  v8::Handle<v8::Boolean> f = v8::False();
1130  CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
1135  v8::HandleScope scope;
1136  LocalContext env;
1137  double PI = 3.1415926;
1138  Local<Value> date = v8::Date::New(PI);
1139  CHECK_EQ(3.0, date->NumberValue());
1140  date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1142}
1143
1144
1145THREADED_TEST(Boolean) {
1146  v8::HandleScope scope;
1147  LocalContext env;
1148  v8::Handle<v8::Boolean> t = v8::True();
1149  CHECK(t->Value());
1150  v8::Handle<v8::Boolean> f = v8::False();
1151  CHECK(!f->Value());
1152  v8::Handle<v8::Primitive> u = v8::Undefined();
1153  CHECK(!u->BooleanValue());
1154  v8::Handle<v8::Primitive> n = v8::Null();
1155  CHECK(!n->BooleanValue());
1156  v8::Handle<String> str1 = v8_str("");
1157  CHECK(!str1->BooleanValue());
1158  v8::Handle<String> str2 = v8_str("x");
1159  CHECK(str2->BooleanValue());
1160  CHECK(!v8::Number::New(0)->BooleanValue());
1161  CHECK(v8::Number::New(-1)->BooleanValue());
1162  CHECK(v8::Number::New(1)->BooleanValue());
1163  CHECK(v8::Number::New(42)->BooleanValue());
1164  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165}
1166
1167
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169  ApiTestFuzzer::Fuzz();
1170  return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175  ApiTestFuzzer::Fuzz();
1176  return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181  v8::HandleScope scope;
1182  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1183  func_templ->PrototypeTemplate()->Set(
1184      "dummy",
1185      v8::FunctionTemplate::New(DummyCallHandler));
1186  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187  templ->Set("x", v8_num(200));
1188  templ->SetAccessor(v8_str("m"), GetM);
1189  LocalContext env(0, templ);
1190  v8::Handle<v8::Object> obj = env->Global();
1191  v8::Handle<Script> script = v8_compile("dummy()");
1192  v8::Handle<Value> result = script->Run();
1193  CHECK_EQ(13.4, result->NumberValue());
1194  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1195  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1196}
1197
1198
1199THREADED_TEST(ObjectTemplate) {
1200  v8::HandleScope scope;
1201  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1202  templ1->Set("x", v8_num(10));
1203  templ1->Set("y", v8_num(13));
1204  LocalContext env;
1205  Local<v8::Object> instance1 = templ1->NewInstance();
1206  env->Global()->Set(v8_str("p"), instance1);
1207  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1208  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1209  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1210  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1211  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1212  templ2->Set("a", v8_num(12));
1213  templ2->Set("b", templ1);
1214  Local<v8::Object> instance2 = templ2->NewInstance();
1215  env->Global()->Set(v8_str("q"), instance2);
1216  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1217  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1218  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1219  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1220}
1221
1222
1223static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1224  ApiTestFuzzer::Fuzz();
1225  return v8_num(17.2);
1226}
1227
1228
1229static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1230  ApiTestFuzzer::Fuzz();
1231  return v8_num(15.2);
1232}
1233
1234
1235THREADED_TEST(DescriptorInheritance) {
1236  v8::HandleScope scope;
1237  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1238  super->PrototypeTemplate()->Set("flabby",
1239                                  v8::FunctionTemplate::New(GetFlabby));
1240  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1241
1242  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1243
1244  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1245  base1->Inherit(super);
1246  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1247
1248  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1249  base2->Inherit(super);
1250  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1251
1252  LocalContext env;
1253
1254  env->Global()->Set(v8_str("s"), super->GetFunction());
1255  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1256  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1257
1258  // Checks right __proto__ chain.
1259  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1260  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1261
1262  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1263
1264  // Instance accessor should not be visible on function object or its prototype
1265  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1266  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1267  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1268
1269  env->Global()->Set(v8_str("obj"),
1270                     base1->GetFunction()->NewInstance());
1271  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1272  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1273  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1274  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1275  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1276
1277  env->Global()->Set(v8_str("obj2"),
1278                     base2->GetFunction()->NewInstance());
1279  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1280  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1281  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1282  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1283  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1284
1285  // base1 and base2 cannot cross reference to each's prototype
1286  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1287  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1288}
1289
1290
1291int echo_named_call_count;
1292
1293
1294static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1295                                           const AccessorInfo& info) {
1296  ApiTestFuzzer::Fuzz();
1297  CHECK_EQ(v8_str("data"), info.Data());
1298  echo_named_call_count++;
1299  return name;
1300}
1301
1302
1303THREADED_TEST(NamedPropertyHandlerGetter) {
1304  echo_named_call_count = 0;
1305  v8::HandleScope scope;
1306  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1307  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1308                                                     0, 0, 0, 0,
1309                                                     v8_str("data"));
1310  LocalContext env;
1311  env->Global()->Set(v8_str("obj"),
1312                     templ->GetFunction()->NewInstance());
1313  CHECK_EQ(echo_named_call_count, 0);
1314  v8_compile("obj.x")->Run();
1315  CHECK_EQ(echo_named_call_count, 1);
1316  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1317  v8::Handle<Value> str = CompileRun(code);
1318  String::AsciiValue value(str);
1319  CHECK_EQ(*value, "oddlepoddle");
1320  // Check default behavior
1321  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1322  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1323  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1324}
1325
1326
1327int echo_indexed_call_count = 0;
1328
1329
1330static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1331                                             const AccessorInfo& info) {
1332  ApiTestFuzzer::Fuzz();
1333  CHECK_EQ(v8_num(637), info.Data());
1334  echo_indexed_call_count++;
1335  return v8_num(index);
1336}
1337
1338
1339THREADED_TEST(IndexedPropertyHandlerGetter) {
1340  v8::HandleScope scope;
1341  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1342  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1343                                                       0, 0, 0, 0,
1344                                                       v8_num(637));
1345  LocalContext env;
1346  env->Global()->Set(v8_str("obj"),
1347                     templ->GetFunction()->NewInstance());
1348  Local<Script> script = v8_compile("obj[900]");
1349  CHECK_EQ(script->Run()->Int32Value(), 900);
1350}
1351
1352
1353v8::Handle<v8::Object> bottom;
1354
1355static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1356    uint32_t index,
1357    const AccessorInfo& info) {
1358  ApiTestFuzzer::Fuzz();
1359  CHECK(info.This()->Equals(bottom));
1360  return v8::Handle<Value>();
1361}
1362
1363static v8::Handle<Value> CheckThisNamedPropertyHandler(
1364    Local<String> name,
1365    const AccessorInfo& info) {
1366  ApiTestFuzzer::Fuzz();
1367  CHECK(info.This()->Equals(bottom));
1368  return v8::Handle<Value>();
1369}
1370
1371
1372v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1373                                                 Local<Value> value,
1374                                                 const AccessorInfo& info) {
1375  ApiTestFuzzer::Fuzz();
1376  CHECK(info.This()->Equals(bottom));
1377  return v8::Handle<Value>();
1378}
1379
1380
1381v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1382                                               Local<Value> value,
1383                                               const AccessorInfo& info) {
1384  ApiTestFuzzer::Fuzz();
1385  CHECK(info.This()->Equals(bottom));
1386  return v8::Handle<Value>();
1387}
1388
1389v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1390    uint32_t index,
1391    const AccessorInfo& info) {
1392  ApiTestFuzzer::Fuzz();
1393  CHECK(info.This()->Equals(bottom));
1394  return v8::Handle<v8::Integer>();
1395}
1396
1397
1398v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1399                                                    const AccessorInfo& info) {
1400  ApiTestFuzzer::Fuzz();
1401  CHECK(info.This()->Equals(bottom));
1402  return v8::Handle<v8::Integer>();
1403}
1404
1405
1406v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1407    uint32_t index,
1408    const AccessorInfo& info) {
1409  ApiTestFuzzer::Fuzz();
1410  CHECK(info.This()->Equals(bottom));
1411  return v8::Handle<v8::Boolean>();
1412}
1413
1414
1415v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1416    Local<String> property,
1417    const AccessorInfo& info) {
1418  ApiTestFuzzer::Fuzz();
1419  CHECK(info.This()->Equals(bottom));
1420  return v8::Handle<v8::Boolean>();
1421}
1422
1423
1424v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1425    const AccessorInfo& info) {
1426  ApiTestFuzzer::Fuzz();
1427  CHECK(info.This()->Equals(bottom));
1428  return v8::Handle<v8::Array>();
1429}
1430
1431
1432v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1433    const AccessorInfo& info) {
1434  ApiTestFuzzer::Fuzz();
1435  CHECK(info.This()->Equals(bottom));
1436  return v8::Handle<v8::Array>();
1437}
1438
1439
1440THREADED_TEST(PropertyHandlerInPrototype) {
1441  v8::HandleScope scope;
1442  LocalContext env;
1443
1444  // Set up a prototype chain with three interceptors.
1445  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1446  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1447      CheckThisIndexedPropertyHandler,
1448      CheckThisIndexedPropertySetter,
1449      CheckThisIndexedPropertyQuery,
1450      CheckThisIndexedPropertyDeleter,
1451      CheckThisIndexedPropertyEnumerator);
1452
1453  templ->InstanceTemplate()->SetNamedPropertyHandler(
1454      CheckThisNamedPropertyHandler,
1455      CheckThisNamedPropertySetter,
1456      CheckThisNamedPropertyQuery,
1457      CheckThisNamedPropertyDeleter,
1458      CheckThisNamedPropertyEnumerator);
1459
1460  bottom = templ->GetFunction()->NewInstance();
1461  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1462  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1463
1464  bottom->Set(v8_str("__proto__"), middle);
1465  middle->Set(v8_str("__proto__"), top);
1466  env->Global()->Set(v8_str("obj"), bottom);
1467
1468  // Indexed and named get.
1469  Script::Compile(v8_str("obj[0]"))->Run();
1470  Script::Compile(v8_str("obj.x"))->Run();
1471
1472  // Indexed and named set.
1473  Script::Compile(v8_str("obj[1] = 42"))->Run();
1474  Script::Compile(v8_str("obj.y = 42"))->Run();
1475
1476  // Indexed and named query.
1477  Script::Compile(v8_str("0 in obj"))->Run();
1478  Script::Compile(v8_str("'x' in obj"))->Run();
1479
1480  // Indexed and named deleter.
1481  Script::Compile(v8_str("delete obj[0]"))->Run();
1482  Script::Compile(v8_str("delete obj.x"))->Run();
1483
1484  // Enumerators.
1485  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1486}
1487
1488
1489static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1490                                               const AccessorInfo& info) {
1491  ApiTestFuzzer::Fuzz();
1492  if (v8_str("pre")->Equals(key)) {
1493    return v8_str("PrePropertyHandler: pre");
1494  }
1495  return v8::Handle<String>();
1496}
1497
1498
1499static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1500                                                       const AccessorInfo&) {
1501  if (v8_str("pre")->Equals(key)) {
1502    return v8::Integer::New(v8::None);
1503  }
1504
1505  return v8::Handle<v8::Integer>();  // do not intercept the call
1506}
1507
1508
1509THREADED_TEST(PrePropertyHandler) {
1510  v8::HandleScope scope;
1511  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1512  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1513                                                    0,
1514                                                    PrePropertyHandlerQuery);
1515  LocalContext env(NULL, desc->InstanceTemplate());
1516  Script::Compile(v8_str(
1517      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1518  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1519  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1520  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1521  CHECK_EQ(v8_str("Object: on"), result_on);
1522  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1523  CHECK(result_post.IsEmpty());
1524}
1525
1526
1527THREADED_TEST(UndefinedIsNotEnumerable) {
1528  v8::HandleScope scope;
1529  LocalContext env;
1530  v8::Handle<Value> result = Script::Compile(v8_str(
1531      "this.propertyIsEnumerable(undefined)"))->Run();
1532  CHECK(result->IsFalse());
1533}
1534
1535
1536v8::Handle<Script> call_recursively_script;
1537static const int kTargetRecursionDepth = 200;  // near maximum
1538
1539
1540static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1541  ApiTestFuzzer::Fuzz();
1542  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1543  if (depth == kTargetRecursionDepth) return v8::Undefined();
1544  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1545  return call_recursively_script->Run();
1546}
1547
1548
1549static v8::Handle<Value> CallFunctionRecursivelyCall(
1550    const v8::Arguments& args) {
1551  ApiTestFuzzer::Fuzz();
1552  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1553  if (depth == kTargetRecursionDepth) {
1554    printf("[depth = %d]\n", depth);
1555    return v8::Undefined();
1556  }
1557  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1558  v8::Handle<Value> function =
1559      args.This()->Get(v8_str("callFunctionRecursively"));
1560  return function.As<Function>()->Call(args.This(), 0, NULL);
1561}
1562
1563
1564THREADED_TEST(DeepCrossLanguageRecursion) {
1565  v8::HandleScope scope;
1566  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1567  global->Set(v8_str("callScriptRecursively"),
1568              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1569  global->Set(v8_str("callFunctionRecursively"),
1570              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1571  LocalContext env(NULL, global);
1572
1573  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574  call_recursively_script = v8_compile("callScriptRecursively()");
1575  v8::Handle<Value> result = call_recursively_script->Run();
1576  call_recursively_script = v8::Handle<Script>();
1577
1578  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1579  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1580}
1581
1582
1583static v8::Handle<Value>
1584    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1585  ApiTestFuzzer::Fuzz();
1586  return v8::ThrowException(key);
1587}
1588
1589
1590static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1591                                                    Local<Value>,
1592                                                    const AccessorInfo&) {
1593  v8::ThrowException(key);
1594  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1595}
1596
1597
1598THREADED_TEST(CallbackExceptionRegression) {
1599  v8::HandleScope scope;
1600  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1601  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1602                               ThrowingPropertyHandlerSet);
1603  LocalContext env;
1604  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1605  v8::Handle<Value> otto = Script::Compile(v8_str(
1606      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1607  CHECK_EQ(v8_str("otto"), otto);
1608  v8::Handle<Value> netto = Script::Compile(v8_str(
1609      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1610  CHECK_EQ(v8_str("netto"), netto);
1611}
1612
1613
1614THREADED_TEST(FunctionPrototype) {
1615  v8::HandleScope scope;
1616  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1617  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1618  LocalContext env;
1619  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1620  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1621  CHECK_EQ(script->Run()->Int32Value(), 321);
1622}
1623
1624
1625THREADED_TEST(InternalFields) {
1626  v8::HandleScope scope;
1627  LocalContext env;
1628
1629  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1630  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1631  instance_templ->SetInternalFieldCount(1);
1632  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1633  CHECK_EQ(1, obj->InternalFieldCount());
1634  CHECK(obj->GetInternalField(0)->IsUndefined());
1635  obj->SetInternalField(0, v8_num(17));
1636  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1637}
1638
1639
1640THREADED_TEST(GlobalObjectInternalFields) {
1641  v8::HandleScope scope;
1642  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1643  global_template->SetInternalFieldCount(1);
1644  LocalContext env(NULL, global_template);
1645  v8::Handle<v8::Object> global_proxy = env->Global();
1646  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1647  CHECK_EQ(1, global->InternalFieldCount());
1648  CHECK(global->GetInternalField(0)->IsUndefined());
1649  global->SetInternalField(0, v8_num(17));
1650  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1651}
1652
1653
1654THREADED_TEST(InternalFieldsNativePointers) {
1655  v8::HandleScope scope;
1656  LocalContext env;
1657
1658  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1659  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1660  instance_templ->SetInternalFieldCount(1);
1661  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1662  CHECK_EQ(1, obj->InternalFieldCount());
1663  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1664
1665  char* data = new char[100];
1666
1667  void* aligned = data;
1668  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1669  void* unaligned = data + 1;
1670  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1671
1672  // Check reading and writing aligned pointers.
1673  obj->SetPointerInInternalField(0, aligned);
1674  HEAP->CollectAllGarbage(false);
1675  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1676
1677  // Check reading and writing unaligned pointers.
1678  obj->SetPointerInInternalField(0, unaligned);
1679  HEAP->CollectAllGarbage(false);
1680  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1681
1682  delete[] data;
1683}
1684
1685
1686THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1687  v8::HandleScope scope;
1688  LocalContext env;
1689
1690  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1691  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1692  instance_templ->SetInternalFieldCount(1);
1693  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1694  CHECK_EQ(1, obj->InternalFieldCount());
1695  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1696
1697  char* data = new char[100];
1698
1699  void* aligned = data;
1700  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1701  void* unaligned = data + 1;
1702  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1703
1704  obj->SetPointerInInternalField(0, aligned);
1705  HEAP->CollectAllGarbage(false);
1706  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1707
1708  obj->SetPointerInInternalField(0, unaligned);
1709  HEAP->CollectAllGarbage(false);
1710  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1711
1712  obj->SetInternalField(0, v8::External::Wrap(aligned));
1713  HEAP->CollectAllGarbage(false);
1714  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1715
1716  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1717  HEAP->CollectAllGarbage(false);
1718  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1719
1720  delete[] data;
1721}
1722
1723
1724THREADED_TEST(IdentityHash) {
1725  v8::HandleScope scope;
1726  LocalContext env;
1727
1728  // Ensure that the test starts with an fresh heap to test whether the hash
1729  // code is based on the address.
1730  HEAP->CollectAllGarbage(false);
1731  Local<v8::Object> obj = v8::Object::New();
1732  int hash = obj->GetIdentityHash();
1733  int hash1 = obj->GetIdentityHash();
1734  CHECK_EQ(hash, hash1);
1735  int hash2 = v8::Object::New()->GetIdentityHash();
1736  // Since the identity hash is essentially a random number two consecutive
1737  // objects should not be assigned the same hash code. If the test below fails
1738  // the random number generator should be evaluated.
1739  CHECK_NE(hash, hash2);
1740  HEAP->CollectAllGarbage(false);
1741  int hash3 = v8::Object::New()->GetIdentityHash();
1742  // Make sure that the identity hash is not based on the initial address of
1743  // the object alone. If the test below fails the random number generator
1744  // should be evaluated.
1745  CHECK_NE(hash, hash3);
1746  int hash4 = obj->GetIdentityHash();
1747  CHECK_EQ(hash, hash4);
1748
1749  // Check identity hashes behaviour in the presence of JS accessors.
1750  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1751  {
1752    CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1753    Local<v8::Object> o1 = v8::Object::New();
1754    Local<v8::Object> o2 = v8::Object::New();
1755    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1756  }
1757  {
1758    CompileRun(
1759        "function cnst() { return 42; };\n"
1760        "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1761    Local<v8::Object> o1 = v8::Object::New();
1762    Local<v8::Object> o2 = v8::Object::New();
1763    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1764  }
1765}
1766
1767
1768THREADED_TEST(HiddenProperties) {
1769  v8::HandleScope scope;
1770  LocalContext env;
1771
1772  v8::Local<v8::Object> obj = v8::Object::New();
1773  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1774  v8::Local<v8::String> empty = v8_str("");
1775  v8::Local<v8::String> prop_name = v8_str("prop_name");
1776
1777  HEAP->CollectAllGarbage(false);
1778
1779  // Make sure delete of a non-existent hidden value works
1780  CHECK(obj->DeleteHiddenValue(key));
1781
1782  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1783  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1784  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1785  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1786
1787  HEAP->CollectAllGarbage(false);
1788
1789  // Make sure we do not find the hidden property.
1790  CHECK(!obj->Has(empty));
1791  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1792  CHECK(obj->Get(empty)->IsUndefined());
1793  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1794  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1795  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1796  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1797
1798  HEAP->CollectAllGarbage(false);
1799
1800  // Add another property and delete it afterwards to force the object in
1801  // slow case.
1802  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1803  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1804  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1805  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1806  CHECK(obj->Delete(prop_name));
1807  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1808
1809  HEAP->CollectAllGarbage(false);
1810
1811  CHECK(obj->DeleteHiddenValue(key));
1812  CHECK(obj->GetHiddenValue(key).IsEmpty());
1813}
1814
1815
1816THREADED_TEST(Regress97784) {
1817  // Regression test for crbug.com/97784
1818  // Messing with the Object.prototype should not have effect on
1819  // hidden properties.
1820  v8::HandleScope scope;
1821  LocalContext env;
1822
1823  v8::Local<v8::Object> obj = v8::Object::New();
1824  v8::Local<v8::String> key = v8_str("hidden");
1825
1826  CompileRun(
1827      "set_called = false;"
1828      "Object.defineProperty("
1829      "    Object.prototype,"
1830      "    'hidden',"
1831      "    {get: function() { return 45; },"
1832      "     set: function() { set_called = true; }})");
1833
1834  CHECK(obj->GetHiddenValue(key).IsEmpty());
1835  // Make sure that the getter and setter from Object.prototype is not invoked.
1836  // If it did we would have full access to the hidden properties in
1837  // the accessor.
1838  CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
1839  ExpectFalse("set_called");
1840  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
1841}
1842
1843
1844static bool interceptor_for_hidden_properties_called;
1845static v8::Handle<Value> InterceptorForHiddenProperties(
1846    Local<String> name, const AccessorInfo& info) {
1847  interceptor_for_hidden_properties_called = true;
1848  return v8::Handle<Value>();
1849}
1850
1851
1852THREADED_TEST(HiddenPropertiesWithInterceptors) {
1853  v8::HandleScope scope;
1854  LocalContext context;
1855
1856  interceptor_for_hidden_properties_called = false;
1857
1858  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1859
1860  // Associate an interceptor with an object and start setting hidden values.
1861  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1862  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1863  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1864  Local<v8::Function> function = fun_templ->GetFunction();
1865  Local<v8::Object> obj = function->NewInstance();
1866  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1867  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1868  CHECK(!interceptor_for_hidden_properties_called);
1869}
1870
1871
1872THREADED_TEST(External) {
1873  v8::HandleScope scope;
1874  int x = 3;
1875  Local<v8::External> ext = v8::External::New(&x);
1876  LocalContext env;
1877  env->Global()->Set(v8_str("ext"), ext);
1878  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1879  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1880  int* ptr = static_cast<int*>(reext->Value());
1881  CHECK_EQ(x, 3);
1882  *ptr = 10;
1883  CHECK_EQ(x, 10);
1884
1885  // Make sure unaligned pointers are wrapped properly.
1886  char* data = i::StrDup("0123456789");
1887  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1888  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1889  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1890  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1891
1892  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1893  CHECK_EQ('0', *char_ptr);
1894  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1895  CHECK_EQ('1', *char_ptr);
1896  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1897  CHECK_EQ('2', *char_ptr);
1898  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1899  CHECK_EQ('3', *char_ptr);
1900  i::DeleteArray(data);
1901}
1902
1903
1904THREADED_TEST(GlobalHandle) {
1905  v8::Persistent<String> global;
1906  {
1907    v8::HandleScope scope;
1908    Local<String> str = v8_str("str");
1909    global = v8::Persistent<String>::New(str);
1910  }
1911  CHECK_EQ(global->Length(), 3);
1912  global.Dispose();
1913}
1914
1915
1916static int NumberOfWeakCalls = 0;
1917static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1918  CHECK_EQ(reinterpret_cast<void*>(1234), id);
1919  NumberOfWeakCalls++;
1920  handle.Dispose();
1921}
1922
1923THREADED_TEST(ApiObjectGroups) {
1924  HandleScope scope;
1925  LocalContext env;
1926
1927  NumberOfWeakCalls = 0;
1928
1929  Persistent<Object> g1s1;
1930  Persistent<Object> g1s2;
1931  Persistent<Object> g1c1;
1932  Persistent<Object> g2s1;
1933  Persistent<Object> g2s2;
1934  Persistent<Object> g2c1;
1935
1936  {
1937    HandleScope scope;
1938    g1s1 = Persistent<Object>::New(Object::New());
1939    g1s2 = Persistent<Object>::New(Object::New());
1940    g1c1 = Persistent<Object>::New(Object::New());
1941    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1942    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1943    g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1944
1945    g2s1 = Persistent<Object>::New(Object::New());
1946    g2s2 = Persistent<Object>::New(Object::New());
1947    g2c1 = Persistent<Object>::New(Object::New());
1948    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1949    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1950    g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1951  }
1952
1953  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
1954
1955  // Connect group 1 and 2, make a cycle.
1956  CHECK(g1s2->Set(0, g2s2));
1957  CHECK(g2s1->Set(0, g1s1));
1958
1959  {
1960    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1961    Persistent<Value> g1_children[] = { g1c1 };
1962    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1963    Persistent<Value> g2_children[] = { g2c1 };
1964    V8::AddObjectGroup(g1_objects, 2);
1965    V8::AddImplicitReferences(g1s1, g1_children, 1);
1966    V8::AddObjectGroup(g2_objects, 2);
1967    V8::AddImplicitReferences(g2s2, g2_children, 1);
1968  }
1969  // Do a full GC
1970  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1971
1972  // All object should be alive.
1973  CHECK_EQ(0, NumberOfWeakCalls);
1974
1975  // Weaken the root.
1976  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1977  // But make children strong roots---all the objects (except for children)
1978  // should be collectable now.
1979  g1c1.ClearWeak();
1980  g2c1.ClearWeak();
1981
1982  // Groups are deleted, rebuild groups.
1983  {
1984    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1985    Persistent<Value> g1_children[] = { g1c1 };
1986    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1987    Persistent<Value> g2_children[] = { g2c1 };
1988    V8::AddObjectGroup(g1_objects, 2);
1989    V8::AddImplicitReferences(g1s1, g1_children, 1);
1990    V8::AddObjectGroup(g2_objects, 2);
1991    V8::AddImplicitReferences(g2s2, g2_children, 1);
1992  }
1993
1994  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
1995
1996  // All objects should be gone. 5 global handles in total.
1997  CHECK_EQ(5, NumberOfWeakCalls);
1998
1999  // And now make children weak again and collect them.
2000  g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2001  g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2002
2003  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2004  CHECK_EQ(7, NumberOfWeakCalls);
2005}
2006
2007
2008THREADED_TEST(ApiObjectGroupsCycle) {
2009  HandleScope scope;
2010  LocalContext env;
2011
2012  NumberOfWeakCalls = 0;
2013
2014  Persistent<Object> g1s1;
2015  Persistent<Object> g1s2;
2016  Persistent<Object> g2s1;
2017  Persistent<Object> g2s2;
2018  Persistent<Object> g3s1;
2019  Persistent<Object> g3s2;
2020
2021  {
2022    HandleScope scope;
2023    g1s1 = Persistent<Object>::New(Object::New());
2024    g1s2 = Persistent<Object>::New(Object::New());
2025    g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2026    g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2027
2028    g2s1 = Persistent<Object>::New(Object::New());
2029    g2s2 = Persistent<Object>::New(Object::New());
2030    g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2031    g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2032
2033    g3s1 = Persistent<Object>::New(Object::New());
2034    g3s2 = Persistent<Object>::New(Object::New());
2035    g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2036    g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2037  }
2038
2039  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
2040
2041  // Connect groups.  We're building the following cycle:
2042  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2043  // groups.
2044  {
2045    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2046    Persistent<Value> g1_children[] = { g2s1 };
2047    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2048    Persistent<Value> g2_children[] = { g3s1 };
2049    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2050    Persistent<Value> g3_children[] = { g1s1 };
2051    V8::AddObjectGroup(g1_objects, 2);
2052    V8::AddImplicitReferences(g1s1, g1_children, 1);
2053    V8::AddObjectGroup(g2_objects, 2);
2054    V8::AddImplicitReferences(g2s1, g2_children, 1);
2055    V8::AddObjectGroup(g3_objects, 2);
2056    V8::AddImplicitReferences(g3s1, g3_children, 1);
2057  }
2058  // Do a full GC
2059  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2060
2061  // All object should be alive.
2062  CHECK_EQ(0, NumberOfWeakCalls);
2063
2064  // Weaken the root.
2065  root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2066
2067  // Groups are deleted, rebuild groups.
2068  {
2069    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2070    Persistent<Value> g1_children[] = { g2s1 };
2071    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2072    Persistent<Value> g2_children[] = { g3s1 };
2073    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2074    Persistent<Value> g3_children[] = { g1s1 };
2075    V8::AddObjectGroup(g1_objects, 2);
2076    V8::AddImplicitReferences(g1s1, g1_children, 1);
2077    V8::AddObjectGroup(g2_objects, 2);
2078    V8::AddImplicitReferences(g2s1, g2_children, 1);
2079    V8::AddObjectGroup(g3_objects, 2);
2080    V8::AddImplicitReferences(g3s1, g3_children, 1);
2081  }
2082
2083  HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
2084
2085  // All objects should be gone. 7 global handles in total.
2086  CHECK_EQ(7, NumberOfWeakCalls);
2087}
2088
2089
2090THREADED_TEST(ScriptException) {
2091  v8::HandleScope scope;
2092  LocalContext env;
2093  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2094  v8::TryCatch try_catch;
2095  Local<Value> result = script->Run();
2096  CHECK(result.IsEmpty());
2097  CHECK(try_catch.HasCaught());
2098  String::AsciiValue exception_value(try_catch.Exception());
2099  CHECK_EQ(*exception_value, "panama!");
2100}
2101
2102
2103bool message_received;
2104
2105
2106static void check_message(v8::Handle<v8::Message> message,
2107                          v8::Handle<Value> data) {
2108  CHECK_EQ(5.76, data->NumberValue());
2109  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2110  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2111  message_received = true;
2112}
2113
2114
2115THREADED_TEST(MessageHandlerData) {
2116  message_received = false;
2117  v8::HandleScope scope;
2118  CHECK(!message_received);
2119  v8::V8::AddMessageListener(check_message, v8_num(5.76));
2120  LocalContext context;
2121  v8::ScriptOrigin origin =
2122      v8::ScriptOrigin(v8_str("6.75"));
2123  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2124                                                  &origin);
2125  script->SetData(v8_str("7.56"));
2126  script->Run();
2127  CHECK(message_received);
2128  // clear out the message listener
2129  v8::V8::RemoveMessageListeners(check_message);
2130}
2131
2132
2133THREADED_TEST(GetSetProperty) {
2134  v8::HandleScope scope;
2135  LocalContext context;
2136  context->Global()->Set(v8_str("foo"), v8_num(14));
2137  context->Global()->Set(v8_str("12"), v8_num(92));
2138  context->Global()->Set(v8::Integer::New(16), v8_num(32));
2139  context->Global()->Set(v8_num(13), v8_num(56));
2140  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2141  CHECK_EQ(14, foo->Int32Value());
2142  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2143  CHECK_EQ(92, twelve->Int32Value());
2144  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2145  CHECK_EQ(32, sixteen->Int32Value());
2146  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2147  CHECK_EQ(56, thirteen->Int32Value());
2148  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2149  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2150  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2151  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2152  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2153  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2154  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2155  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2156  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2157}
2158
2159
2160THREADED_TEST(PropertyAttributes) {
2161  v8::HandleScope scope;
2162  LocalContext context;
2163  // none
2164  Local<String> prop = v8_str("none");
2165  context->Global()->Set(prop, v8_num(7));
2166  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2167  // read-only
2168  prop = v8_str("read_only");
2169  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2170  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2171  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2172  Script::Compile(v8_str("read_only = 9"))->Run();
2173  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2174  context->Global()->Set(prop, v8_num(10));
2175  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2176  // dont-delete
2177  prop = v8_str("dont_delete");
2178  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2179  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2180  Script::Compile(v8_str("delete dont_delete"))->Run();
2181  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2182  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2183  // dont-enum
2184  prop = v8_str("dont_enum");
2185  context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2186  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2187  // absent
2188  prop = v8_str("absent");
2189  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2190  Local<Value> fake_prop = v8_num(1);
2191  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2192  // exception
2193  TryCatch try_catch;
2194  Local<Value> exception =
2195      CompileRun("({ toString: function() { throw 'exception';} })");
2196  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2197  CHECK(try_catch.HasCaught());
2198  String::AsciiValue exception_value(try_catch.Exception());
2199  CHECK_EQ("exception", *exception_value);
2200  try_catch.Reset();
2201}
2202
2203
2204THREADED_TEST(Array) {
2205  v8::HandleScope scope;
2206  LocalContext context;
2207  Local<v8::Array> array = v8::Array::New();
2208  CHECK_EQ(0, array->Length());
2209  CHECK(array->Get(0)->IsUndefined());
2210  CHECK(!array->Has(0));
2211  CHECK(array->Get(100)->IsUndefined());
2212  CHECK(!array->Has(100));
2213  array->Set(2, v8_num(7));
2214  CHECK_EQ(3, array->Length());
2215  CHECK(!array->Has(0));
2216  CHECK(!array->Has(1));
2217  CHECK(array->Has(2));
2218  CHECK_EQ(7, array->Get(2)->Int32Value());
2219  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2220  Local<v8::Array> arr = obj.As<v8::Array>();
2221  CHECK_EQ(3, arr->Length());
2222  CHECK_EQ(1, arr->Get(0)->Int32Value());
2223  CHECK_EQ(2, arr->Get(1)->Int32Value());
2224  CHECK_EQ(3, arr->Get(2)->Int32Value());
2225  array = v8::Array::New(27);
2226  CHECK_EQ(27, array->Length());
2227  array = v8::Array::New(-27);
2228  CHECK_EQ(0, array->Length());
2229}
2230
2231
2232v8::Handle<Value> HandleF(const v8::Arguments& args) {
2233  v8::HandleScope scope;
2234  ApiTestFuzzer::Fuzz();
2235  Local<v8::Array> result = v8::Array::New(args.Length());
2236  for (int i = 0; i < args.Length(); i++)
2237    result->Set(i, args[i]);
2238  return scope.Close(result);
2239}
2240
2241
2242THREADED_TEST(Vector) {
2243  v8::HandleScope scope;
2244  Local<ObjectTemplate> global = ObjectTemplate::New();
2245  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2246  LocalContext context(0, global);
2247
2248  const char* fun = "f()";
2249  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2250  CHECK_EQ(0, a0->Length());
2251
2252  const char* fun2 = "f(11)";
2253  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2254  CHECK_EQ(1, a1->Length());
2255  CHECK_EQ(11, a1->Get(0)->Int32Value());
2256
2257  const char* fun3 = "f(12, 13)";
2258  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2259  CHECK_EQ(2, a2->Length());
2260  CHECK_EQ(12, a2->Get(0)->Int32Value());
2261  CHECK_EQ(13, a2->Get(1)->Int32Value());
2262
2263  const char* fun4 = "f(14, 15, 16)";
2264  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2265  CHECK_EQ(3, a3->Length());
2266  CHECK_EQ(14, a3->Get(0)->Int32Value());
2267  CHECK_EQ(15, a3->Get(1)->Int32Value());
2268  CHECK_EQ(16, a3->Get(2)->Int32Value());
2269
2270  const char* fun5 = "f(17, 18, 19, 20)";
2271  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2272  CHECK_EQ(4, a4->Length());
2273  CHECK_EQ(17, a4->Get(0)->Int32Value());
2274  CHECK_EQ(18, a4->Get(1)->Int32Value());
2275  CHECK_EQ(19, a4->Get(2)->Int32Value());
2276  CHECK_EQ(20, a4->Get(3)->Int32Value());
2277}
2278
2279
2280THREADED_TEST(FunctionCall) {
2281  v8::HandleScope scope;
2282  LocalContext context;
2283  CompileRun(
2284    "function Foo() {"
2285    "  var result = [];"
2286    "  for (var i = 0; i < arguments.length; i++) {"
2287    "    result.push(arguments[i]);"
2288    "  }"
2289    "  return result;"
2290    "}");
2291  Local<Function> Foo =
2292      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2293
2294  v8::Handle<Value>* args0 = NULL;
2295  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2296  CHECK_EQ(0, a0->Length());
2297
2298  v8::Handle<Value> args1[] = { v8_num(1.1) };
2299  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2300  CHECK_EQ(1, a1->Length());
2301  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2302
2303  v8::Handle<Value> args2[] = { v8_num(2.2),
2304                                v8_num(3.3) };
2305  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2306  CHECK_EQ(2, a2->Length());
2307  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2308  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2309
2310  v8::Handle<Value> args3[] = { v8_num(4.4),
2311                                v8_num(5.5),
2312                                v8_num(6.6) };
2313  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2314  CHECK_EQ(3, a3->Length());
2315  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2316  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2317  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2318
2319  v8::Handle<Value> args4[] = { v8_num(7.7),
2320                                v8_num(8.8),
2321                                v8_num(9.9),
2322                                v8_num(10.11) };
2323  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2324  CHECK_EQ(4, a4->Length());
2325  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2326  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2327  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2328  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2329}
2330
2331
2332static const char* js_code_causing_out_of_memory =
2333    "var a = new Array(); while(true) a.push(a);";
2334
2335
2336// These tests run for a long time and prevent us from running tests
2337// that come after them so they cannot run in parallel.
2338TEST(OutOfMemory) {
2339  // It's not possible to read a snapshot into a heap with different dimensions.
2340  if (i::Snapshot::IsEnabled()) return;
2341  // Set heap limits.
2342  static const int K = 1024;
2343  v8::ResourceConstraints constraints;
2344  constraints.set_max_young_space_size(256 * K);
2345  constraints.set_max_old_space_size(4 * K * K);
2346  v8::SetResourceConstraints(&constraints);
2347
2348  // Execute a script that causes out of memory.
2349  v8::HandleScope scope;
2350  LocalContext context;
2351  v8::V8::IgnoreOutOfMemoryException();
2352  Local<Script> script =
2353      Script::Compile(String::New(js_code_causing_out_of_memory));
2354  Local<Value> result = script->Run();
2355
2356  // Check for out of memory state.
2357  CHECK(result.IsEmpty());
2358  CHECK(context->HasOutOfMemoryException());
2359}
2360
2361
2362v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2363  ApiTestFuzzer::Fuzz();
2364
2365  v8::HandleScope scope;
2366  LocalContext context;
2367  Local<Script> script =
2368      Script::Compile(String::New(js_code_causing_out_of_memory));
2369  Local<Value> result = script->Run();
2370
2371  // Check for out of memory state.
2372  CHECK(result.IsEmpty());
2373  CHECK(context->HasOutOfMemoryException());
2374
2375  return result;
2376}
2377
2378
2379TEST(OutOfMemoryNested) {
2380  // It's not possible to read a snapshot into a heap with different dimensions.
2381  if (i::Snapshot::IsEnabled()) return;
2382  // Set heap limits.
2383  static const int K = 1024;
2384  v8::ResourceConstraints constraints;
2385  constraints.set_max_young_space_size(256 * K);
2386  constraints.set_max_old_space_size(4 * K * K);
2387  v8::SetResourceConstraints(&constraints);
2388
2389  v8::HandleScope scope;
2390  Local<ObjectTemplate> templ = ObjectTemplate::New();
2391  templ->Set(v8_str("ProvokeOutOfMemory"),
2392             v8::FunctionTemplate::New(ProvokeOutOfMemory));
2393  LocalContext context(0, templ);
2394  v8::V8::IgnoreOutOfMemoryException();
2395  Local<Value> result = CompileRun(
2396    "var thrown = false;"
2397    "try {"
2398    "  ProvokeOutOfMemory();"
2399    "} catch (e) {"
2400    "  thrown = true;"
2401    "}");
2402  // Check for out of memory state.
2403  CHECK(result.IsEmpty());
2404  CHECK(context->HasOutOfMemoryException());
2405}
2406
2407
2408TEST(HugeConsStringOutOfMemory) {
2409  // It's not possible to read a snapshot into a heap with different dimensions.
2410  if (i::Snapshot::IsEnabled()) return;
2411  // Set heap limits.
2412  static const int K = 1024;
2413  v8::ResourceConstraints constraints;
2414  constraints.set_max_young_space_size(256 * K);
2415  constraints.set_max_old_space_size(2 * K * K);
2416  v8::SetResourceConstraints(&constraints);
2417
2418  // Execute a script that causes out of memory.
2419  v8::V8::IgnoreOutOfMemoryException();
2420
2421  v8::HandleScope scope;
2422  LocalContext context;
2423
2424  // Build huge string. This should fail with out of memory exception.
2425  Local<Value> result = CompileRun(
2426    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2427    "for (var i = 0; i < 22; i++) { str = str + str; }");
2428
2429  // Check for out of memory state.
2430  CHECK(result.IsEmpty());
2431  CHECK(context->HasOutOfMemoryException());
2432}
2433
2434
2435THREADED_TEST(ConstructCall) {
2436  v8::HandleScope scope;
2437  LocalContext context;
2438  CompileRun(
2439    "function Foo() {"
2440    "  var result = [];"
2441    "  for (var i = 0; i < arguments.length; i++) {"
2442    "    result.push(arguments[i]);"
2443    "  }"
2444    "  return result;"
2445    "}");
2446  Local<Function> Foo =
2447      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2448
2449  v8::Handle<Value>* args0 = NULL;
2450  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2451  CHECK_EQ(0, a0->Length());
2452
2453  v8::Handle<Value> args1[] = { v8_num(1.1) };
2454  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2455  CHECK_EQ(1, a1->Length());
2456  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2457
2458  v8::Handle<Value> args2[] = { v8_num(2.2),
2459                                v8_num(3.3) };
2460  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2461  CHECK_EQ(2, a2->Length());
2462  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2463  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2464
2465  v8::Handle<Value> args3[] = { v8_num(4.4),
2466                                v8_num(5.5),
2467                                v8_num(6.6) };
2468  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2469  CHECK_EQ(3, a3->Length());
2470  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2471  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2472  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2473
2474  v8::Handle<Value> args4[] = { v8_num(7.7),
2475                                v8_num(8.8),
2476                                v8_num(9.9),
2477                                v8_num(10.11) };
2478  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2479  CHECK_EQ(4, a4->Length());
2480  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2481  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2482  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2483  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2484}
2485
2486
2487static void CheckUncle(v8::TryCatch* try_catch) {
2488  CHECK(try_catch->HasCaught());
2489  String::AsciiValue str_value(try_catch->Exception());
2490  CHECK_EQ(*str_value, "uncle?");
2491  try_catch->Reset();
2492}
2493
2494
2495THREADED_TEST(ConversionNumber) {
2496  v8::HandleScope scope;
2497  LocalContext env;
2498  // Very large number.
2499  CompileRun("var obj = Math.pow(2,32) * 1237;");
2500  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2501  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2502  CHECK_EQ(0, obj->ToInt32()->Value());
2503  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2504  // Large number.
2505  CompileRun("var obj = -1234567890123;");
2506  obj = env->Global()->Get(v8_str("obj"));
2507  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2508  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2509  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2510  // Small positive integer.
2511  CompileRun("var obj = 42;");
2512  obj = env->Global()->Get(v8_str("obj"));
2513  CHECK_EQ(42.0, obj->ToNumber()->Value());
2514  CHECK_EQ(42, obj->ToInt32()->Value());
2515  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2516  // Negative integer.
2517  CompileRun("var obj = -37;");
2518  obj = env->Global()->Get(v8_str("obj"));
2519  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2520  CHECK_EQ(-37, obj->ToInt32()->Value());
2521  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2522  // Positive non-int32 integer.
2523  CompileRun("var obj = 0x81234567;");
2524  obj = env->Global()->Get(v8_str("obj"));
2525  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2526  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2527  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2528  // Fraction.
2529  CompileRun("var obj = 42.3;");
2530  obj = env->Global()->Get(v8_str("obj"));
2531  CHECK_EQ(42.3, obj->ToNumber()->Value());
2532  CHECK_EQ(42, obj->ToInt32()->Value());
2533  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2534  // Large negative fraction.
2535  CompileRun("var obj = -5726623061.75;");
2536  obj = env->Global()->Get(v8_str("obj"));
2537  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2538  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2539  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2540}
2541
2542
2543THREADED_TEST(isNumberType) {
2544  v8::HandleScope scope;
2545  LocalContext env;
2546  // Very large number.
2547  CompileRun("var obj = Math.pow(2,32) * 1237;");
2548  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2549  CHECK(!obj->IsInt32());
2550  CHECK(!obj->IsUint32());
2551  // Large negative number.
2552  CompileRun("var obj = -1234567890123;");
2553  obj = env->Global()->Get(v8_str("obj"));
2554  CHECK(!obj->IsInt32());
2555  CHECK(!obj->IsUint32());
2556  // Small positive integer.
2557  CompileRun("var obj = 42;");
2558  obj = env->Global()->Get(v8_str("obj"));
2559  CHECK(obj->IsInt32());
2560  CHECK(obj->IsUint32());
2561  // Negative integer.
2562  CompileRun("var obj = -37;");
2563  obj = env->Global()->Get(v8_str("obj"));
2564  CHECK(obj->IsInt32());
2565  CHECK(!obj->IsUint32());
2566  // Positive non-int32 integer.
2567  CompileRun("var obj = 0x81234567;");
2568  obj = env->Global()->Get(v8_str("obj"));
2569  CHECK(!obj->IsInt32());
2570  CHECK(obj->IsUint32());
2571  // Fraction.
2572  CompileRun("var obj = 42.3;");
2573  obj = env->Global()->Get(v8_str("obj"));
2574  CHECK(!obj->IsInt32());
2575  CHECK(!obj->IsUint32());
2576  // Large negative fraction.
2577  CompileRun("var obj = -5726623061.75;");
2578  obj = env->Global()->Get(v8_str("obj"));
2579  CHECK(!obj->IsInt32());
2580  CHECK(!obj->IsUint32());
2581}
2582
2583
2584THREADED_TEST(ConversionException) {
2585  v8::HandleScope scope;
2586  LocalContext env;
2587  CompileRun(
2588    "function TestClass() { };"
2589    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2590    "var obj = new TestClass();");
2591  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2592
2593  v8::TryCatch try_catch;
2594
2595  Local<Value> to_string_result = obj->ToString();
2596  CHECK(to_string_result.IsEmpty());
2597  CheckUncle(&try_catch);
2598
2599  Local<Value> to_number_result = obj->ToNumber();
2600  CHECK(to_number_result.IsEmpty());
2601  CheckUncle(&try_catch);
2602
2603  Local<Value> to_integer_result = obj->ToInteger();
2604  CHECK(to_integer_result.IsEmpty());
2605  CheckUncle(&try_catch);
2606
2607  Local<Value> to_uint32_result = obj->ToUint32();
2608  CHECK(to_uint32_result.IsEmpty());
2609  CheckUncle(&try_catch);
2610
2611  Local<Value> to_int32_result = obj->ToInt32();
2612  CHECK(to_int32_result.IsEmpty());
2613  CheckUncle(&try_catch);
2614
2615  Local<Value> to_object_result = v8::Undefined()->ToObject();
2616  CHECK(to_object_result.IsEmpty());
2617  CHECK(try_catch.HasCaught());
2618  try_catch.Reset();
2619
2620  int32_t int32_value = obj->Int32Value();
2621  CHECK_EQ(0, int32_value);
2622  CheckUncle(&try_catch);
2623
2624  uint32_t uint32_value = obj->Uint32Value();
2625  CHECK_EQ(0, uint32_value);
2626  CheckUncle(&try_catch);
2627
2628  double number_value = obj->NumberValue();
2629  CHECK_NE(0, IsNaN(number_value));
2630  CheckUncle(&try_catch);
2631
2632  int64_t integer_value = obj->IntegerValue();
2633  CHECK_EQ(0.0, static_cast<double>(integer_value));
2634  CheckUncle(&try_catch);
2635}
2636
2637
2638v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2639  ApiTestFuzzer::Fuzz();
2640  return v8::ThrowException(v8_str("konto"));
2641}
2642
2643
2644v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2645  if (args.Length() < 1) return v8::Boolean::New(false);
2646  v8::HandleScope scope;
2647  v8::TryCatch try_catch;
2648  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2649  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2650  return v8::Boolean::New(try_catch.HasCaught());
2651}
2652
2653
2654THREADED_TEST(APICatch) {
2655  v8::HandleScope scope;
2656  Local<ObjectTemplate> templ = ObjectTemplate::New();
2657  templ->Set(v8_str("ThrowFromC"),
2658             v8::FunctionTemplate::New(ThrowFromC));
2659  LocalContext context(0, templ);
2660  CompileRun(
2661    "var thrown = false;"
2662    "try {"
2663    "  ThrowFromC();"
2664    "} catch (e) {"
2665    "  thrown = true;"
2666    "}");
2667  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2668  CHECK(thrown->BooleanValue());
2669}
2670
2671
2672THREADED_TEST(APIThrowTryCatch) {
2673  v8::HandleScope scope;
2674  Local<ObjectTemplate> templ = ObjectTemplate::New();
2675  templ->Set(v8_str("ThrowFromC"),
2676             v8::FunctionTemplate::New(ThrowFromC));
2677  LocalContext context(0, templ);
2678  v8::TryCatch try_catch;
2679  CompileRun("ThrowFromC();");
2680  CHECK(try_catch.HasCaught());
2681}
2682
2683
2684// Test that a try-finally block doesn't shadow a try-catch block
2685// when setting up an external handler.
2686//
2687// BUG(271): Some of the exception propagation does not work on the
2688// ARM simulator because the simulator separates the C++ stack and the
2689// JS stack.  This test therefore fails on the simulator.  The test is
2690// not threaded to allow the threading tests to run on the simulator.
2691TEST(TryCatchInTryFinally) {
2692  v8::HandleScope scope;
2693  Local<ObjectTemplate> templ = ObjectTemplate::New();
2694  templ->Set(v8_str("CCatcher"),
2695             v8::FunctionTemplate::New(CCatcher));
2696  LocalContext context(0, templ);
2697  Local<Value> result = CompileRun("try {"
2698                                   "  try {"
2699                                   "    CCatcher('throw 7;');"
2700                                   "  } finally {"
2701                                   "  }"
2702                                   "} catch (e) {"
2703                                   "}");
2704  CHECK(result->IsTrue());
2705}
2706
2707
2708static void check_reference_error_message(
2709    v8::Handle<v8::Message> message,
2710    v8::Handle<v8::Value> data) {
2711  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2712  CHECK(message->Get()->Equals(v8_str(reference_error)));
2713}
2714
2715
2716static v8::Handle<Value> Fail(const v8::Arguments& args) {
2717  ApiTestFuzzer::Fuzz();
2718  CHECK(false);
2719  return v8::Undefined();
2720}
2721
2722
2723// Test that overwritten methods are not invoked on uncaught exception
2724// formatting. However, they are invoked when performing normal error
2725// string conversions.
2726TEST(APIThrowMessageOverwrittenToString) {
2727  v8::HandleScope scope;
2728  v8::V8::AddMessageListener(check_reference_error_message);
2729  Local<ObjectTemplate> templ = ObjectTemplate::New();
2730  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2731  LocalContext context(NULL, templ);
2732  CompileRun("asdf;");
2733  CompileRun("var limit = {};"
2734             "limit.valueOf = fail;"
2735             "Error.stackTraceLimit = limit;");
2736  CompileRun("asdf");
2737  CompileRun("Array.prototype.pop = fail;");
2738  CompileRun("Object.prototype.hasOwnProperty = fail;");
2739  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2740  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2741  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2742  CompileRun("ReferenceError.prototype.toString ="
2743             "  function() { return 'Whoops' }");
2744  CompileRun("asdf;");
2745  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2746  CompileRun("asdf;");
2747  CompileRun("ReferenceError.prototype.constructor = void 0;");
2748  CompileRun("asdf;");
2749  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2750  CompileRun("asdf;");
2751  CompileRun("ReferenceError.prototype = new Object();");
2752  CompileRun("asdf;");
2753  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2754  CHECK(string->Equals(v8_str("Whoops")));
2755  CompileRun("ReferenceError.prototype.constructor = new Object();"
2756             "ReferenceError.prototype.constructor.name = 1;"
2757             "Number.prototype.toString = function() { return 'Whoops'; };"
2758             "ReferenceError.prototype.toString = Object.prototype.toString;");
2759  CompileRun("asdf;");
2760  v8::V8::RemoveMessageListeners(check_message);
2761}
2762
2763
2764static void receive_message(v8::Handle<v8::Message> message,
2765                            v8::Handle<v8::Value> data) {
2766  message->Get();
2767  message_received = true;
2768}
2769
2770
2771TEST(APIThrowMessage) {
2772  message_received = false;
2773  v8::HandleScope scope;
2774  v8::V8::AddMessageListener(receive_message);
2775  Local<ObjectTemplate> templ = ObjectTemplate::New();
2776  templ->Set(v8_str("ThrowFromC"),
2777             v8::FunctionTemplate::New(ThrowFromC));
2778  LocalContext context(0, templ);
2779  CompileRun("ThrowFromC();");
2780  CHECK(message_received);
2781  v8::V8::RemoveMessageListeners(check_message);
2782}
2783
2784
2785TEST(APIThrowMessageAndVerboseTryCatch) {
2786  message_received = false;
2787  v8::HandleScope scope;
2788  v8::V8::AddMessageListener(receive_message);
2789  Local<ObjectTemplate> templ = ObjectTemplate::New();
2790  templ->Set(v8_str("ThrowFromC"),
2791             v8::FunctionTemplate::New(ThrowFromC));
2792  LocalContext context(0, templ);
2793  v8::TryCatch try_catch;
2794  try_catch.SetVerbose(true);
2795  Local<Value> result = CompileRun("ThrowFromC();");
2796  CHECK(try_catch.HasCaught());
2797  CHECK(result.IsEmpty());
2798  CHECK(message_received);
2799  v8::V8::RemoveMessageListeners(check_message);
2800}
2801
2802
2803TEST(APIStackOverflowAndVerboseTryCatch) {
2804  message_received = false;
2805  v8::HandleScope scope;
2806  v8::V8::AddMessageListener(receive_message);
2807  LocalContext context;
2808  v8::TryCatch try_catch;
2809  try_catch.SetVerbose(true);
2810  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2811  CHECK(try_catch.HasCaught());
2812  CHECK(result.IsEmpty());
2813  CHECK(message_received);
2814  v8::V8::RemoveMessageListeners(receive_message);
2815}
2816
2817
2818THREADED_TEST(ExternalScriptException) {
2819  v8::HandleScope scope;
2820  Local<ObjectTemplate> templ = ObjectTemplate::New();
2821  templ->Set(v8_str("ThrowFromC"),
2822             v8::FunctionTemplate::New(ThrowFromC));
2823  LocalContext context(0, templ);
2824
2825  v8::TryCatch try_catch;
2826  Local<Script> script
2827      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2828  Local<Value> result = script->Run();
2829  CHECK(result.IsEmpty());
2830  CHECK(try_catch.HasCaught());
2831  String::AsciiValue exception_value(try_catch.Exception());
2832  CHECK_EQ("konto", *exception_value);
2833}
2834
2835
2836
2837v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2838  ApiTestFuzzer::Fuzz();
2839  CHECK_EQ(4, args.Length());
2840  int count = args[0]->Int32Value();
2841  int cInterval = args[2]->Int32Value();
2842  if (count == 0) {
2843    return v8::ThrowException(v8_str("FromC"));
2844  } else {
2845    Local<v8::Object> global = Context::GetCurrent()->Global();
2846    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2847    v8::Handle<Value> argv[] = { v8_num(count - 1),
2848                                 args[1],
2849                                 args[2],
2850                                 args[3] };
2851    if (count % cInterval == 0) {
2852      v8::TryCatch try_catch;
2853      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2854      int expected = args[3]->Int32Value();
2855      if (try_catch.HasCaught()) {
2856        CHECK_EQ(expected, count);
2857        CHECK(result.IsEmpty());
2858        CHECK(!i::Isolate::Current()->has_scheduled_exception());
2859      } else {
2860        CHECK_NE(expected, count);
2861      }
2862      return result;
2863    } else {
2864      return fun.As<Function>()->Call(global, 4, argv);
2865    }
2866  }
2867}
2868
2869
2870v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2871  ApiTestFuzzer::Fuzz();
2872  CHECK_EQ(3, args.Length());
2873  bool equality = args[0]->BooleanValue();
2874  int count = args[1]->Int32Value();
2875  int expected = args[2]->Int32Value();
2876  if (equality) {
2877    CHECK_EQ(count, expected);
2878  } else {
2879    CHECK_NE(count, expected);
2880  }
2881  return v8::Undefined();
2882}
2883
2884
2885THREADED_TEST(EvalInTryFinally) {
2886  v8::HandleScope scope;
2887  LocalContext context;
2888  v8::TryCatch try_catch;
2889  CompileRun("(function() {"
2890             "  try {"
2891             "    eval('asldkf (*&^&*^');"
2892             "  } finally {"
2893             "    return;"
2894             "  }"
2895             "})()");
2896  CHECK(!try_catch.HasCaught());
2897}
2898
2899
2900// This test works by making a stack of alternating JavaScript and C
2901// activations.  These activations set up exception handlers with regular
2902// intervals, one interval for C activations and another for JavaScript
2903// activations.  When enough activations have been created an exception is
2904// thrown and we check that the right activation catches the exception and that
2905// no other activations do.  The right activation is always the topmost one with
2906// a handler, regardless of whether it is in JavaScript or C.
2907//
2908// The notation used to describe a test case looks like this:
2909//
2910//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2911//
2912// Each entry is an activation, either JS or C.  The index is the count at that
2913// level.  Stars identify activations with exception handlers, the @ identifies
2914// the exception handler that should catch the exception.
2915//
2916// BUG(271): Some of the exception propagation does not work on the
2917// ARM simulator because the simulator separates the C++ stack and the
2918// JS stack.  This test therefore fails on the simulator.  The test is
2919// not threaded to allow the threading tests to run on the simulator.
2920TEST(ExceptionOrder) {
2921  v8::HandleScope scope;
2922  Local<ObjectTemplate> templ = ObjectTemplate::New();
2923  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2924  templ->Set(v8_str("CThrowCountDown"),
2925             v8::FunctionTemplate::New(CThrowCountDown));
2926  LocalContext context(0, templ);
2927  CompileRun(
2928    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2929    "  if (count == 0) throw 'FromJS';"
2930    "  if (count % jsInterval == 0) {"
2931    "    try {"
2932    "      var value = CThrowCountDown(count - 1,"
2933    "                                  jsInterval,"
2934    "                                  cInterval,"
2935    "                                  expected);"
2936    "      check(false, count, expected);"
2937    "      return value;"
2938    "    } catch (e) {"
2939    "      check(true, count, expected);"
2940    "    }"
2941    "  } else {"
2942    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2943    "  }"
2944    "}");
2945  Local<Function> fun =
2946      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2947
2948  const int argc = 4;
2949  //                             count      jsInterval cInterval  expected
2950
2951  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2952  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2953  fun->Call(fun, argc, a0);
2954
2955  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2956  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2957  fun->Call(fun, argc, a1);
2958
2959  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2960  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2961  fun->Call(fun, argc, a2);
2962
2963  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2964  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2965  fun->Call(fun, argc, a3);
2966
2967  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2968  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2969  fun->Call(fun, argc, a4);
2970
2971  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2972  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2973  fun->Call(fun, argc, a5);
2974}
2975
2976
2977v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2978  ApiTestFuzzer::Fuzz();
2979  CHECK_EQ(1, args.Length());
2980  return v8::ThrowException(args[0]);
2981}
2982
2983
2984THREADED_TEST(ThrowValues) {
2985  v8::HandleScope scope;
2986  Local<ObjectTemplate> templ = ObjectTemplate::New();
2987  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2988  LocalContext context(0, templ);
2989  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2990    "function Run(obj) {"
2991    "  try {"
2992    "    Throw(obj);"
2993    "  } catch (e) {"
2994    "    return e;"
2995    "  }"
2996    "  return 'no exception';"
2997    "}"
2998    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2999  CHECK_EQ(5, result->Length());
3000  CHECK(result->Get(v8::Integer::New(0))->IsString());
3001  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3002  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3003  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3004  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3005  CHECK(result->Get(v8::Integer::New(3))->IsNull());
3006  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3007}
3008
3009
3010THREADED_TEST(CatchZero) {
3011  v8::HandleScope scope;
3012  LocalContext context;
3013  v8::TryCatch try_catch;
3014  CHECK(!try_catch.HasCaught());
3015  Script::Compile(v8_str("throw 10"))->Run();
3016  CHECK(try_catch.HasCaught());
3017  CHECK_EQ(10, try_catch.Exception()->Int32Value());
3018  try_catch.Reset();
3019  CHECK(!try_catch.HasCaught());
3020  Script::Compile(v8_str("throw 0"))->Run();
3021  CHECK(try_catch.HasCaught());
3022  CHECK_EQ(0, try_catch.Exception()->Int32Value());
3023}
3024
3025
3026THREADED_TEST(CatchExceptionFromWith) {
3027  v8::HandleScope scope;
3028  LocalContext context;
3029  v8::TryCatch try_catch;
3030  CHECK(!try_catch.HasCaught());
3031  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3032  CHECK(try_catch.HasCaught());
3033}
3034
3035
3036THREADED_TEST(TryCatchAndFinallyHidingException) {
3037  v8::HandleScope scope;
3038  LocalContext context;
3039  v8::TryCatch try_catch;
3040  CHECK(!try_catch.HasCaught());
3041  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3042  CompileRun("f({toString: function() { throw 42; }});");
3043  CHECK(!try_catch.HasCaught());
3044}
3045
3046
3047v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3048  v8::TryCatch try_catch;
3049  return v8::Undefined();
3050}
3051
3052
3053THREADED_TEST(TryCatchAndFinally) {
3054  v8::HandleScope scope;
3055  LocalContext context;
3056  context->Global()->Set(
3057      v8_str("native_with_try_catch"),
3058      v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3059  v8::TryCatch try_catch;
3060  CHECK(!try_catch.HasCaught());
3061  CompileRun(
3062      "try {\n"
3063      "  throw new Error('a');\n"
3064      "} finally {\n"
3065      "  native_with_try_catch();\n"
3066      "}\n");
3067  CHECK(try_catch.HasCaught());
3068}
3069
3070
3071THREADED_TEST(Equality) {
3072  v8::HandleScope scope;
3073  LocalContext context;
3074  // Check that equality works at all before relying on CHECK_EQ
3075  CHECK(v8_str("a")->Equals(v8_str("a")));
3076  CHECK(!v8_str("a")->Equals(v8_str("b")));
3077
3078  CHECK_EQ(v8_str("a"), v8_str("a"));
3079  CHECK_NE(v8_str("a"), v8_str("b"));
3080  CHECK_EQ(v8_num(1), v8_num(1));
3081  CHECK_EQ(v8_num(1.00), v8_num(1));
3082  CHECK_NE(v8_num(1), v8_num(2));
3083
3084  // Assume String is not symbol.
3085  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3086  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3087  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3088  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3089  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3090  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3091  Local<Value> not_a_number = v8_num(i::OS::nan_value());
3092  CHECK(!not_a_number->StrictEquals(not_a_number));
3093  CHECK(v8::False()->StrictEquals(v8::False()));
3094  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3095
3096  v8::Handle<v8::Object> obj = v8::Object::New();
3097  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3098  CHECK(alias->StrictEquals(obj));
3099  alias.Dispose();
3100}
3101
3102
3103THREADED_TEST(MultiRun) {
3104  v8::HandleScope scope;
3105  LocalContext context;
3106  Local<Script> script = Script::Compile(v8_str("x"));
3107  for (int i = 0; i < 10; i++)
3108    script->Run();
3109}
3110
3111
3112static v8::Handle<Value> GetXValue(Local<String> name,
3113                                   const AccessorInfo& info) {
3114  ApiTestFuzzer::Fuzz();
3115  CHECK_EQ(info.Data(), v8_str("donut"));
3116  CHECK_EQ(name, v8_str("x"));
3117  return name;
3118}
3119
3120
3121THREADED_TEST(SimplePropertyRead) {
3122  v8::HandleScope scope;
3123  Local<ObjectTemplate> templ = ObjectTemplate::New();
3124  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3125  LocalContext context;
3126  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3127  Local<Script> script = Script::Compile(v8_str("obj.x"));
3128  for (int i = 0; i < 10; i++) {
3129    Local<Value> result = script->Run();
3130    CHECK_EQ(result, v8_str("x"));
3131  }
3132}
3133
3134THREADED_TEST(DefinePropertyOnAPIAccessor) {
3135  v8::HandleScope scope;
3136  Local<ObjectTemplate> templ = ObjectTemplate::New();
3137  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3138  LocalContext context;
3139  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3140
3141  // Uses getOwnPropertyDescriptor to check the configurable status
3142  Local<Script> script_desc
3143    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3144                             "obj, 'x');"
3145                             "prop.configurable;"));
3146  Local<Value> result = script_desc->Run();
3147  CHECK_EQ(result->BooleanValue(), true);
3148
3149  // Redefine get - but still configurable
3150  Local<Script> script_define
3151    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3152                             "            configurable: true };"
3153                             "Object.defineProperty(obj, 'x', desc);"
3154                             "obj.x"));
3155  result = script_define->Run();
3156  CHECK_EQ(result, v8_num(42));
3157
3158  // Check that the accessor is still configurable
3159  result = script_desc->Run();
3160  CHECK_EQ(result->BooleanValue(), true);
3161
3162  // Redefine to a non-configurable
3163  script_define
3164    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3165                             "             configurable: false };"
3166                             "Object.defineProperty(obj, 'x', desc);"
3167                             "obj.x"));
3168  result = script_define->Run();
3169  CHECK_EQ(result, v8_num(43));
3170  result = script_desc->Run();
3171  CHECK_EQ(result->BooleanValue(), false);
3172
3173  // Make sure that it is not possible to redefine again
3174  v8::TryCatch try_catch;
3175  result = script_define->Run();
3176  CHECK(try_catch.HasCaught());
3177  String::AsciiValue exception_value(try_catch.Exception());
3178  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3179}
3180
3181THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3182  v8::HandleScope scope;
3183  Local<ObjectTemplate> templ = ObjectTemplate::New();
3184  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3185  LocalContext context;
3186  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3187
3188  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3189                                    "Object.getOwnPropertyDescriptor( "
3190                                    "obj, 'x');"
3191                                    "prop.configurable;"));
3192  Local<Value> result = script_desc->Run();
3193  CHECK_EQ(result->BooleanValue(), true);
3194
3195  Local<Script> script_define =
3196    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3197                           "            configurable: true };"
3198                           "Object.defineProperty(obj, 'x', desc);"
3199                           "obj.x"));
3200  result = script_define->Run();
3201  CHECK_EQ(result, v8_num(42));
3202
3203
3204  result = script_desc->Run();
3205  CHECK_EQ(result->BooleanValue(), true);
3206
3207
3208  script_define =
3209    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3210                           "            configurable: false };"
3211                           "Object.defineProperty(obj, 'x', desc);"
3212                           "obj.x"));
3213  result = script_define->Run();
3214  CHECK_EQ(result, v8_num(43));
3215  result = script_desc->Run();
3216
3217  CHECK_EQ(result->BooleanValue(), false);
3218
3219  v8::TryCatch try_catch;
3220  result = script_define->Run();
3221  CHECK(try_catch.HasCaught());
3222  String::AsciiValue exception_value(try_catch.Exception());
3223  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3224}
3225
3226
3227static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3228                                                char const* name) {
3229  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3230}
3231
3232
3233THREADED_TEST(DefineAPIAccessorOnObject) {
3234  v8::HandleScope scope;
3235  Local<ObjectTemplate> templ = ObjectTemplate::New();
3236  LocalContext context;
3237
3238  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3239  CompileRun("var obj2 = {};");
3240
3241  CHECK(CompileRun("obj1.x")->IsUndefined());
3242  CHECK(CompileRun("obj2.x")->IsUndefined());
3243
3244  CHECK(GetGlobalProperty(&context, "obj1")->
3245      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3246
3247  ExpectString("obj1.x", "x");
3248  CHECK(CompileRun("obj2.x")->IsUndefined());
3249
3250  CHECK(GetGlobalProperty(&context, "obj2")->
3251      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3252
3253  ExpectString("obj1.x", "x");
3254  ExpectString("obj2.x", "x");
3255
3256  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3257  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3258
3259  CompileRun("Object.defineProperty(obj1, 'x',"
3260             "{ get: function() { return 'y'; }, configurable: true })");
3261
3262  ExpectString("obj1.x", "y");
3263  ExpectString("obj2.x", "x");
3264
3265  CompileRun("Object.defineProperty(obj2, 'x',"
3266             "{ get: function() { return 'y'; }, configurable: true })");
3267
3268  ExpectString("obj1.x", "y");
3269  ExpectString("obj2.x", "y");
3270
3271  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3272  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3273
3274  CHECK(GetGlobalProperty(&context, "obj1")->
3275      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3276  CHECK(GetGlobalProperty(&context, "obj2")->
3277      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3278
3279  ExpectString("obj1.x", "x");
3280  ExpectString("obj2.x", "x");
3281
3282  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3283  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3284
3285  // Define getters/setters, but now make them not configurable.
3286  CompileRun("Object.defineProperty(obj1, 'x',"
3287             "{ get: function() { return 'z'; }, configurable: false })");
3288  CompileRun("Object.defineProperty(obj2, 'x',"
3289             "{ get: function() { return 'z'; }, configurable: false })");
3290
3291  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3292  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3293
3294  ExpectString("obj1.x", "z");
3295  ExpectString("obj2.x", "z");
3296
3297  CHECK(!GetGlobalProperty(&context, "obj1")->
3298      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3299  CHECK(!GetGlobalProperty(&context, "obj2")->
3300      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3301
3302  ExpectString("obj1.x", "z");
3303  ExpectString("obj2.x", "z");
3304}
3305
3306
3307THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3308  v8::HandleScope scope;
3309  Local<ObjectTemplate> templ = ObjectTemplate::New();
3310  LocalContext context;
3311
3312  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3313  CompileRun("var obj2 = {};");
3314
3315  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3316        v8_str("x"),
3317        GetXValue, NULL,
3318        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3319  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3320        v8_str("x"),
3321        GetXValue, NULL,
3322        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3323
3324  ExpectString("obj1.x", "x");
3325  ExpectString("obj2.x", "x");
3326
3327  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3328  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3329
3330  CHECK(!GetGlobalProperty(&context, "obj1")->
3331      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3332  CHECK(!GetGlobalProperty(&context, "obj2")->
3333      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3334
3335  {
3336    v8::TryCatch try_catch;
3337    CompileRun("Object.defineProperty(obj1, 'x',"
3338        "{get: function() { return 'func'; }})");
3339    CHECK(try_catch.HasCaught());
3340    String::AsciiValue exception_value(try_catch.Exception());
3341    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3342  }
3343  {
3344    v8::TryCatch try_catch;
3345    CompileRun("Object.defineProperty(obj2, 'x',"
3346        "{get: function() { return 'func'; }})");
3347    CHECK(try_catch.HasCaught());
3348    String::AsciiValue exception_value(try_catch.Exception());
3349    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3350  }
3351}
3352
3353
3354static v8::Handle<Value> Get239Value(Local<String> name,
3355                                     const AccessorInfo& info) {
3356  ApiTestFuzzer::Fuzz();
3357  CHECK_EQ(info.Data(), v8_str("donut"));
3358  CHECK_EQ(name, v8_str("239"));
3359  return name;
3360}
3361
3362
3363THREADED_TEST(ElementAPIAccessor) {
3364  v8::HandleScope scope;
3365  Local<ObjectTemplate> templ = ObjectTemplate::New();
3366  LocalContext context;
3367
3368  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3369  CompileRun("var obj2 = {};");
3370
3371  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3372        v8_str("239"),
3373        Get239Value, NULL,
3374        v8_str("donut")));
3375  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3376        v8_str("239"),
3377        Get239Value, NULL,
3378        v8_str("donut")));
3379
3380  ExpectString("obj1[239]", "239");
3381  ExpectString("obj2[239]", "239");
3382  ExpectString("obj1['239']", "239");
3383  ExpectString("obj2['239']", "239");
3384}
3385
3386
3387v8::Persistent<Value> xValue;
3388
3389
3390static void SetXValue(Local<String> name,
3391                      Local<Value> value,
3392                      const AccessorInfo& info) {
3393  CHECK_EQ(value, v8_num(4));
3394  CHECK_EQ(info.Data(), v8_str("donut"));
3395  CHECK_EQ(name, v8_str("x"));
3396  CHECK(xValue.IsEmpty());
3397  xValue = v8::Persistent<Value>::New(value);
3398}
3399
3400
3401THREADED_TEST(SimplePropertyWrite) {
3402  v8::HandleScope scope;
3403  Local<ObjectTemplate> templ = ObjectTemplate::New();
3404  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3405  LocalContext context;
3406  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3407  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3408  for (int i = 0; i < 10; i++) {
3409    CHECK(xValue.IsEmpty());
3410    script->Run();
3411    CHECK_EQ(v8_num(4), xValue);
3412    xValue.Dispose();
3413    xValue = v8::Persistent<Value>();
3414  }
3415}
3416
3417
3418static v8::Handle<Value> XPropertyGetter(Local<String> property,
3419                                         const AccessorInfo& info) {
3420  ApiTestFuzzer::Fuzz();
3421  CHECK(info.Data()->IsUndefined());
3422  return property;
3423}
3424
3425
3426THREADED_TEST(NamedInterceptorPropertyRead) {
3427  v8::HandleScope scope;
3428  Local<ObjectTemplate> templ = ObjectTemplate::New();
3429  templ->SetNamedPropertyHandler(XPropertyGetter);
3430  LocalContext context;
3431  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3432  Local<Script> script = Script::Compile(v8_str("obj.x"));
3433  for (int i = 0; i < 10; i++) {
3434    Local<Value> result = script->Run();
3435    CHECK_EQ(result, v8_str("x"));
3436  }
3437}
3438
3439
3440THREADED_TEST(NamedInterceptorDictionaryIC) {
3441  v8::HandleScope scope;
3442  Local<ObjectTemplate> templ = ObjectTemplate::New();
3443  templ->SetNamedPropertyHandler(XPropertyGetter);
3444  LocalContext context;
3445  // Create an object with a named interceptor.
3446  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3447  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3448  for (int i = 0; i < 10; i++) {
3449    Local<Value> result = script->Run();
3450    CHECK_EQ(result, v8_str("x"));
3451  }
3452  // Create a slow case object and a function accessing a property in
3453  // that slow case object (with dictionary probing in generated
3454  // code). Then force object with a named interceptor into slow-case,
3455  // pass it to the function, and check that the interceptor is called
3456  // instead of accessing the local property.
3457  Local<Value> result =
3458      CompileRun("function get_x(o) { return o.x; };"
3459                 "var obj = { x : 42, y : 0 };"
3460                 "delete obj.y;"
3461                 "for (var i = 0; i < 10; i++) get_x(obj);"
3462                 "interceptor_obj.x = 42;"
3463                 "interceptor_obj.y = 10;"
3464                 "delete interceptor_obj.y;"
3465                 "get_x(interceptor_obj)");
3466  CHECK_EQ(result, v8_str("x"));
3467}
3468
3469
3470THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3471  v8::HandleScope scope;
3472
3473  v8::Persistent<Context> context1 = Context::New();
3474
3475  context1->Enter();
3476  Local<ObjectTemplate> templ = ObjectTemplate::New();
3477  templ->SetNamedPropertyHandler(XPropertyGetter);
3478  // Create an object with a named interceptor.
3479  v8::Local<v8::Object> object = templ->NewInstance();
3480  context1->Global()->Set(v8_str("interceptor_obj"), object);
3481
3482  // Force the object into the slow case.
3483  CompileRun("interceptor_obj.y = 0;"
3484             "delete interceptor_obj.y;");
3485  context1->Exit();
3486
3487  {
3488    // Introduce the object into a different context.
3489    // Repeat named loads to exercise ICs.
3490    LocalContext context2;
3491    context2->Global()->Set(v8_str("interceptor_obj"), object);
3492    Local<Value> result =
3493      CompileRun("function get_x(o) { return o.x; }"
3494                 "interceptor_obj.x = 42;"
3495                 "for (var i=0; i != 10; i++) {"
3496                 "  get_x(interceptor_obj);"
3497                 "}"
3498                 "get_x(interceptor_obj)");
3499    // Check that the interceptor was actually invoked.
3500    CHECK_EQ(result, v8_str("x"));
3501  }
3502
3503  // Return to the original context and force some object to the slow case
3504  // to cause the NormalizedMapCache to verify.
3505  context1->Enter();
3506  CompileRun("var obj = { x : 0 }; delete obj.x;");
3507  context1->Exit();
3508
3509  context1.Dispose();
3510}
3511
3512
3513static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3514                                               const AccessorInfo& info) {
3515  // Set x on the prototype object and do not handle the get request.
3516  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3517  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3518  return v8::Handle<Value>();
3519}
3520
3521
3522// This is a regression test for http://crbug.com/20104. Map
3523// transitions should not interfere with post interceptor lookup.
3524THREADED_TEST(NamedInterceptorMapTransitionRead) {
3525  v8::HandleScope scope;
3526  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3527  Local<v8::ObjectTemplate> instance_template
3528      = function_template->InstanceTemplate();
3529  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3530  LocalContext context;
3531  context->Global()->Set(v8_str("F"), function_template->GetFunction());
3532  // Create an instance of F and introduce a map transition for x.
3533  CompileRun("var o = new F(); o.x = 23;");
3534  // Create an instance of F and invoke the getter. The result should be 23.
3535  Local<Value> result = CompileRun("o = new F(); o.x");
3536  CHECK_EQ(result->Int32Value(), 23);
3537}
3538
3539
3540static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3541                                               const AccessorInfo& info) {
3542  ApiTestFuzzer::Fuzz();
3543  if (index == 37) {
3544    return v8::Handle<Value>(v8_num(625));
3545  }
3546  return v8::Handle<Value>();
3547}
3548
3549
3550static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3551                                               Local<Value> value,
3552                                               const AccessorInfo& info) {
3553  ApiTestFuzzer::Fuzz();
3554  if (index == 39) {
3555    return value;
3556  }
3557  return v8::Handle<Value>();
3558}
3559
3560
3561THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3562  v8::HandleScope scope;
3563  Local<ObjectTemplate> templ = ObjectTemplate::New();
3564  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3565                                   IndexedPropertySetter);
3566  LocalContext context;
3567  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3568  Local<Script> getter_script = Script::Compile(v8_str(
3569      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3570  Local<Script> setter_script = Script::Compile(v8_str(
3571      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3572      "obj[17] = 23;"
3573      "obj.foo;"));
3574  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3575      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3576      "obj[39] = 47;"
3577      "obj.foo;"));  // This setter should not run, due to the interceptor.
3578  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3579      "obj[37];"));
3580  Local<Value> result = getter_script->Run();
3581  CHECK_EQ(v8_num(5), result);
3582  result = setter_script->Run();
3583  CHECK_EQ(v8_num(23), result);
3584  result = interceptor_setter_script->Run();
3585  CHECK_EQ(v8_num(23), result);
3586  result = interceptor_getter_script->Run();
3587  CHECK_EQ(v8_num(625), result);
3588}
3589
3590
3591static v8::Handle<Value> IdentityIndexedPropertyGetter(
3592    uint32_t index,
3593    const AccessorInfo& info) {
3594  return v8::Integer::NewFromUnsigned(index);
3595}
3596
3597
3598THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3599  v8::HandleScope scope;
3600  Local<ObjectTemplate> templ = ObjectTemplate::New();
3601  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3602
3603  LocalContext context;
3604  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3605
3606  // Check fast object case.
3607  const char* fast_case_code =
3608      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3609  ExpectString(fast_case_code, "0");
3610
3611  // Check slow case.
3612  const char* slow_case_code =
3613      "obj.x = 1; delete obj.x;"
3614      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3615  ExpectString(slow_case_code, "1");
3616}
3617
3618
3619THREADED_TEST(IndexedInterceptorWithNoSetter) {
3620  v8::HandleScope scope;
3621  Local<ObjectTemplate> templ = ObjectTemplate::New();
3622  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3623
3624  LocalContext context;
3625  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3626
3627  const char* code =
3628      "try {"
3629      "  obj[0] = 239;"
3630      "  for (var i = 0; i < 100; i++) {"
3631      "    var v = obj[0];"
3632      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3633      "  }"
3634      "  'PASSED'"
3635      "} catch(e) {"
3636      "  e"
3637      "}";
3638  ExpectString(code, "PASSED");
3639}
3640
3641
3642THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3643  v8::HandleScope scope;
3644  Local<ObjectTemplate> templ = ObjectTemplate::New();
3645  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3646
3647  LocalContext context;
3648  Local<v8::Object> obj = templ->NewInstance();
3649  obj->TurnOnAccessCheck();
3650  context->Global()->Set(v8_str("obj"), obj);
3651
3652  const char* code =
3653      "try {"
3654      "  for (var i = 0; i < 100; i++) {"
3655      "    var v = obj[0];"
3656      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3657      "  }"
3658      "  'PASSED'"
3659      "} catch(e) {"
3660      "  e"
3661      "}";
3662  ExpectString(code, "PASSED");
3663}
3664
3665
3666THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3667  i::FLAG_allow_natives_syntax = true;
3668  v8::HandleScope scope;
3669  Local<ObjectTemplate> templ = ObjectTemplate::New();
3670  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3671
3672  LocalContext context;
3673  Local<v8::Object> obj = templ->NewInstance();
3674  context->Global()->Set(v8_str("obj"), obj);
3675
3676  const char* code =
3677      "try {"
3678      "  for (var i = 0; i < 100; i++) {"
3679      "    var expected = i;"
3680      "    if (i == 5) {"
3681      "      %EnableAccessChecks(obj);"
3682      "      expected = undefined;"
3683      "    }"
3684      "    var v = obj[i];"
3685      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3686      "    if (i == 5) %DisableAccessChecks(obj);"
3687      "  }"
3688      "  'PASSED'"
3689      "} catch(e) {"
3690      "  e"
3691      "}";
3692  ExpectString(code, "PASSED");
3693}
3694
3695
3696THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3697  v8::HandleScope scope;
3698  Local<ObjectTemplate> templ = ObjectTemplate::New();
3699  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3700
3701  LocalContext context;
3702  Local<v8::Object> obj = templ->NewInstance();
3703  context->Global()->Set(v8_str("obj"), obj);
3704
3705  const char* code =
3706      "try {"
3707      "  for (var i = 0; i < 100; i++) {"
3708      "    var v = obj[i];"
3709      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3710      "  }"
3711      "  'PASSED'"
3712      "} catch(e) {"
3713      "  e"
3714      "}";
3715  ExpectString(code, "PASSED");
3716}
3717
3718
3719THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3720  v8::HandleScope scope;
3721  Local<ObjectTemplate> templ = ObjectTemplate::New();
3722  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3723
3724  LocalContext context;
3725  Local<v8::Object> obj = templ->NewInstance();
3726  context->Global()->Set(v8_str("obj"), obj);
3727
3728  const char* code =
3729      "try {"
3730      "  for (var i = 0; i < 100; i++) {"
3731      "    var expected = i;"
3732      "    var key = i;"
3733      "    if (i == 25) {"
3734      "       key = -1;"
3735      "       expected = undefined;"
3736      "    }"
3737      "    if (i == 50) {"
3738      "       /* probe minimal Smi number on 32-bit platforms */"
3739      "       key = -(1 << 30);"
3740      "       expected = undefined;"
3741      "    }"
3742      "    if (i == 75) {"
3743      "       /* probe minimal Smi number on 64-bit platforms */"
3744      "       key = 1 << 31;"
3745      "       expected = undefined;"
3746      "    }"
3747      "    var v = obj[key];"
3748      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3749      "  }"
3750      "  'PASSED'"
3751      "} catch(e) {"
3752      "  e"
3753      "}";
3754  ExpectString(code, "PASSED");
3755}
3756
3757
3758THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3759  v8::HandleScope scope;
3760  Local<ObjectTemplate> templ = ObjectTemplate::New();
3761  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3762
3763  LocalContext context;
3764  Local<v8::Object> obj = templ->NewInstance();
3765  context->Global()->Set(v8_str("obj"), obj);
3766
3767  const char* code =
3768      "try {"
3769      "  for (var i = 0; i < 100; i++) {"
3770      "    var expected = i;"
3771      "    var key = i;"
3772      "    if (i == 50) {"
3773      "       key = 'foobar';"
3774      "       expected = undefined;"
3775      "    }"
3776      "    var v = obj[key];"
3777      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3778      "  }"
3779      "  'PASSED'"
3780      "} catch(e) {"
3781      "  e"
3782      "}";
3783  ExpectString(code, "PASSED");
3784}
3785
3786
3787THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3788  v8::HandleScope scope;
3789  Local<ObjectTemplate> templ = ObjectTemplate::New();
3790  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3791
3792  LocalContext context;
3793  Local<v8::Object> obj = templ->NewInstance();
3794  context->Global()->Set(v8_str("obj"), obj);
3795
3796  const char* code =
3797      "var original = obj;"
3798      "try {"
3799      "  for (var i = 0; i < 100; i++) {"
3800      "    var expected = i;"
3801      "    if (i == 50) {"
3802      "       obj = {50: 'foobar'};"
3803      "       expected = 'foobar';"
3804      "    }"
3805      "    var v = obj[i];"
3806      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3807      "    if (i == 50) obj = original;"
3808      "  }"
3809      "  'PASSED'"
3810      "} catch(e) {"
3811      "  e"
3812      "}";
3813  ExpectString(code, "PASSED");
3814}
3815
3816
3817THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3818  v8::HandleScope scope;
3819  Local<ObjectTemplate> templ = ObjectTemplate::New();
3820  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3821
3822  LocalContext context;
3823  Local<v8::Object> obj = templ->NewInstance();
3824  context->Global()->Set(v8_str("obj"), obj);
3825
3826  const char* code =
3827      "var original = obj;"
3828      "try {"
3829      "  for (var i = 0; i < 100; i++) {"
3830      "    var expected = i;"
3831      "    if (i == 5) {"
3832      "       obj = 239;"
3833      "       expected = undefined;"
3834      "    }"
3835      "    var v = obj[i];"
3836      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3837      "    if (i == 5) obj = original;"
3838      "  }"
3839      "  'PASSED'"
3840      "} catch(e) {"
3841      "  e"
3842      "}";
3843  ExpectString(code, "PASSED");
3844}
3845
3846
3847THREADED_TEST(IndexedInterceptorOnProto) {
3848  v8::HandleScope scope;
3849  Local<ObjectTemplate> templ = ObjectTemplate::New();
3850  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3851
3852  LocalContext context;
3853  Local<v8::Object> obj = templ->NewInstance();
3854  context->Global()->Set(v8_str("obj"), obj);
3855
3856  const char* code =
3857      "var o = {__proto__: obj};"
3858      "try {"
3859      "  for (var i = 0; i < 100; i++) {"
3860      "    var v = o[i];"
3861      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3862      "  }"
3863      "  'PASSED'"
3864      "} catch(e) {"
3865      "  e"
3866      "}";
3867  ExpectString(code, "PASSED");
3868}
3869
3870
3871THREADED_TEST(MultiContexts) {
3872  v8::HandleScope scope;
3873  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3874  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3875
3876  Local<String> password = v8_str("Password");
3877
3878  // Create an environment
3879  LocalContext context0(0, templ);
3880  context0->SetSecurityToken(password);
3881  v8::Handle<v8::Object> global0 = context0->Global();
3882  global0->Set(v8_str("custom"), v8_num(1234));
3883  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3884
3885  // Create an independent environment
3886  LocalContext context1(0, templ);
3887  context1->SetSecurityToken(password);
3888  v8::Handle<v8::Object> global1 = context1->Global();
3889  global1->Set(v8_str("custom"), v8_num(1234));
3890  CHECK_NE(global0, global1);
3891  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3892  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3893
3894  // Now create a new context with the old global
3895  LocalContext context2(0, templ, global1);
3896  context2->SetSecurityToken(password);
3897  v8::Handle<v8::Object> global2 = context2->Global();
3898  CHECK_EQ(global1, global2);
3899  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3900  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3901}
3902
3903
3904THREADED_TEST(FunctionPrototypeAcrossContexts) {
3905  // Make sure that functions created by cloning boilerplates cannot
3906  // communicate through their __proto__ field.
3907
3908  v8::HandleScope scope;
3909
3910  LocalContext env0;
3911  v8::Handle<v8::Object> global0 =
3912      env0->Global();
3913  v8::Handle<v8::Object> object0 =
3914      global0->Get(v8_str("Object")).As<v8::Object>();
3915  v8::Handle<v8::Object> tostring0 =
3916      object0->Get(v8_str("toString")).As<v8::Object>();
3917  v8::Handle<v8::Object> proto0 =
3918      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3919  proto0->Set(v8_str("custom"), v8_num(1234));
3920
3921  LocalContext env1;
3922  v8::Handle<v8::Object> global1 =
3923      env1->Global();
3924  v8::Handle<v8::Object> object1 =
3925      global1->Get(v8_str("Object")).As<v8::Object>();
3926  v8::Handle<v8::Object> tostring1 =
3927      object1->Get(v8_str("toString")).As<v8::Object>();
3928  v8::Handle<v8::Object> proto1 =
3929      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3930  CHECK(!proto1->Has(v8_str("custom")));
3931}
3932
3933
3934THREADED_TEST(Regress892105) {
3935  // Make sure that object and array literals created by cloning
3936  // boilerplates cannot communicate through their __proto__
3937  // field. This is rather difficult to check, but we try to add stuff
3938  // to Object.prototype and Array.prototype and create a new
3939  // environment. This should succeed.
3940
3941  v8::HandleScope scope;
3942
3943  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3944                                "Array.prototype.arr = 4567;"
3945                                "8901");
3946
3947  LocalContext env0;
3948  Local<Script> script0 = Script::Compile(source);
3949  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3950
3951  LocalContext env1;
3952  Local<Script> script1 = Script::Compile(source);
3953  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3954}
3955
3956
3957THREADED_TEST(UndetectableObject) {
3958  v8::HandleScope scope;
3959  LocalContext env;
3960
3961  Local<v8::FunctionTemplate> desc =
3962      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3963  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3964
3965  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3966  env->Global()->Set(v8_str("undetectable"), obj);
3967
3968  ExpectString("undetectable.toString()", "[object Object]");
3969  ExpectString("typeof undetectable", "undefined");
3970  ExpectString("typeof(undetectable)", "undefined");
3971  ExpectBoolean("typeof undetectable == 'undefined'", true);
3972  ExpectBoolean("typeof undetectable == 'object'", false);
3973  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3974  ExpectBoolean("!undetectable", true);
3975
3976  ExpectObject("true&&undetectable", obj);
3977  ExpectBoolean("false&&undetectable", false);
3978  ExpectBoolean("true||undetectable", true);
3979  ExpectObject("false||undetectable", obj);
3980
3981  ExpectObject("undetectable&&true", obj);
3982  ExpectObject("undetectable&&false", obj);
3983  ExpectBoolean("undetectable||true", true);
3984  ExpectBoolean("undetectable||false", false);
3985
3986  ExpectBoolean("undetectable==null", true);
3987  ExpectBoolean("null==undetectable", true);
3988  ExpectBoolean("undetectable==undefined", true);
3989  ExpectBoolean("undefined==undetectable", true);
3990  ExpectBoolean("undetectable==undetectable", true);
3991
3992
3993  ExpectBoolean("undetectable===null", false);
3994  ExpectBoolean("null===undetectable", false);
3995  ExpectBoolean("undetectable===undefined", false);
3996  ExpectBoolean("undefined===undetectable", false);
3997  ExpectBoolean("undetectable===undetectable", true);
3998}
3999
4000
4001THREADED_TEST(VoidLiteral) {
4002  v8::HandleScope scope;
4003  LocalContext env;
4004
4005  Local<v8::FunctionTemplate> desc =
4006      v8::FunctionTemplate::New(0, v8::Handle<Value>());
4007  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4008
4009  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4010  env->Global()->Set(v8_str("undetectable"), obj);
4011
4012  ExpectBoolean("undefined == void 0", true);
4013  ExpectBoolean("undetectable == void 0", true);
4014  ExpectBoolean("null == void 0", true);
4015  ExpectBoolean("undefined === void 0", true);
4016  ExpectBoolean("undetectable === void 0", false);
4017  ExpectBoolean("null === void 0", false);
4018
4019  ExpectBoolean("void 0 == undefined", true);
4020  ExpectBoolean("void 0 == undetectable", true);
4021  ExpectBoolean("void 0 == null", true);
4022  ExpectBoolean("void 0 === undefined", true);
4023  ExpectBoolean("void 0 === undetectable", false);
4024  ExpectBoolean("void 0 === null", false);
4025
4026  ExpectString("(function() {"
4027               "  try {"
4028               "    return x === void 0;"
4029               "  } catch(e) {"
4030               "    return e.toString();"
4031               "  }"
4032               "})()",
4033               "ReferenceError: x is not defined");
4034  ExpectString("(function() {"
4035               "  try {"
4036               "    return void 0 === x;"
4037               "  } catch(e) {"
4038               "    return e.toString();"
4039               "  }"
4040               "})()",
4041               "ReferenceError: x is not defined");
4042}
4043
4044
4045THREADED_TEST(ExtensibleOnUndetectable) {
4046  v8::HandleScope scope;
4047  LocalContext env;
4048
4049  Local<v8::FunctionTemplate> desc =
4050      v8::FunctionTemplate::New(0, v8::Handle<Value>());
4051  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4052
4053  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4054  env->Global()->Set(v8_str("undetectable"), obj);
4055
4056  Local<String> source = v8_str("undetectable.x = 42;"
4057                                "undetectable.x");
4058
4059  Local<Script> script = Script::Compile(source);
4060
4061  CHECK_EQ(v8::Integer::New(42), script->Run());
4062
4063  ExpectBoolean("Object.isExtensible(undetectable)", true);
4064
4065  source = v8_str("Object.preventExtensions(undetectable);");
4066  script = Script::Compile(source);
4067  script->Run();
4068  ExpectBoolean("Object.isExtensible(undetectable)", false);
4069
4070  source = v8_str("undetectable.y = 2000;");
4071  script = Script::Compile(source);
4072  Local<Value> result = script->Run();
4073  ExpectBoolean("undetectable.y == undefined", true);
4074}
4075
4076
4077
4078THREADED_TEST(UndetectableString) {
4079  v8::HandleScope scope;
4080  LocalContext env;
4081
4082  Local<String> obj = String::NewUndetectable("foo");
4083  env->Global()->Set(v8_str("undetectable"), obj);
4084
4085  ExpectString("undetectable", "foo");
4086  ExpectString("typeof undetectable", "undefined");
4087  ExpectString("typeof(undetectable)", "undefined");
4088  ExpectBoolean("typeof undetectable == 'undefined'", true);
4089  ExpectBoolean("typeof undetectable == 'string'", false);
4090  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4091  ExpectBoolean("!undetectable", true);
4092
4093  ExpectObject("true&&undetectable", obj);
4094  ExpectBoolean("false&&undetectable", false);
4095  ExpectBoolean("true||undetectable", true);
4096  ExpectObject("false||undetectable", obj);
4097
4098  ExpectObject("undetectable&&true", obj);
4099  ExpectObject("undetectable&&false", obj);
4100  ExpectBoolean("undetectable||true", true);
4101  ExpectBoolean("undetectable||false", false);
4102
4103  ExpectBoolean("undetectable==null", true);
4104  ExpectBoolean("null==undetectable", true);
4105  ExpectBoolean("undetectable==undefined", true);
4106  ExpectBoolean("undefined==undetectable", true);
4107  ExpectBoolean("undetectable==undetectable", true);
4108
4109
4110  ExpectBoolean("undetectable===null", false);
4111  ExpectBoolean("null===undetectable", false);
4112  ExpectBoolean("undetectable===undefined", false);
4113  ExpectBoolean("undefined===undetectable", false);
4114  ExpectBoolean("undetectable===undetectable", true);
4115}
4116
4117
4118TEST(UndetectableOptimized) {
4119  i::FLAG_allow_natives_syntax = true;
4120  v8::HandleScope scope;
4121  LocalContext env;
4122
4123  Local<String> obj = String::NewUndetectable("foo");
4124  env->Global()->Set(v8_str("undetectable"), obj);
4125  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4126
4127  ExpectString(
4128      "function testBranch() {"
4129      "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
4130      "  if (%_IsUndetectableObject(detectable)) throw 2;"
4131      "}\n"
4132      "function testBool() {"
4133      "  var b1 = !%_IsUndetectableObject(undetectable);"
4134      "  var b2 = %_IsUndetectableObject(detectable);"
4135      "  if (b1) throw 3;"
4136      "  if (b2) throw 4;"
4137      "  return b1 == b2;"
4138      "}\n"
4139      "%OptimizeFunctionOnNextCall(testBranch);"
4140      "%OptimizeFunctionOnNextCall(testBool);"
4141      "for (var i = 0; i < 10; i++) {"
4142      "  testBranch();"
4143      "  testBool();"
4144      "}\n"
4145      "\"PASS\"",
4146      "PASS");
4147}
4148
4149
4150template <typename T> static void USE(T) { }
4151
4152
4153// This test is not intended to be run, just type checked.
4154static void PersistentHandles() {
4155  USE(PersistentHandles);
4156  Local<String> str = v8_str("foo");
4157  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4158  USE(p_str);
4159  Local<Script> scr = Script::Compile(v8_str(""));
4160  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4161  USE(p_scr);
4162  Local<ObjectTemplate> templ = ObjectTemplate::New();
4163  v8::Persistent<ObjectTemplate> p_templ =
4164    v8::Persistent<ObjectTemplate>::New(templ);
4165  USE(p_templ);
4166}
4167
4168
4169static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4170  ApiTestFuzzer::Fuzz();
4171  return v8::Undefined();
4172}
4173
4174
4175THREADED_TEST(GlobalObjectTemplate) {
4176  v8::HandleScope handle_scope;
4177  Local<ObjectTemplate> global_template = ObjectTemplate::New();
4178  global_template->Set(v8_str("JSNI_Log"),
4179                       v8::FunctionTemplate::New(HandleLogDelegator));
4180  v8::Persistent<Context> context = Context::New(0, global_template);
4181  Context::Scope context_scope(context);
4182  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4183  context.Dispose();
4184}
4185
4186
4187static const char* kSimpleExtensionSource =
4188  "function Foo() {"
4189  "  return 4;"
4190  "}";
4191
4192
4193THREADED_TEST(SimpleExtensions) {
4194  v8::HandleScope handle_scope;
4195  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4196  const char* extension_names[] = { "simpletest" };
4197  v8::ExtensionConfiguration extensions(1, extension_names);
4198  v8::Handle<Context> context = Context::New(&extensions);
4199  Context::Scope lock(context);
4200  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4201  CHECK_EQ(result, v8::Integer::New(4));
4202}
4203
4204
4205static const char* kEvalExtensionSource1 =
4206  "function UseEval1() {"
4207  "  var x = 42;"
4208  "  return eval('x');"
4209  "}";
4210
4211
4212static const char* kEvalExtensionSource2 =
4213  "(function() {"
4214  "  var x = 42;"
4215  "  function e() {"
4216  "    return eval('x');"
4217  "  }"
4218  "  this.UseEval2 = e;"
4219  "})()";
4220
4221
4222THREADED_TEST(UseEvalFromExtension) {
4223  v8::HandleScope handle_scope;
4224  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4225  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4226  const char* extension_names[] = { "evaltest1", "evaltest2" };
4227  v8::ExtensionConfiguration extensions(2, extension_names);
4228  v8::Handle<Context> context = Context::New(&extensions);
4229  Context::Scope lock(context);
4230  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4231  CHECK_EQ(result, v8::Integer::New(42));
4232  result = Script::Compile(v8_str("UseEval2()"))->Run();
4233  CHECK_EQ(result, v8::Integer::New(42));
4234}
4235
4236
4237static const char* kWithExtensionSource1 =
4238  "function UseWith1() {"
4239  "  var x = 42;"
4240  "  with({x:87}) { return x; }"
4241  "}";
4242
4243
4244
4245static const char* kWithExtensionSource2 =
4246  "(function() {"
4247  "  var x = 42;"
4248  "  function e() {"
4249  "    with ({x:87}) { return x; }"
4250  "  }"
4251  "  this.UseWith2 = e;"
4252  "})()";
4253
4254
4255THREADED_TEST(UseWithFromExtension) {
4256  v8::HandleScope handle_scope;
4257  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4258  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4259  const char* extension_names[] = { "withtest1", "withtest2" };
4260  v8::ExtensionConfiguration extensions(2, extension_names);
4261  v8::Handle<Context> context = Context::New(&extensions);
4262  Context::Scope lock(context);
4263  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4264  CHECK_EQ(result, v8::Integer::New(87));
4265  result = Script::Compile(v8_str("UseWith2()"))->Run();
4266  CHECK_EQ(result, v8::Integer::New(87));
4267}
4268
4269
4270THREADED_TEST(AutoExtensions) {
4271  v8::HandleScope handle_scope;
4272  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4273  extension->set_auto_enable(true);
4274  v8::RegisterExtension(extension);
4275  v8::Handle<Context> context = Context::New();
4276  Context::Scope lock(context);
4277  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4278  CHECK_EQ(result, v8::Integer::New(4));
4279}
4280
4281
4282static const char* kSyntaxErrorInExtensionSource =
4283    "[";
4284
4285
4286// Test that a syntax error in an extension does not cause a fatal
4287// error but results in an empty context.
4288THREADED_TEST(SyntaxErrorExtensions) {
4289  v8::HandleScope handle_scope;
4290  v8::RegisterExtension(new Extension("syntaxerror",
4291                                      kSyntaxErrorInExtensionSource));
4292  const char* extension_names[] = { "syntaxerror" };
4293  v8::ExtensionConfiguration extensions(1, extension_names);
4294  v8::Handle<Context> context = Context::New(&extensions);
4295  CHECK(context.IsEmpty());
4296}
4297
4298
4299static const char* kExceptionInExtensionSource =
4300    "throw 42";
4301
4302
4303// Test that an exception when installing an extension does not cause
4304// a fatal error but results in an empty context.
4305THREADED_TEST(ExceptionExtensions) {
4306  v8::HandleScope handle_scope;
4307  v8::RegisterExtension(new Extension("exception",
4308                                      kExceptionInExtensionSource));
4309  const char* extension_names[] = { "exception" };
4310  v8::ExtensionConfiguration extensions(1, extension_names);
4311  v8::Handle<Context> context = Context::New(&extensions);
4312  CHECK(context.IsEmpty());
4313}
4314
4315
4316static const char* kNativeCallInExtensionSource =
4317    "function call_runtime_last_index_of(x) {"
4318    "  return %StringLastIndexOf(x, 'bob', 10);"
4319    "}";
4320
4321
4322static const char* kNativeCallTest =
4323    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4324
4325// Test that a native runtime calls are supported in extensions.
4326THREADED_TEST(NativeCallInExtensions) {
4327  v8::HandleScope handle_scope;
4328  v8::RegisterExtension(new Extension("nativecall",
4329                                      kNativeCallInExtensionSource));
4330  const char* extension_names[] = { "nativecall" };
4331  v8::ExtensionConfiguration extensions(1, extension_names);
4332  v8::Handle<Context> context = Context::New(&extensions);
4333  Context::Scope lock(context);
4334  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4335  CHECK_EQ(result, v8::Integer::New(3));
4336}
4337
4338
4339class NativeFunctionExtension : public Extension {
4340 public:
4341  NativeFunctionExtension(const char* name,
4342                          const char* source,
4343                          v8::InvocationCallback fun = &Echo)
4344      : Extension(name, source),
4345        function_(fun) { }
4346
4347  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4348      v8::Handle<v8::String> name) {
4349    return v8::FunctionTemplate::New(function_);
4350  }
4351
4352  static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4353    if (args.Length() >= 1) return (args[0]);
4354    return v8::Undefined();
4355  }
4356 private:
4357  v8::InvocationCallback function_;
4358};
4359
4360
4361THREADED_TEST(NativeFunctionDeclaration) {
4362  v8::HandleScope handle_scope;
4363  const char* name = "nativedecl";
4364  v8::RegisterExtension(new NativeFunctionExtension(name,
4365                                                    "native function foo();"));
4366  const char* extension_names[] = { name };
4367  v8::ExtensionConfiguration extensions(1, extension_names);
4368  v8::Handle<Context> context = Context::New(&extensions);
4369  Context::Scope lock(context);
4370  v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4371  CHECK_EQ(result, v8::Integer::New(42));
4372}
4373
4374
4375THREADED_TEST(NativeFunctionDeclarationError) {
4376  v8::HandleScope handle_scope;
4377  const char* name = "nativedeclerr";
4378  // Syntax error in extension code.
4379  v8::RegisterExtension(new NativeFunctionExtension(name,
4380                                                    "native\nfunction foo();"));
4381  const char* extension_names[] = { name };
4382  v8::ExtensionConfiguration extensions(1, extension_names);
4383  v8::Handle<Context> context = Context::New(&extensions);
4384  ASSERT(context.IsEmpty());
4385}
4386
4387THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4388  v8::HandleScope handle_scope;
4389  const char* name = "nativedeclerresc";
4390  // Syntax error in extension code - escape code in "native" means that
4391  // it's not treated as a keyword.
4392  v8::RegisterExtension(new NativeFunctionExtension(
4393      name,
4394      "nativ\\u0065 function foo();"));
4395  const char* extension_names[] = { name };
4396  v8::ExtensionConfiguration extensions(1, extension_names);
4397  v8::Handle<Context> context = Context::New(&extensions);
4398  ASSERT(context.IsEmpty());
4399}
4400
4401
4402static void CheckDependencies(const char* name, const char* expected) {
4403  v8::HandleScope handle_scope;
4404  v8::ExtensionConfiguration config(1, &name);
4405  LocalContext context(&config);
4406  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4407}
4408
4409
4410/*
4411 * Configuration:
4412 *
4413 *     /-- B <--\
4414 * A <-          -- D <-- E
4415 *     \-- C <--/
4416 */
4417THREADED_TEST(ExtensionDependency) {
4418  static const char* kEDeps[] = { "D" };
4419  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4420  static const char* kDDeps[] = { "B", "C" };
4421  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4422  static const char* kBCDeps[] = { "A" };
4423  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4424  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4425  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4426  CheckDependencies("A", "undefinedA");
4427  CheckDependencies("B", "undefinedAB");
4428  CheckDependencies("C", "undefinedAC");
4429  CheckDependencies("D", "undefinedABCD");
4430  CheckDependencies("E", "undefinedABCDE");
4431  v8::HandleScope handle_scope;
4432  static const char* exts[2] = { "C", "E" };
4433  v8::ExtensionConfiguration config(2, exts);
4434  LocalContext context(&config);
4435  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4436}
4437
4438
4439static const char* kExtensionTestScript =
4440  "native function A();"
4441  "native function B();"
4442  "native function C();"
4443  "function Foo(i) {"
4444  "  if (i == 0) return A();"
4445  "  if (i == 1) return B();"
4446  "  if (i == 2) return C();"
4447  "}";
4448
4449
4450static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4451  ApiTestFuzzer::Fuzz();
4452  if (args.IsConstructCall()) {
4453    args.This()->Set(v8_str("data"), args.Data());
4454    return v8::Null();
4455  }
4456  return args.Data();
4457}
4458
4459
4460class FunctionExtension : public Extension {
4461 public:
4462  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4463  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4464      v8::Handle<String> name);
4465};
4466
4467
4468static int lookup_count = 0;
4469v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4470      v8::Handle<String> name) {
4471  lookup_count++;
4472  if (name->Equals(v8_str("A"))) {
4473    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4474  } else if (name->Equals(v8_str("B"))) {
4475    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4476  } else if (name->Equals(v8_str("C"))) {
4477    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4478  } else {
4479    return v8::Handle<v8::FunctionTemplate>();
4480  }
4481}
4482
4483
4484THREADED_TEST(FunctionLookup) {
4485  v8::RegisterExtension(new FunctionExtension());
4486  v8::HandleScope handle_scope;
4487  static const char* exts[1] = { "functiontest" };
4488  v8::ExtensionConfiguration config(1, exts);
4489  LocalContext context(&config);
4490  CHECK_EQ(3, lookup_count);
4491  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4492  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4493  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4494}
4495
4496
4497THREADED_TEST(NativeFunctionConstructCall) {
4498  v8::RegisterExtension(new FunctionExtension());
4499  v8::HandleScope handle_scope;
4500  static const char* exts[1] = { "functiontest" };
4501  v8::ExtensionConfiguration config(1, exts);
4502  LocalContext context(&config);
4503  for (int i = 0; i < 10; i++) {
4504    // Run a few times to ensure that allocation of objects doesn't
4505    // change behavior of a constructor function.
4506    CHECK_EQ(v8::Integer::New(8),
4507             Script::Compile(v8_str("(new A()).data"))->Run());
4508    CHECK_EQ(v8::Integer::New(7),
4509             Script::Compile(v8_str("(new B()).data"))->Run());
4510    CHECK_EQ(v8::Integer::New(6),
4511             Script::Compile(v8_str("(new C()).data"))->Run());
4512  }
4513}
4514
4515
4516static const char* last_location;
4517static const char* last_message;
4518void StoringErrorCallback(const char* location, const char* message) {
4519  if (last_location == NULL) {
4520    last_location = location;
4521    last_message = message;
4522  }
4523}
4524
4525
4526// ErrorReporting creates a circular extensions configuration and
4527// tests that the fatal error handler gets called.  This renders V8
4528// unusable and therefore this test cannot be run in parallel.
4529TEST(ErrorReporting) {
4530  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4531  static const char* aDeps[] = { "B" };
4532  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4533  static const char* bDeps[] = { "A" };
4534  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4535  last_location = NULL;
4536  v8::ExtensionConfiguration config(1, bDeps);
4537  v8::Handle<Context> context = Context::New(&config);
4538  CHECK(context.IsEmpty());
4539  CHECK_NE(last_location, NULL);
4540}
4541
4542
4543static const char* js_code_causing_huge_string_flattening =
4544    "var str = 'X';"
4545    "for (var i = 0; i < 30; i++) {"
4546    "  str = str + str;"
4547    "}"
4548    "str.match(/X/);";
4549
4550
4551void OOMCallback(const char* location, const char* message) {
4552  exit(0);
4553}
4554
4555
4556TEST(RegexpOutOfMemory) {
4557  // Execute a script that causes out of memory when flattening a string.
4558  v8::HandleScope scope;
4559  v8::V8::SetFatalErrorHandler(OOMCallback);
4560  LocalContext context;
4561  Local<Script> script =
4562      Script::Compile(String::New(js_code_causing_huge_string_flattening));
4563  last_location = NULL;
4564  Local<Value> result = script->Run();
4565
4566  CHECK(false);  // Should not return.
4567}
4568
4569
4570static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4571                                             v8::Handle<Value> data) {
4572  CHECK_EQ(v8::Undefined(), data);
4573  CHECK(message->GetScriptResourceName()->IsUndefined());
4574  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4575  message->GetLineNumber();
4576  message->GetSourceLine();
4577}
4578
4579
4580THREADED_TEST(ErrorWithMissingScriptInfo) {
4581  v8::HandleScope scope;
4582  LocalContext context;
4583  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4584  Script::Compile(v8_str("throw Error()"))->Run();
4585  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4586}
4587
4588
4589int global_index = 0;
4590
4591class Snorkel {
4592 public:
4593  Snorkel() { index_ = global_index++; }
4594  int index_;
4595};
4596
4597class Whammy {
4598 public:
4599  Whammy() {
4600    cursor_ = 0;
4601  }
4602  ~Whammy() {
4603    script_.Dispose();
4604  }
4605  v8::Handle<Script> getScript() {
4606    if (script_.IsEmpty())
4607      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4608    return Local<Script>(*script_);
4609  }
4610
4611 public:
4612  static const int kObjectCount = 256;
4613  int cursor_;
4614  v8::Persistent<v8::Object> objects_[kObjectCount];
4615  v8::Persistent<Script> script_;
4616};
4617
4618static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4619  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4620  delete snorkel;
4621  obj.ClearWeak();
4622}
4623
4624v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4625                                       const AccessorInfo& info) {
4626  Whammy* whammy =
4627    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4628
4629  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4630
4631  v8::Handle<v8::Object> obj = v8::Object::New();
4632  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4633  if (!prev.IsEmpty()) {
4634    prev->Set(v8_str("next"), obj);
4635    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4636    whammy->objects_[whammy->cursor_].Clear();
4637  }
4638  whammy->objects_[whammy->cursor_] = global;
4639  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4640  return whammy->getScript()->Run();
4641}
4642
4643THREADED_TEST(WeakReference) {
4644  v8::HandleScope handle_scope;
4645  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
4646  Whammy* whammy = new Whammy();
4647  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4648                                 0, 0, 0, 0,
4649                                 v8::External::New(whammy));
4650  const char* extension_list[] = { "v8/gc" };
4651  v8::ExtensionConfiguration extensions(1, extension_list);
4652  v8::Persistent<Context> context = Context::New(&extensions);
4653  Context::Scope context_scope(context);
4654
4655  v8::Handle<v8::Object> interceptor = templ->NewInstance();
4656  context->Global()->Set(v8_str("whammy"), interceptor);
4657  const char* code =
4658      "var last;"
4659      "for (var i = 0; i < 10000; i++) {"
4660      "  var obj = whammy.length;"
4661      "  if (last) last.next = obj;"
4662      "  last = obj;"
4663      "}"
4664      "gc();"
4665      "4";
4666  v8::Handle<Value> result = CompileRun(code);
4667  CHECK_EQ(4.0, result->NumberValue());
4668  delete whammy;
4669  context.Dispose();
4670}
4671
4672
4673static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
4674  obj.Dispose();
4675  obj.Clear();
4676  *(reinterpret_cast<bool*>(data)) = true;
4677}
4678
4679
4680THREADED_TEST(IndependentWeakHandle) {
4681  v8::Persistent<Context> context = Context::New();
4682  Context::Scope context_scope(context);
4683
4684  v8::Persistent<v8::Object> object_a;
4685
4686  {
4687    v8::HandleScope handle_scope;
4688    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4689  }
4690
4691  bool object_a_disposed = false;
4692  object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4693  object_a.MarkIndependent();
4694  HEAP->PerformScavenge();
4695  CHECK(object_a_disposed);
4696}
4697
4698
4699static void InvokeScavenge() {
4700  HEAP->PerformScavenge();
4701}
4702
4703
4704static void InvokeMarkSweep() {
4705  HEAP->CollectAllGarbage(false);
4706}
4707
4708
4709static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4710  obj.Dispose();
4711  obj.Clear();
4712  *(reinterpret_cast<bool*>(data)) = true;
4713  InvokeScavenge();
4714}
4715
4716
4717static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4718  obj.Dispose();
4719  obj.Clear();
4720  *(reinterpret_cast<bool*>(data)) = true;
4721  InvokeMarkSweep();
4722}
4723
4724
4725THREADED_TEST(GCFromWeakCallbacks) {
4726  v8::Persistent<Context> context = Context::New();
4727  Context::Scope context_scope(context);
4728
4729  static const int kNumberOfGCTypes = 2;
4730  v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4731      {&ForceScavenge, &ForceMarkSweep};
4732
4733  typedef void (*GCInvoker)();
4734  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4735
4736  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4737    for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4738      v8::Persistent<v8::Object> object;
4739      {
4740        v8::HandleScope handle_scope;
4741        object = v8::Persistent<v8::Object>::New(v8::Object::New());
4742      }
4743      bool disposed = false;
4744      object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4745      object.MarkIndependent();
4746      invoke_gc[outer_gc]();
4747      CHECK(disposed);
4748    }
4749  }
4750}
4751
4752
4753static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4754  obj.ClearWeak();
4755  *(reinterpret_cast<bool*>(data)) = true;
4756}
4757
4758
4759THREADED_TEST(IndependentHandleRevival) {
4760  v8::Persistent<Context> context = Context::New();
4761  Context::Scope context_scope(context);
4762
4763  v8::Persistent<v8::Object> object;
4764  {
4765    v8::HandleScope handle_scope;
4766    object = v8::Persistent<v8::Object>::New(v8::Object::New());
4767    object->Set(v8_str("x"), v8::Integer::New(1));
4768    v8::Local<String> y_str = v8_str("y");
4769    object->Set(y_str, y_str);
4770  }
4771  bool revived = false;
4772  object.MakeWeak(&revived, &RevivingCallback);
4773  object.MarkIndependent();
4774  HEAP->PerformScavenge();
4775  CHECK(revived);
4776  HEAP->CollectAllGarbage(true);
4777  {
4778    v8::HandleScope handle_scope;
4779    v8::Local<String> y_str = v8_str("y");
4780    CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4781    CHECK(object->Get(y_str)->Equals(y_str));
4782  }
4783}
4784
4785
4786v8::Handle<Function> args_fun;
4787
4788
4789static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4790  ApiTestFuzzer::Fuzz();
4791  CHECK_EQ(args_fun, args.Callee());
4792  CHECK_EQ(3, args.Length());
4793  CHECK_EQ(v8::Integer::New(1), args[0]);
4794  CHECK_EQ(v8::Integer::New(2), args[1]);
4795  CHECK_EQ(v8::Integer::New(3), args[2]);
4796  CHECK_EQ(v8::Undefined(), args[3]);
4797  v8::HandleScope scope;
4798  HEAP->CollectAllGarbage(false);
4799  return v8::Undefined();
4800}
4801
4802
4803THREADED_TEST(Arguments) {
4804  v8::HandleScope scope;
4805  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4806  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4807  LocalContext context(NULL, global);
4808  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
4809  v8_compile("f(1, 2, 3)")->Run();
4810}
4811
4812
4813static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4814                                        const AccessorInfo&) {
4815  return v8::Handle<Value>();
4816}
4817
4818
4819static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4820                                        const AccessorInfo&) {
4821  return v8::Handle<Value>();
4822}
4823
4824
4825static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4826                                        const AccessorInfo&) {
4827  if (!name->Equals(v8_str("foo"))) {
4828    return v8::Handle<v8::Boolean>();  // not intercepted
4829  }
4830
4831  return v8::False();  // intercepted, and don't delete the property
4832}
4833
4834
4835static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4836  if (index != 2) {
4837    return v8::Handle<v8::Boolean>();  // not intercepted
4838  }
4839
4840  return v8::False();  // intercepted, and don't delete the property
4841}
4842
4843
4844THREADED_TEST(Deleter) {
4845  v8::HandleScope scope;
4846  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4847  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4848  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4849  LocalContext context;
4850  context->Global()->Set(v8_str("k"), obj->NewInstance());
4851  CompileRun(
4852    "k.foo = 'foo';"
4853    "k.bar = 'bar';"
4854    "k[2] = 2;"
4855    "k[4] = 4;");
4856  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4857  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4858
4859  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4860  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4861
4862  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4863  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4864
4865  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4866  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4867}
4868
4869
4870static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4871  ApiTestFuzzer::Fuzz();
4872  if (name->Equals(v8_str("foo")) ||
4873      name->Equals(v8_str("bar")) ||
4874      name->Equals(v8_str("baz"))) {
4875    return v8::Undefined();
4876  }
4877  return v8::Handle<Value>();
4878}
4879
4880
4881static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4882  ApiTestFuzzer::Fuzz();
4883  if (index == 0 || index == 1) return v8::Undefined();
4884  return v8::Handle<Value>();
4885}
4886
4887
4888static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4889  ApiTestFuzzer::Fuzz();
4890  v8::Handle<v8::Array> result = v8::Array::New(3);
4891  result->Set(v8::Integer::New(0), v8_str("foo"));
4892  result->Set(v8::Integer::New(1), v8_str("bar"));
4893  result->Set(v8::Integer::New(2), v8_str("baz"));
4894  return result;
4895}
4896
4897
4898static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4899  ApiTestFuzzer::Fuzz();
4900  v8::Handle<v8::Array> result = v8::Array::New(2);
4901  result->Set(v8::Integer::New(0), v8_str("0"));
4902  result->Set(v8::Integer::New(1), v8_str("1"));
4903  return result;
4904}
4905
4906
4907THREADED_TEST(Enumerators) {
4908  v8::HandleScope scope;
4909  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4910  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4911  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4912  LocalContext context;
4913  context->Global()->Set(v8_str("k"), obj->NewInstance());
4914  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4915    "k[10] = 0;"
4916    "k.a = 0;"
4917    "k[5] = 0;"
4918    "k.b = 0;"
4919    "k[4294967295] = 0;"
4920    "k.c = 0;"
4921    "k[4294967296] = 0;"
4922    "k.d = 0;"
4923    "k[140000] = 0;"
4924    "k.e = 0;"
4925    "k[30000000000] = 0;"
4926    "k.f = 0;"
4927    "var result = [];"
4928    "for (var prop in k) {"
4929    "  result.push(prop);"
4930    "}"
4931    "result"));
4932  // Check that we get all the property names returned including the
4933  // ones from the enumerators in the right order: indexed properties
4934  // in numerical order, indexed interceptor properties, named
4935  // properties in insertion order, named interceptor properties.
4936  // This order is not mandated by the spec, so this test is just
4937  // documenting our behavior.
4938  CHECK_EQ(17, result->Length());
4939  // Indexed properties in numerical order.
4940  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4941  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4942  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4943  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4944  // Indexed interceptor properties in the order they are returned
4945  // from the enumerator interceptor.
4946  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4947  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4948  // Named properties in insertion order.
4949  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4950  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4951  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4952  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4953  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4954  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4955  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4956  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4957  // Named interceptor properties.
4958  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4959  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4960  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4961}
4962
4963
4964int p_getter_count;
4965int p_getter_count2;
4966
4967
4968static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4969  ApiTestFuzzer::Fuzz();
4970  p_getter_count++;
4971  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4972  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4973  if (name->Equals(v8_str("p1"))) {
4974    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4975  } else if (name->Equals(v8_str("p2"))) {
4976    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4977  } else if (name->Equals(v8_str("p3"))) {
4978    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4979  } else if (name->Equals(v8_str("p4"))) {
4980    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4981  }
4982  return v8::Undefined();
4983}
4984
4985
4986static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4987  ApiTestFuzzer::Fuzz();
4988  LocalContext context;
4989  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4990  CompileRun(
4991    "o1.__proto__ = { };"
4992    "var o2 = { __proto__: o1 };"
4993    "var o3 = { __proto__: o2 };"
4994    "var o4 = { __proto__: o3 };"
4995    "for (var i = 0; i < 10; i++) o4.p4;"
4996    "for (var i = 0; i < 10; i++) o3.p3;"
4997    "for (var i = 0; i < 10; i++) o2.p2;"
4998    "for (var i = 0; i < 10; i++) o1.p1;");
4999}
5000
5001
5002static v8::Handle<Value> PGetter2(Local<String> name,
5003                                  const AccessorInfo& info) {
5004  ApiTestFuzzer::Fuzz();
5005  p_getter_count2++;
5006  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5007  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5008  if (name->Equals(v8_str("p1"))) {
5009    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5010  } else if (name->Equals(v8_str("p2"))) {
5011    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5012  } else if (name->Equals(v8_str("p3"))) {
5013    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5014  } else if (name->Equals(v8_str("p4"))) {
5015    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5016  }
5017  return v8::Undefined();
5018}
5019
5020
5021THREADED_TEST(GetterHolders) {
5022  v8::HandleScope scope;
5023  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5024  obj->SetAccessor(v8_str("p1"), PGetter);
5025  obj->SetAccessor(v8_str("p2"), PGetter);
5026  obj->SetAccessor(v8_str("p3"), PGetter);
5027  obj->SetAccessor(v8_str("p4"), PGetter);
5028  p_getter_count = 0;
5029  RunHolderTest(obj);
5030  CHECK_EQ(40, p_getter_count);
5031}
5032
5033
5034THREADED_TEST(PreInterceptorHolders) {
5035  v8::HandleScope scope;
5036  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5037  obj->SetNamedPropertyHandler(PGetter2);
5038  p_getter_count2 = 0;
5039  RunHolderTest(obj);
5040  CHECK_EQ(40, p_getter_count2);
5041}
5042
5043
5044THREADED_TEST(ObjectInstantiation) {
5045  v8::HandleScope scope;
5046  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5047  templ->SetAccessor(v8_str("t"), PGetter2);
5048  LocalContext context;
5049  context->Global()->Set(v8_str("o"), templ->NewInstance());
5050  for (int i = 0; i < 100; i++) {
5051    v8::HandleScope inner_scope;
5052    v8::Handle<v8::Object> obj = templ->NewInstance();
5053    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5054    context->Global()->Set(v8_str("o2"), obj);
5055    v8::Handle<Value> value =
5056        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5057    CHECK_EQ(v8::True(), value);
5058    context->Global()->Set(v8_str("o"), obj);
5059  }
5060}
5061
5062
5063static int StrCmp16(uint16_t* a, uint16_t* b) {
5064  while (true) {
5065    if (*a == 0 && *b == 0) return 0;
5066    if (*a != *b) return 0 + *a - *b;
5067    a++;
5068    b++;
5069  }
5070}
5071
5072
5073static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5074  while (true) {
5075    if (n-- == 0) return 0;
5076    if (*a == 0 && *b == 0) return 0;
5077    if (*a != *b) return 0 + *a - *b;
5078    a++;
5079    b++;
5080  }
5081}
5082
5083
5084THREADED_TEST(StringWrite) {
5085  v8::HandleScope scope;
5086  v8::Handle<String> str = v8_str("abcde");
5087  // abc<Icelandic eth><Unicode snowman>.
5088  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5089
5090  CHECK_EQ(5, str2->Length());
5091
5092  char buf[100];
5093  char utf8buf[100];
5094  uint16_t wbuf[100];
5095  int len;
5096  int charlen;
5097
5098  memset(utf8buf, 0x1, sizeof(utf8buf));
5099  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5100  CHECK_EQ(9, len);
5101  CHECK_EQ(5, charlen);
5102  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5103
5104  memset(utf8buf, 0x1, sizeof(utf8buf));
5105  len = str2->WriteUtf8(utf8buf, 8, &charlen);
5106  CHECK_EQ(8, len);
5107  CHECK_EQ(5, charlen);
5108  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5109
5110  memset(utf8buf, 0x1, sizeof(utf8buf));
5111  len = str2->WriteUtf8(utf8buf, 7, &charlen);
5112  CHECK_EQ(5, len);
5113  CHECK_EQ(4, charlen);
5114  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5115
5116  memset(utf8buf, 0x1, sizeof(utf8buf));
5117  len = str2->WriteUtf8(utf8buf, 6, &charlen);
5118  CHECK_EQ(5, len);
5119  CHECK_EQ(4, charlen);
5120  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5121
5122  memset(utf8buf, 0x1, sizeof(utf8buf));
5123  len = str2->WriteUtf8(utf8buf, 5, &charlen);
5124  CHECK_EQ(5, len);
5125  CHECK_EQ(4, charlen);
5126  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5127
5128  memset(utf8buf, 0x1, sizeof(utf8buf));
5129  len = str2->WriteUtf8(utf8buf, 4, &charlen);
5130  CHECK_EQ(3, len);
5131  CHECK_EQ(3, charlen);
5132  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5133
5134  memset(utf8buf, 0x1, sizeof(utf8buf));
5135  len = str2->WriteUtf8(utf8buf, 3, &charlen);
5136  CHECK_EQ(3, len);
5137  CHECK_EQ(3, charlen);
5138  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5139
5140  memset(utf8buf, 0x1, sizeof(utf8buf));
5141  len = str2->WriteUtf8(utf8buf, 2, &charlen);
5142  CHECK_EQ(2, len);
5143  CHECK_EQ(2, charlen);
5144  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5145
5146  memset(buf, 0x1, sizeof(buf));
5147  memset(wbuf, 0x1, sizeof(wbuf));
5148  len = str->WriteAscii(buf);
5149  CHECK_EQ(5, len);
5150  len = str->Write(wbuf);
5151  CHECK_EQ(5, len);
5152  CHECK_EQ(0, strcmp("abcde", buf));
5153  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5154  CHECK_EQ(0, StrCmp16(answer1, wbuf));
5155
5156  memset(buf, 0x1, sizeof(buf));
5157  memset(wbuf, 0x1, sizeof(wbuf));
5158  len = str->WriteAscii(buf, 0, 4);
5159  CHECK_EQ(4, len);
5160  len = str->Write(wbuf, 0, 4);
5161  CHECK_EQ(4, len);
5162  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5163  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5164  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5165
5166  memset(buf, 0x1, sizeof(buf));
5167  memset(wbuf, 0x1, sizeof(wbuf));
5168  len = str->WriteAscii(buf, 0, 5);
5169  CHECK_EQ(5, len);
5170  len = str->Write(wbuf, 0, 5);
5171  CHECK_EQ(5, len);
5172  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5173  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5174  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5175
5176  memset(buf, 0x1, sizeof(buf));
5177  memset(wbuf, 0x1, sizeof(wbuf));
5178  len = str->WriteAscii(buf, 0, 6);
5179  CHECK_EQ(5, len);
5180  len = str->Write(wbuf, 0, 6);
5181  CHECK_EQ(5, len);
5182  CHECK_EQ(0, strcmp("abcde", buf));
5183  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5184  CHECK_EQ(0, StrCmp16(answer4, wbuf));
5185
5186  memset(buf, 0x1, sizeof(buf));
5187  memset(wbuf, 0x1, sizeof(wbuf));
5188  len = str->WriteAscii(buf, 4, -1);
5189  CHECK_EQ(1, len);
5190  len = str->Write(wbuf, 4, -1);
5191  CHECK_EQ(1, len);
5192  CHECK_EQ(0, strcmp("e", buf));
5193  uint16_t answer5[] = {'e', '\0'};
5194  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5195
5196  memset(buf, 0x1, sizeof(buf));
5197  memset(wbuf, 0x1, sizeof(wbuf));
5198  len = str->WriteAscii(buf, 4, 6);
5199  CHECK_EQ(1, len);
5200  len = str->Write(wbuf, 4, 6);
5201  CHECK_EQ(1, len);
5202  CHECK_EQ(0, strcmp("e", buf));
5203  CHECK_EQ(0, StrCmp16(answer5, wbuf));
5204
5205  memset(buf, 0x1, sizeof(buf));
5206  memset(wbuf, 0x1, sizeof(wbuf));
5207  len = str->WriteAscii(buf, 4, 1);
5208  CHECK_EQ(1, len);
5209  len = str->Write(wbuf, 4, 1);
5210  CHECK_EQ(1, len);
5211  CHECK_EQ(0, strncmp("e\1", buf, 2));
5212  uint16_t answer6[] = {'e', 0x101};
5213  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5214
5215  memset(buf, 0x1, sizeof(buf));
5216  memset(wbuf, 0x1, sizeof(wbuf));
5217  len = str->WriteAscii(buf, 3, 1);
5218  CHECK_EQ(1, len);
5219  len = str->Write(wbuf, 3, 1);
5220  CHECK_EQ(1, len);
5221  CHECK_EQ(0, strncmp("d\1", buf, 2));
5222  uint16_t answer7[] = {'d', 0x101};
5223  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5224}
5225
5226
5227THREADED_TEST(ToArrayIndex) {
5228  v8::HandleScope scope;
5229  LocalContext context;
5230
5231  v8::Handle<String> str = v8_str("42");
5232  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5233  CHECK(!index.IsEmpty());
5234  CHECK_EQ(42.0, index->Uint32Value());
5235  str = v8_str("42asdf");
5236  index = str->ToArrayIndex();
5237  CHECK(index.IsEmpty());
5238  str = v8_str("-42");
5239  index = str->ToArrayIndex();
5240  CHECK(index.IsEmpty());
5241  str = v8_str("4294967295");
5242  index = str->ToArrayIndex();
5243  CHECK(!index.IsEmpty());
5244  CHECK_EQ(4294967295.0, index->Uint32Value());
5245  v8::Handle<v8::Number> num = v8::Number::New(1);
5246  index = num->ToArrayIndex();
5247  CHECK(!index.IsEmpty());
5248  CHECK_EQ(1.0, index->Uint32Value());
5249  num = v8::Number::New(-1);
5250  index = num->ToArrayIndex();
5251  CHECK(index.IsEmpty());
5252  v8::Handle<v8::Object> obj = v8::Object::New();
5253  index = obj->ToArrayIndex();
5254  CHECK(index.IsEmpty());
5255}
5256
5257
5258THREADED_TEST(ErrorConstruction) {
5259  v8::HandleScope scope;
5260  LocalContext context;
5261
5262  v8::Handle<String> foo = v8_str("foo");
5263  v8::Handle<String> message = v8_str("message");
5264  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5265  CHECK(range_error->IsObject());
5266  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5267  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
5268  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5269  CHECK(reference_error->IsObject());
5270  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
5271  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5272  CHECK(syntax_error->IsObject());
5273  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
5274  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5275  CHECK(type_error->IsObject());
5276  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
5277  v8::Handle<Value> error = v8::Exception::Error(foo);
5278  CHECK(error->IsObject());
5279  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
5280}
5281
5282
5283static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5284  ApiTestFuzzer::Fuzz();
5285  return v8_num(10);
5286}
5287
5288
5289static void YSetter(Local<String> name,
5290                    Local<Value> value,
5291                    const AccessorInfo& info) {
5292  if (info.This()->Has(name)) {
5293    info.This()->Delete(name);
5294  }
5295  info.This()->Set(name, value);
5296}
5297
5298
5299THREADED_TEST(DeleteAccessor) {
5300  v8::HandleScope scope;
5301  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5302  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5303  LocalContext context;
5304  v8::Handle<v8::Object> holder = obj->NewInstance();
5305  context->Global()->Set(v8_str("holder"), holder);
5306  v8::Handle<Value> result = CompileRun(
5307      "holder.y = 11; holder.y = 12; holder.y");
5308  CHECK_EQ(12, result->Uint32Value());
5309}
5310
5311
5312THREADED_TEST(TypeSwitch) {
5313  v8::HandleScope scope;
5314  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5315  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5316  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5317  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5318  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5319  LocalContext context;
5320  v8::Handle<v8::Object> obj0 = v8::Object::New();
5321  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5322  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5323  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5324  for (int i = 0; i < 10; i++) {
5325    CHECK_EQ(0, type_switch->match(obj0));
5326    CHECK_EQ(1, type_switch->match(obj1));
5327    CHECK_EQ(2, type_switch->match(obj2));
5328    CHECK_EQ(3, type_switch->match(obj3));
5329    CHECK_EQ(3, type_switch->match(obj3));
5330    CHECK_EQ(2, type_switch->match(obj2));
5331    CHECK_EQ(1, type_switch->match(obj1));
5332    CHECK_EQ(0, type_switch->match(obj0));
5333  }
5334}
5335
5336
5337// For use within the TestSecurityHandler() test.
5338static bool g_security_callback_result = false;
5339static bool NamedSecurityTestCallback(Local<v8::Object> global,
5340                                      Local<Value> name,
5341                                      v8::AccessType type,
5342                                      Local<Value> data) {
5343  // Always allow read access.
5344  if (type == v8::ACCESS_GET)
5345    return true;
5346
5347  // Sometimes allow other access.
5348  return g_security_callback_result;
5349}
5350
5351
5352static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5353                                        uint32_t key,
5354                                        v8::AccessType type,
5355                                        Local<Value> data) {
5356  // Always allow read access.
5357  if (type == v8::ACCESS_GET)
5358    return true;
5359
5360  // Sometimes allow other access.
5361  return g_security_callback_result;
5362}
5363
5364
5365static int trouble_nesting = 0;
5366static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5367  ApiTestFuzzer::Fuzz();
5368  trouble_nesting++;
5369
5370  // Call a JS function that throws an uncaught exception.
5371  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5372  Local<Value> trouble_callee = (trouble_nesting == 3) ?
5373    arg_this->Get(v8_str("trouble_callee")) :
5374    arg_this->Get(v8_str("trouble_caller"));
5375  CHECK(trouble_callee->IsFunction());
5376  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5377}
5378
5379
5380static int report_count = 0;
5381static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5382                                             v8::Handle<Value>) {
5383  report_count++;
5384}
5385
5386
5387// Counts uncaught exceptions, but other tests running in parallel
5388// also have uncaught exceptions.
5389TEST(ApiUncaughtException) {
5390  report_count = 0;
5391  v8::HandleScope scope;
5392  LocalContext env;
5393  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5394
5395  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5396  v8::Local<v8::Object> global = env->Global();
5397  global->Set(v8_str("trouble"), fun->GetFunction());
5398
5399  Script::Compile(v8_str("function trouble_callee() {"
5400                         "  var x = null;"
5401                         "  return x.foo;"
5402                         "};"
5403                         "function trouble_caller() {"
5404                         "  trouble();"
5405                         "};"))->Run();
5406  Local<Value> trouble = global->Get(v8_str("trouble"));
5407  CHECK(trouble->IsFunction());
5408  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5409  CHECK(trouble_callee->IsFunction());
5410  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5411  CHECK(trouble_caller->IsFunction());
5412  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5413  CHECK_EQ(1, report_count);
5414  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5415}
5416
5417static const char* script_resource_name = "ExceptionInNativeScript.js";
5418static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5419                                                v8::Handle<Value>) {
5420  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5421  CHECK(!name_val.IsEmpty() && name_val->IsString());
5422  v8::String::AsciiValue name(message->GetScriptResourceName());
5423  CHECK_EQ(script_resource_name, *name);
5424  CHECK_EQ(3, message->GetLineNumber());
5425  v8::String::AsciiValue source_line(message->GetSourceLine());
5426  CHECK_EQ("  new o.foo();", *source_line);
5427}
5428
5429TEST(ExceptionInNativeScript) {
5430  v8::HandleScope scope;
5431  LocalContext env;
5432  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5433
5434  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5435  v8::Local<v8::Object> global = env->Global();
5436  global->Set(v8_str("trouble"), fun->GetFunction());
5437
5438  Script::Compile(v8_str("function trouble() {\n"
5439                         "  var o = {};\n"
5440                         "  new o.foo();\n"
5441                         "};"), v8::String::New(script_resource_name))->Run();
5442  Local<Value> trouble = global->Get(v8_str("trouble"));
5443  CHECK(trouble->IsFunction());
5444  Function::Cast(*trouble)->Call(global, 0, NULL);
5445  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5446}
5447
5448
5449TEST(CompilationErrorUsingTryCatchHandler) {
5450  v8::HandleScope scope;
5451  LocalContext env;
5452  v8::TryCatch try_catch;
5453  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5454  CHECK_NE(NULL, *try_catch.Exception());
5455  CHECK(try_catch.HasCaught());
5456}
5457
5458
5459TEST(TryCatchFinallyUsingTryCatchHandler) {
5460  v8::HandleScope scope;
5461  LocalContext env;
5462  v8::TryCatch try_catch;
5463  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5464  CHECK(!try_catch.HasCaught());
5465  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5466  CHECK(try_catch.HasCaught());
5467  try_catch.Reset();
5468  Script::Compile(v8_str("(function() {"
5469                         "try { throw ''; } finally { return; }"
5470                         "})()"))->Run();
5471  CHECK(!try_catch.HasCaught());
5472  Script::Compile(v8_str("(function()"
5473                         "  { try { throw ''; } finally { throw 0; }"
5474                         "})()"))->Run();
5475  CHECK(try_catch.HasCaught());
5476}
5477
5478
5479// SecurityHandler can't be run twice
5480TEST(SecurityHandler) {
5481  v8::HandleScope scope0;
5482  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5483  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5484                                           IndexedSecurityTestCallback);
5485  // Create an environment
5486  v8::Persistent<Context> context0 =
5487    Context::New(NULL, global_template);
5488  context0->Enter();
5489
5490  v8::Handle<v8::Object> global0 = context0->Global();
5491  v8::Handle<Script> script0 = v8_compile("foo = 111");
5492  script0->Run();
5493  global0->Set(v8_str("0"), v8_num(999));
5494  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5495  CHECK_EQ(111, foo0->Int32Value());
5496  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5497  CHECK_EQ(999, z0->Int32Value());
5498
5499  // Create another environment, should fail security checks.
5500  v8::HandleScope scope1;
5501
5502  v8::Persistent<Context> context1 =
5503    Context::New(NULL, global_template);
5504  context1->Enter();
5505
5506  v8::Handle<v8::Object> global1 = context1->Global();
5507  global1->Set(v8_str("othercontext"), global0);
5508  // This set will fail the security check.
5509  v8::Handle<Script> script1 =
5510    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5511  script1->Run();
5512  // This read will pass the security check.
5513  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5514  CHECK_EQ(111, foo1->Int32Value());
5515  // This read will pass the security check.
5516  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5517  CHECK_EQ(999, z1->Int32Value());
5518
5519  // Create another environment, should pass security checks.
5520  { g_security_callback_result = true;  // allow security handler to pass.
5521    v8::HandleScope scope2;
5522    LocalContext context2;
5523    v8::Handle<v8::Object> global2 = context2->Global();
5524    global2->Set(v8_str("othercontext"), global0);
5525    v8::Handle<Script> script2 =
5526        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5527    script2->Run();
5528    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5529    CHECK_EQ(333, foo2->Int32Value());
5530    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5531    CHECK_EQ(888, z2->Int32Value());
5532  }
5533
5534  context1->Exit();
5535  context1.Dispose();
5536
5537  context0->Exit();
5538  context0.Dispose();
5539}
5540
5541
5542THREADED_TEST(SecurityChecks) {
5543  v8::HandleScope handle_scope;
5544  LocalContext env1;
5545  v8::Persistent<Context> env2 = Context::New();
5546
5547  Local<Value> foo = v8_str("foo");
5548  Local<Value> bar = v8_str("bar");
5549
5550  // Set to the same domain.
5551  env1->SetSecurityToken(foo);
5552
5553  // Create a function in env1.
5554  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5555  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5556  CHECK(spy->IsFunction());
5557
5558  // Create another function accessing global objects.
5559  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5560  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5561  CHECK(spy2->IsFunction());
5562
5563  // Switch to env2 in the same domain and invoke spy on env2.
5564  {
5565    env2->SetSecurityToken(foo);
5566    // Enter env2
5567    Context::Scope scope_env2(env2);
5568    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5569    CHECK(result->IsFunction());
5570  }
5571
5572  {
5573    env2->SetSecurityToken(bar);
5574    Context::Scope scope_env2(env2);
5575
5576    // Call cross_domain_call, it should throw an exception
5577    v8::TryCatch try_catch;
5578    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5579    CHECK(try_catch.HasCaught());
5580  }
5581
5582  env2.Dispose();
5583}
5584
5585
5586// Regression test case for issue 1183439.
5587THREADED_TEST(SecurityChecksForPrototypeChain) {
5588  v8::HandleScope scope;
5589  LocalContext current;
5590  v8::Persistent<Context> other = Context::New();
5591
5592  // Change context to be able to get to the Object function in the
5593  // other context without hitting the security checks.
5594  v8::Local<Value> other_object;
5595  { Context::Scope scope(other);
5596    other_object = other->Global()->Get(v8_str("Object"));
5597    other->Global()->Set(v8_num(42), v8_num(87));
5598  }
5599
5600  current->Global()->Set(v8_str("other"), other->Global());
5601  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5602
5603  // Make sure the security check fails here and we get an undefined
5604  // result instead of getting the Object function. Repeat in a loop
5605  // to make sure to exercise the IC code.
5606  v8::Local<Script> access_other0 = v8_compile("other.Object");
5607  v8::Local<Script> access_other1 = v8_compile("other[42]");
5608  for (int i = 0; i < 5; i++) {
5609    CHECK(!access_other0->Run()->Equals(other_object));
5610    CHECK(access_other0->Run()->IsUndefined());
5611    CHECK(!access_other1->Run()->Equals(v8_num(87)));
5612    CHECK(access_other1->Run()->IsUndefined());
5613  }
5614
5615  // Create an object that has 'other' in its prototype chain and make
5616  // sure we cannot access the Object function indirectly through
5617  // that. Repeat in a loop to make sure to exercise the IC code.
5618  v8_compile("function F() { };"
5619             "F.prototype = other;"
5620             "var f = new F();")->Run();
5621  v8::Local<Script> access_f0 = v8_compile("f.Object");
5622  v8::Local<Script> access_f1 = v8_compile("f[42]");
5623  for (int j = 0; j < 5; j++) {
5624    CHECK(!access_f0->Run()->Equals(other_object));
5625    CHECK(access_f0->Run()->IsUndefined());
5626    CHECK(!access_f1->Run()->Equals(v8_num(87)));
5627    CHECK(access_f1->Run()->IsUndefined());
5628  }
5629
5630  // Now it gets hairy: Set the prototype for the other global object
5631  // to be the current global object. The prototype chain for 'f' now
5632  // goes through 'other' but ends up in the current global object.
5633  { Context::Scope scope(other);
5634    other->Global()->Set(v8_str("__proto__"), current->Global());
5635  }
5636  // Set a named and an index property on the current global
5637  // object. To force the lookup to go through the other global object,
5638  // the properties must not exist in the other global object.
5639  current->Global()->Set(v8_str("foo"), v8_num(100));
5640  current->Global()->Set(v8_num(99), v8_num(101));
5641  // Try to read the properties from f and make sure that the access
5642  // gets stopped by the security checks on the other global object.
5643  Local<Script> access_f2 = v8_compile("f.foo");
5644  Local<Script> access_f3 = v8_compile("f[99]");
5645  for (int k = 0; k < 5; k++) {
5646    CHECK(!access_f2->Run()->Equals(v8_num(100)));
5647    CHECK(access_f2->Run()->IsUndefined());
5648    CHECK(!access_f3->Run()->Equals(v8_num(101)));
5649    CHECK(access_f3->Run()->IsUndefined());
5650  }
5651  other.Dispose();
5652}
5653
5654
5655THREADED_TEST(CrossDomainDelete) {
5656  v8::HandleScope handle_scope;
5657  LocalContext env1;
5658  v8::Persistent<Context> env2 = Context::New();
5659
5660  Local<Value> foo = v8_str("foo");
5661  Local<Value> bar = v8_str("bar");
5662
5663  // Set to the same domain.
5664  env1->SetSecurityToken(foo);
5665  env2->SetSecurityToken(foo);
5666
5667  env1->Global()->Set(v8_str("prop"), v8_num(3));
5668  env2->Global()->Set(v8_str("env1"), env1->Global());
5669
5670  // Change env2 to a different domain and delete env1.prop.
5671  env2->SetSecurityToken(bar);
5672  {
5673    Context::Scope scope_env2(env2);
5674    Local<Value> result =
5675        Script::Compile(v8_str("delete env1.prop"))->Run();
5676    CHECK(result->IsFalse());
5677  }
5678
5679  // Check that env1.prop still exists.
5680  Local<Value> v = env1->Global()->Get(v8_str("prop"));
5681  CHECK(v->IsNumber());
5682  CHECK_EQ(3, v->Int32Value());
5683
5684  env2.Dispose();
5685}
5686
5687
5688THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5689  v8::HandleScope handle_scope;
5690  LocalContext env1;
5691  v8::Persistent<Context> env2 = Context::New();
5692
5693  Local<Value> foo = v8_str("foo");
5694  Local<Value> bar = v8_str("bar");
5695
5696  // Set to the same domain.
5697  env1->SetSecurityToken(foo);
5698  env2->SetSecurityToken(foo);
5699
5700  env1->Global()->Set(v8_str("prop"), v8_num(3));
5701  env2->Global()->Set(v8_str("env1"), env1->Global());
5702
5703  // env1.prop is enumerable in env2.
5704  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5705  {
5706    Context::Scope scope_env2(env2);
5707    Local<Value> result = Script::Compile(test)->Run();
5708    CHECK(result->IsTrue());
5709  }
5710
5711  // Change env2 to a different domain and test again.
5712  env2->SetSecurityToken(bar);
5713  {
5714    Context::Scope scope_env2(env2);
5715    Local<Value> result = Script::Compile(test)->Run();
5716    CHECK(result->IsFalse());
5717  }
5718
5719  env2.Dispose();
5720}
5721
5722
5723THREADED_TEST(CrossDomainForIn) {
5724  v8::HandleScope handle_scope;
5725  LocalContext env1;
5726  v8::Persistent<Context> env2 = Context::New();
5727
5728  Local<Value> foo = v8_str("foo");
5729  Local<Value> bar = v8_str("bar");
5730
5731  // Set to the same domain.
5732  env1->SetSecurityToken(foo);
5733  env2->SetSecurityToken(foo);
5734
5735  env1->Global()->Set(v8_str("prop"), v8_num(3));
5736  env2->Global()->Set(v8_str("env1"), env1->Global());
5737
5738  // Change env2 to a different domain and set env1's global object
5739  // as the __proto__ of an object in env2 and enumerate properties
5740  // in for-in. It shouldn't enumerate properties on env1's global
5741  // object.
5742  env2->SetSecurityToken(bar);
5743  {
5744    Context::Scope scope_env2(env2);
5745    Local<Value> result =
5746        CompileRun("(function(){var obj = {'__proto__':env1};"
5747                   "for (var p in obj)"
5748                   "   if (p == 'prop') return false;"
5749                   "return true;})()");
5750    CHECK(result->IsTrue());
5751  }
5752  env2.Dispose();
5753}
5754
5755
5756TEST(ContextDetachGlobal) {
5757  v8::HandleScope handle_scope;
5758  LocalContext env1;
5759  v8::Persistent<Context> env2 = Context::New();
5760
5761  Local<v8::Object> global1 = env1->Global();
5762
5763  Local<Value> foo = v8_str("foo");
5764
5765  // Set to the same domain.
5766  env1->SetSecurityToken(foo);
5767  env2->SetSecurityToken(foo);
5768
5769  // Enter env2
5770  env2->Enter();
5771
5772  // Create a function in env2 and add a reference to it in env1.
5773  Local<v8::Object> global2 = env2->Global();
5774  global2->Set(v8_str("prop"), v8::Integer::New(1));
5775  CompileRun("function getProp() {return prop;}");
5776
5777  env1->Global()->Set(v8_str("getProp"),
5778                      global2->Get(v8_str("getProp")));
5779
5780  // Detach env2's global, and reuse the global object of env2
5781  env2->Exit();
5782  env2->DetachGlobal();
5783  // env2 has a new global object.
5784  CHECK(!env2->Global()->Equals(global2));
5785
5786  v8::Persistent<Context> env3 =
5787      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5788  env3->SetSecurityToken(v8_str("bar"));
5789  env3->Enter();
5790
5791  Local<v8::Object> global3 = env3->Global();
5792  CHECK_EQ(global2, global3);
5793  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5794  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5795  global3->Set(v8_str("prop"), v8::Integer::New(-1));
5796  global3->Set(v8_str("prop2"), v8::Integer::New(2));
5797  env3->Exit();
5798
5799  // Call getProp in env1, and it should return the value 1
5800  {
5801    Local<Value> get_prop = global1->Get(v8_str("getProp"));
5802    CHECK(get_prop->IsFunction());
5803    v8::TryCatch try_catch;
5804    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5805    CHECK(!try_catch.HasCaught());
5806    CHECK_EQ(1, r->Int32Value());
5807  }
5808
5809  // Check that env3 is not accessible from env1
5810  {
5811    Local<Value> r = global3->Get(v8_str("prop2"));
5812    CHECK(r->IsUndefined());
5813  }
5814
5815  env2.Dispose();
5816  env3.Dispose();
5817}
5818
5819
5820TEST(DetachAndReattachGlobal) {
5821  v8::HandleScope scope;
5822  LocalContext env1;
5823
5824  // Create second environment.
5825  v8::Persistent<Context> env2 = Context::New();
5826
5827  Local<Value> foo = v8_str("foo");
5828
5829  // Set same security token for env1 and env2.
5830  env1->SetSecurityToken(foo);
5831  env2->SetSecurityToken(foo);
5832
5833  // Create a property on the global object in env2.
5834  {
5835    v8::Context::Scope scope(env2);
5836    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5837  }
5838
5839  // Create a reference to env2 global from env1 global.
5840  env1->Global()->Set(v8_str("other"), env2->Global());
5841
5842  // Check that we have access to other.p in env2 from env1.
5843  Local<Value> result = CompileRun("other.p");
5844  CHECK(result->IsInt32());
5845  CHECK_EQ(42, result->Int32Value());
5846
5847  // Hold on to global from env2 and detach global from env2.
5848  Local<v8::Object> global2 = env2->Global();
5849  env2->DetachGlobal();
5850
5851  // Check that the global has been detached. No other.p property can
5852  // be found.
5853  result = CompileRun("other.p");
5854  CHECK(result->IsUndefined());
5855
5856  // Reuse global2 for env3.
5857  v8::Persistent<Context> env3 =
5858      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5859  CHECK_EQ(global2, env3->Global());
5860
5861  // Start by using the same security token for env3 as for env1 and env2.
5862  env3->SetSecurityToken(foo);
5863
5864  // Create a property on the global object in env3.
5865  {
5866    v8::Context::Scope scope(env3);
5867    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5868  }
5869
5870  // Check that other.p is now the property in env3 and that we have access.
5871  result = CompileRun("other.p");
5872  CHECK(result->IsInt32());
5873  CHECK_EQ(24, result->Int32Value());
5874
5875  // Change security token for env3 to something different from env1 and env2.
5876  env3->SetSecurityToken(v8_str("bar"));
5877
5878  // Check that we do not have access to other.p in env1. |other| is now
5879  // the global object for env3 which has a different security token,
5880  // so access should be blocked.
5881  result = CompileRun("other.p");
5882  CHECK(result->IsUndefined());
5883
5884  // Detach the global for env3 and reattach it to env2.
5885  env3->DetachGlobal();
5886  env2->ReattachGlobal(global2);
5887
5888  // Check that we have access to other.p again in env1.  |other| is now
5889  // the global object for env2 which has the same security token as env1.
5890  result = CompileRun("other.p");
5891  CHECK(result->IsInt32());
5892  CHECK_EQ(42, result->Int32Value());
5893
5894  env2.Dispose();
5895  env3.Dispose();
5896}
5897
5898
5899static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
5900static bool NamedAccessBlocker(Local<v8::Object> global,
5901                               Local<Value> name,
5902                               v8::AccessType type,
5903                               Local<Value> data) {
5904  return Context::GetCurrent()->Global()->Equals(global) ||
5905      allowed_access_type[type];
5906}
5907
5908
5909static bool IndexedAccessBlocker(Local<v8::Object> global,
5910                                 uint32_t key,
5911                                 v8::AccessType type,
5912                                 Local<Value> data) {
5913  return Context::GetCurrent()->Global()->Equals(global) ||
5914      allowed_access_type[type];
5915}
5916
5917
5918static int g_echo_value = -1;
5919static v8::Handle<Value> EchoGetter(Local<String> name,
5920                                    const AccessorInfo& info) {
5921  return v8_num(g_echo_value);
5922}
5923
5924
5925static void EchoSetter(Local<String> name,
5926                       Local<Value> value,
5927                       const AccessorInfo&) {
5928  if (value->IsNumber())
5929    g_echo_value = value->Int32Value();
5930}
5931
5932
5933static v8::Handle<Value> UnreachableGetter(Local<String> name,
5934                                           const AccessorInfo& info) {
5935  CHECK(false);  // This function should not be called..
5936  return v8::Undefined();
5937}
5938
5939
5940static void UnreachableSetter(Local<String>, Local<Value>,
5941                              const AccessorInfo&) {
5942  CHECK(false);  // This function should nto be called.
5943}
5944
5945
5946TEST(AccessControl) {
5947  v8::HandleScope handle_scope;
5948  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5949
5950  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5951                                           IndexedAccessBlocker);
5952
5953  // Add an accessor accessible by cross-domain JS code.
5954  global_template->SetAccessor(
5955      v8_str("accessible_prop"),
5956      EchoGetter, EchoSetter,
5957      v8::Handle<Value>(),
5958      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5959
5960  // Add an accessor that is not accessible by cross-domain JS code.
5961  global_template->SetAccessor(v8_str("blocked_prop"),
5962                               UnreachableGetter, UnreachableSetter,
5963                               v8::Handle<Value>(),
5964                               v8::DEFAULT);
5965
5966  // Create an environment
5967  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5968  context0->Enter();
5969
5970  v8::Handle<v8::Object> global0 = context0->Global();
5971
5972  // Define a property with JS getter and setter.
5973  CompileRun(
5974      "function getter() { return 'getter'; };\n"
5975      "function setter() { return 'setter'; }\n"
5976      "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5977
5978  Local<Value> getter = global0->Get(v8_str("getter"));
5979  Local<Value> setter = global0->Get(v8_str("setter"));
5980
5981  // And define normal element.
5982  global0->Set(239, v8_str("239"));
5983
5984  // Define an element with JS getter and setter.
5985  CompileRun(
5986      "function el_getter() { return 'el_getter'; };\n"
5987      "function el_setter() { return 'el_setter'; };\n"
5988      "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5989
5990  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5991  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5992
5993  v8::HandleScope scope1;
5994
5995  v8::Persistent<Context> context1 = Context::New();
5996  context1->Enter();
5997
5998  v8::Handle<v8::Object> global1 = context1->Global();
5999  global1->Set(v8_str("other"), global0);
6000
6001  // Access blocked property.
6002  CompileRun("other.blocked_prop = 1");
6003
6004  ExpectUndefined("other.blocked_prop");
6005  ExpectUndefined(
6006      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6007  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6008
6009  // Enable ACCESS_HAS
6010  allowed_access_type[v8::ACCESS_HAS] = true;
6011  ExpectUndefined("other.blocked_prop");
6012  // ... and now we can get the descriptor...
6013  ExpectUndefined(
6014      "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6015  // ... and enumerate the property.
6016  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6017  allowed_access_type[v8::ACCESS_HAS] = false;
6018
6019  // Access blocked element.
6020  CompileRun("other[239] = 1");
6021
6022  ExpectUndefined("other[239]");
6023  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6024  ExpectFalse("propertyIsEnumerable.call(other, '239')");
6025
6026  // Enable ACCESS_HAS
6027  allowed_access_type[v8::ACCESS_HAS] = true;
6028  ExpectUndefined("other[239]");
6029  // ... and now we can get the descriptor...
6030  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6031  // ... and enumerate the property.
6032  ExpectTrue("propertyIsEnumerable.call(other, '239')");
6033  allowed_access_type[v8::ACCESS_HAS] = false;
6034
6035  // Access a property with JS accessor.
6036  CompileRun("other.js_accessor_p = 2");
6037
6038  ExpectUndefined("other.js_accessor_p");
6039  ExpectUndefined(
6040      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6041
6042  // Enable ACCESS_HAS.
6043  allowed_access_type[v8::ACCESS_HAS] = true;
6044  ExpectUndefined("other.js_accessor_p");
6045  ExpectUndefined(
6046      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6047  ExpectUndefined(
6048      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6049  ExpectUndefined(
6050      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6051  allowed_access_type[v8::ACCESS_HAS] = false;
6052
6053  // Enable both ACCESS_HAS and ACCESS_GET.
6054  allowed_access_type[v8::ACCESS_HAS] = true;
6055  allowed_access_type[v8::ACCESS_GET] = true;
6056
6057  ExpectString("other.js_accessor_p", "getter");
6058  ExpectObject(
6059      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6060  ExpectUndefined(
6061      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6062  ExpectUndefined(
6063      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6064
6065  allowed_access_type[v8::ACCESS_GET] = false;
6066  allowed_access_type[v8::ACCESS_HAS] = false;
6067
6068  // Enable both ACCESS_HAS and ACCESS_SET.
6069  allowed_access_type[v8::ACCESS_HAS] = true;
6070  allowed_access_type[v8::ACCESS_SET] = true;
6071
6072  ExpectUndefined("other.js_accessor_p");
6073  ExpectUndefined(
6074      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6075  ExpectObject(
6076      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6077  ExpectUndefined(
6078      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6079
6080  allowed_access_type[v8::ACCESS_SET] = false;
6081  allowed_access_type[v8::ACCESS_HAS] = false;
6082
6083  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6084  allowed_access_type[v8::ACCESS_HAS] = true;
6085  allowed_access_type[v8::ACCESS_GET] = true;
6086  allowed_access_type[v8::ACCESS_SET] = true;
6087
6088  ExpectString("other.js_accessor_p", "getter");
6089  ExpectObject(
6090      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6091  ExpectObject(
6092      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6093  ExpectUndefined(
6094      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6095
6096  allowed_access_type[v8::ACCESS_SET] = false;
6097  allowed_access_type[v8::ACCESS_GET] = false;
6098  allowed_access_type[v8::ACCESS_HAS] = false;
6099
6100  // Access an element with JS accessor.
6101  CompileRun("other[42] = 2");
6102
6103  ExpectUndefined("other[42]");
6104  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6105
6106  // Enable ACCESS_HAS.
6107  allowed_access_type[v8::ACCESS_HAS] = true;
6108  ExpectUndefined("other[42]");
6109  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6110  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6111  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6112  allowed_access_type[v8::ACCESS_HAS] = false;
6113
6114  // Enable both ACCESS_HAS and ACCESS_GET.
6115  allowed_access_type[v8::ACCESS_HAS] = true;
6116  allowed_access_type[v8::ACCESS_GET] = true;
6117
6118  ExpectString("other[42]", "el_getter");
6119  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6120  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6121  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6122
6123  allowed_access_type[v8::ACCESS_GET] = false;
6124  allowed_access_type[v8::ACCESS_HAS] = false;
6125
6126  // Enable both ACCESS_HAS and ACCESS_SET.
6127  allowed_access_type[v8::ACCESS_HAS] = true;
6128  allowed_access_type[v8::ACCESS_SET] = true;
6129
6130  ExpectUndefined("other[42]");
6131  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6132  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6133  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6134
6135  allowed_access_type[v8::ACCESS_SET] = false;
6136  allowed_access_type[v8::ACCESS_HAS] = false;
6137
6138  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6139  allowed_access_type[v8::ACCESS_HAS] = true;
6140  allowed_access_type[v8::ACCESS_GET] = true;
6141  allowed_access_type[v8::ACCESS_SET] = true;
6142
6143  ExpectString("other[42]", "el_getter");
6144  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6145  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6146  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6147
6148  allowed_access_type[v8::ACCESS_SET] = false;
6149  allowed_access_type[v8::ACCESS_GET] = false;
6150  allowed_access_type[v8::ACCESS_HAS] = false;
6151
6152  v8::Handle<Value> value;
6153
6154  // Access accessible property
6155  value = CompileRun("other.accessible_prop = 3");
6156  CHECK(value->IsNumber());
6157  CHECK_EQ(3, value->Int32Value());
6158  CHECK_EQ(3, g_echo_value);
6159
6160  value = CompileRun("other.accessible_prop");
6161  CHECK(value->IsNumber());
6162  CHECK_EQ(3, value->Int32Value());
6163
6164  value = CompileRun(
6165      "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6166  CHECK(value->IsNumber());
6167  CHECK_EQ(3, value->Int32Value());
6168
6169  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
6170  CHECK(value->IsTrue());
6171
6172  // Enumeration doesn't enumerate accessors from inaccessible objects in
6173  // the prototype chain even if the accessors are in themselves accessible.
6174  value =
6175      CompileRun("(function(){var obj = {'__proto__':other};"
6176                 "for (var p in obj)"
6177                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
6178                 "     return false;"
6179                 "   }"
6180                 "return true;})()");
6181  CHECK(value->IsTrue());
6182
6183  context1->Exit();
6184  context0->Exit();
6185  context1.Dispose();
6186  context0.Dispose();
6187}
6188
6189
6190TEST(AccessControlES5) {
6191  v8::HandleScope handle_scope;
6192  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6193
6194  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6195                                           IndexedAccessBlocker);
6196
6197  // Add accessible accessor.
6198  global_template->SetAccessor(
6199      v8_str("accessible_prop"),
6200      EchoGetter, EchoSetter,
6201      v8::Handle<Value>(),
6202      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6203
6204
6205  // Add an accessor that is not accessible by cross-domain JS code.
6206  global_template->SetAccessor(v8_str("blocked_prop"),
6207                               UnreachableGetter, UnreachableSetter,
6208                               v8::Handle<Value>(),
6209                               v8::DEFAULT);
6210
6211  // Create an environment
6212  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6213  context0->Enter();
6214
6215  v8::Handle<v8::Object> global0 = context0->Global();
6216
6217  v8::Persistent<Context> context1 = Context::New();
6218  context1->Enter();
6219  v8::Handle<v8::Object> global1 = context1->Global();
6220  global1->Set(v8_str("other"), global0);
6221
6222  // Regression test for issue 1154.
6223  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6224
6225  ExpectUndefined("other.blocked_prop");
6226
6227  // Regression test for issue 1027.
6228  CompileRun("Object.defineProperty(\n"
6229             "  other, 'blocked_prop', {configurable: false})");
6230  ExpectUndefined("other.blocked_prop");
6231  ExpectUndefined(
6232      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6233
6234  // Regression test for issue 1171.
6235  ExpectTrue("Object.isExtensible(other)");
6236  CompileRun("Object.preventExtensions(other)");
6237  ExpectTrue("Object.isExtensible(other)");
6238
6239  // Object.seal and Object.freeze.
6240  CompileRun("Object.freeze(other)");
6241  ExpectTrue("Object.isExtensible(other)");
6242
6243  CompileRun("Object.seal(other)");
6244  ExpectTrue("Object.isExtensible(other)");
6245
6246  // Regression test for issue 1250.
6247  // Make sure that we can set the accessible accessors value using normal
6248  // assignment.
6249  CompileRun("other.accessible_prop = 42");
6250  CHECK_EQ(42, g_echo_value);
6251
6252  v8::Handle<Value> value;
6253  // We follow Safari in ignoring assignments to host object accessors.
6254  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6255  value = CompileRun("other.accessible_prop == 42");
6256  CHECK(value->IsTrue());
6257}
6258
6259
6260static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6261                                            Local<Value> name,
6262                                            v8::AccessType type,
6263                                            Local<Value> data) {
6264  return false;
6265}
6266
6267
6268static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6269                                              uint32_t key,
6270                                              v8::AccessType type,
6271                                              Local<Value> data) {
6272  return false;
6273}
6274
6275
6276THREADED_TEST(AccessControlGetOwnPropertyNames) {
6277  v8::HandleScope handle_scope;
6278  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6279
6280  obj_template->Set(v8_str("x"), v8::Integer::New(42));
6281  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6282                                        GetOwnPropertyNamesIndexedBlocker);
6283
6284  // Create an environment
6285  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6286  context0->Enter();
6287
6288  v8::Handle<v8::Object> global0 = context0->Global();
6289
6290  v8::HandleScope scope1;
6291
6292  v8::Persistent<Context> context1 = Context::New();
6293  context1->Enter();
6294
6295  v8::Handle<v8::Object> global1 = context1->Global();
6296  global1->Set(v8_str("other"), global0);
6297  global1->Set(v8_str("object"), obj_template->NewInstance());
6298
6299  v8::Handle<Value> value;
6300
6301  // Attempt to get the property names of the other global object and
6302  // of an object that requires access checks.  Accessing the other
6303  // global object should be blocked by access checks on the global
6304  // proxy object.  Accessing the object that requires access checks
6305  // is blocked by the access checks on the object itself.
6306  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6307  CHECK(value->IsTrue());
6308
6309  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6310  CHECK(value->IsTrue());
6311
6312  context1->Exit();
6313  context0->Exit();
6314  context1.Dispose();
6315  context0.Dispose();
6316}
6317
6318
6319static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6320  v8::Handle<v8::Array> result = v8::Array::New(1);
6321  result->Set(0, v8_str("x"));
6322  return result;
6323}
6324
6325
6326THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6327  v8::HandleScope handle_scope;
6328  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6329
6330  obj_template->Set(v8_str("x"), v8::Integer::New(42));
6331  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6332                                        NamedPropertyEnumerator);
6333
6334  LocalContext context;
6335  v8::Handle<v8::Object> global = context->Global();
6336  global->Set(v8_str("object"), obj_template->NewInstance());
6337
6338  v8::Handle<Value> value =
6339      CompileRun("Object.getOwnPropertyNames(object).join(',')");
6340  CHECK_EQ(v8_str("x"), value);
6341}
6342
6343
6344static v8::Handle<Value> ConstTenGetter(Local<String> name,
6345                                        const AccessorInfo& info) {
6346  return v8_num(10);
6347}
6348
6349
6350THREADED_TEST(CrossDomainAccessors) {
6351  v8::HandleScope handle_scope;
6352
6353  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6354
6355  v8::Handle<v8::ObjectTemplate> global_template =
6356      func_template->InstanceTemplate();
6357
6358  v8::Handle<v8::ObjectTemplate> proto_template =
6359      func_template->PrototypeTemplate();
6360
6361  // Add an accessor to proto that's accessible by cross-domain JS code.
6362  proto_template->SetAccessor(v8_str("accessible"),
6363                              ConstTenGetter, 0,
6364                              v8::Handle<Value>(),
6365                              v8::ALL_CAN_READ);
6366
6367  // Add an accessor that is not accessible by cross-domain JS code.
6368  global_template->SetAccessor(v8_str("unreachable"),
6369                               UnreachableGetter, 0,
6370                               v8::Handle<Value>(),
6371                               v8::DEFAULT);
6372
6373  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6374  context0->Enter();
6375
6376  Local<v8::Object> global = context0->Global();
6377  // Add a normal property that shadows 'accessible'
6378  global->Set(v8_str("accessible"), v8_num(11));
6379
6380  // Enter a new context.
6381  v8::HandleScope scope1;
6382  v8::Persistent<Context> context1 = Context::New();
6383  context1->Enter();
6384
6385  v8::Handle<v8::Object> global1 = context1->Global();
6386  global1->Set(v8_str("other"), global);
6387
6388  // Should return 10, instead of 11
6389  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6390  CHECK(value->IsNumber());
6391  CHECK_EQ(10, value->Int32Value());
6392
6393  value = v8_compile("other.unreachable")->Run();
6394  CHECK(value->IsUndefined());
6395
6396  context1->Exit();
6397  context0->Exit();
6398  context1.Dispose();
6399  context0.Dispose();
6400}
6401
6402
6403static int named_access_count = 0;
6404static int indexed_access_count = 0;
6405
6406static bool NamedAccessCounter(Local<v8::Object> global,
6407                               Local<Value> name,
6408                               v8::AccessType type,
6409                               Local<Value> data) {
6410  named_access_count++;
6411  return true;
6412}
6413
6414
6415static bool IndexedAccessCounter(Local<v8::Object> global,
6416                                 uint32_t key,
6417                                 v8::AccessType type,
6418                                 Local<Value> data) {
6419  indexed_access_count++;
6420  return true;
6421}
6422
6423
6424// This one is too easily disturbed by other tests.
6425TEST(AccessControlIC) {
6426  named_access_count = 0;
6427  indexed_access_count = 0;
6428
6429  v8::HandleScope handle_scope;
6430
6431  // Create an environment.
6432  v8::Persistent<Context> context0 = Context::New();
6433  context0->Enter();
6434
6435  // Create an object that requires access-check functions to be
6436  // called for cross-domain access.
6437  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6438  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6439                                           IndexedAccessCounter);
6440  Local<v8::Object> object = object_template->NewInstance();
6441
6442  v8::HandleScope scope1;
6443
6444  // Create another environment.
6445  v8::Persistent<Context> context1 = Context::New();
6446  context1->Enter();
6447
6448  // Make easy access to the object from the other environment.
6449  v8::Handle<v8::Object> global1 = context1->Global();
6450  global1->Set(v8_str("obj"), object);
6451
6452  v8::Handle<Value> value;
6453
6454  // Check that the named access-control function is called every time.
6455  CompileRun("function testProp(obj) {"
6456             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
6457             "  for (var j = 0; j < 10; j++) obj.prop;"
6458             "  return obj.prop"
6459             "}");
6460  value = CompileRun("testProp(obj)");
6461  CHECK(value->IsNumber());
6462  CHECK_EQ(1, value->Int32Value());
6463  CHECK_EQ(21, named_access_count);
6464
6465  // Check that the named access-control function is called every time.
6466  CompileRun("var p = 'prop';"
6467             "function testKeyed(obj) {"
6468             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
6469             "  for (var j = 0; j < 10; j++) obj[p];"
6470             "  return obj[p];"
6471             "}");
6472  // Use obj which requires access checks.  No inline caching is used
6473  // in that case.
6474  value = CompileRun("testKeyed(obj)");
6475  CHECK(value->IsNumber());
6476  CHECK_EQ(1, value->Int32Value());
6477  CHECK_EQ(42, named_access_count);
6478  // Force the inline caches into generic state and try again.
6479  CompileRun("testKeyed({ a: 0 })");
6480  CompileRun("testKeyed({ b: 0 })");
6481  value = CompileRun("testKeyed(obj)");
6482  CHECK(value->IsNumber());
6483  CHECK_EQ(1, value->Int32Value());
6484  CHECK_EQ(63, named_access_count);
6485
6486  // Check that the indexed access-control function is called every time.
6487  CompileRun("function testIndexed(obj) {"
6488             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
6489             "  for (var j = 0; j < 10; j++) obj[0];"
6490             "  return obj[0]"
6491             "}");
6492  value = CompileRun("testIndexed(obj)");
6493  CHECK(value->IsNumber());
6494  CHECK_EQ(1, value->Int32Value());
6495  CHECK_EQ(21, indexed_access_count);
6496  // Force the inline caches into generic state.
6497  CompileRun("testIndexed(new Array(1))");
6498  // Test that the indexed access check is called.
6499  value = CompileRun("testIndexed(obj)");
6500  CHECK(value->IsNumber());
6501  CHECK_EQ(1, value->Int32Value());
6502  CHECK_EQ(42, indexed_access_count);
6503
6504  // Check that the named access check is called when invoking
6505  // functions on an object that requires access checks.
6506  CompileRun("obj.f = function() {}");
6507  CompileRun("function testCallNormal(obj) {"
6508             "  for (var i = 0; i < 10; i++) obj.f();"
6509             "}");
6510  CompileRun("testCallNormal(obj)");
6511  CHECK_EQ(74, named_access_count);
6512
6513  // Force obj into slow case.
6514  value = CompileRun("delete obj.prop");
6515  CHECK(value->BooleanValue());
6516  // Force inline caches into dictionary probing mode.
6517  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6518  // Test that the named access check is called.
6519  value = CompileRun("testProp(obj);");
6520  CHECK(value->IsNumber());
6521  CHECK_EQ(1, value->Int32Value());
6522  CHECK_EQ(96, named_access_count);
6523
6524  // Force the call inline cache into dictionary probing mode.
6525  CompileRun("o.f = function() {}; testCallNormal(o)");
6526  // Test that the named access check is still called for each
6527  // invocation of the function.
6528  value = CompileRun("testCallNormal(obj)");
6529  CHECK_EQ(106, named_access_count);
6530
6531  context1->Exit();
6532  context0->Exit();
6533  context1.Dispose();
6534  context0.Dispose();
6535}
6536
6537
6538static bool NamedAccessFlatten(Local<v8::Object> global,
6539                               Local<Value> name,
6540                               v8::AccessType type,
6541                               Local<Value> data) {
6542  char buf[100];
6543  int len;
6544
6545  CHECK(name->IsString());
6546
6547  memset(buf, 0x1, sizeof(buf));
6548  len = name.As<String>()->WriteAscii(buf);
6549  CHECK_EQ(4, len);
6550
6551  uint16_t buf2[100];
6552
6553  memset(buf, 0x1, sizeof(buf));
6554  len = name.As<String>()->Write(buf2);
6555  CHECK_EQ(4, len);
6556
6557  return true;
6558}
6559
6560
6561static bool IndexedAccessFlatten(Local<v8::Object> global,
6562                                 uint32_t key,
6563                                 v8::AccessType type,
6564                                 Local<Value> data) {
6565  return true;
6566}
6567
6568
6569// Regression test.  In access checks, operations that may cause
6570// garbage collection are not allowed.  It used to be the case that
6571// using the Write operation on a string could cause a garbage
6572// collection due to flattening of the string.  This is no longer the
6573// case.
6574THREADED_TEST(AccessControlFlatten) {
6575  named_access_count = 0;
6576  indexed_access_count = 0;
6577
6578  v8::HandleScope handle_scope;
6579
6580  // Create an environment.
6581  v8::Persistent<Context> context0 = Context::New();
6582  context0->Enter();
6583
6584  // Create an object that requires access-check functions to be
6585  // called for cross-domain access.
6586  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6587  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6588                                           IndexedAccessFlatten);
6589  Local<v8::Object> object = object_template->NewInstance();
6590
6591  v8::HandleScope scope1;
6592
6593  // Create another environment.
6594  v8::Persistent<Context> context1 = Context::New();
6595  context1->Enter();
6596
6597  // Make easy access to the object from the other environment.
6598  v8::Handle<v8::Object> global1 = context1->Global();
6599  global1->Set(v8_str("obj"), object);
6600
6601  v8::Handle<Value> value;
6602
6603  value = v8_compile("var p = 'as' + 'df';")->Run();
6604  value = v8_compile("obj[p];")->Run();
6605
6606  context1->Exit();
6607  context0->Exit();
6608  context1.Dispose();
6609  context0.Dispose();
6610}
6611
6612
6613static v8::Handle<Value> AccessControlNamedGetter(
6614    Local<String>, const AccessorInfo&) {
6615  return v8::Integer::New(42);
6616}
6617
6618
6619static v8::Handle<Value> AccessControlNamedSetter(
6620    Local<String>, Local<Value> value, const AccessorInfo&) {
6621  return value;
6622}
6623
6624
6625static v8::Handle<Value> AccessControlIndexedGetter(
6626      uint32_t index,
6627      const AccessorInfo& info) {
6628  return v8_num(42);
6629}
6630
6631
6632static v8::Handle<Value> AccessControlIndexedSetter(
6633    uint32_t, Local<Value> value, const AccessorInfo&) {
6634  return value;
6635}
6636
6637
6638THREADED_TEST(AccessControlInterceptorIC) {
6639  named_access_count = 0;
6640  indexed_access_count = 0;
6641
6642  v8::HandleScope handle_scope;
6643
6644  // Create an environment.
6645  v8::Persistent<Context> context0 = Context::New();
6646  context0->Enter();
6647
6648  // Create an object that requires access-check functions to be
6649  // called for cross-domain access.  The object also has interceptors
6650  // interceptor.
6651  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6652  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6653                                           IndexedAccessCounter);
6654  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6655                                           AccessControlNamedSetter);
6656  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6657                                             AccessControlIndexedSetter);
6658  Local<v8::Object> object = object_template->NewInstance();
6659
6660  v8::HandleScope scope1;
6661
6662  // Create another environment.
6663  v8::Persistent<Context> context1 = Context::New();
6664  context1->Enter();
6665
6666  // Make easy access to the object from the other environment.
6667  v8::Handle<v8::Object> global1 = context1->Global();
6668  global1->Set(v8_str("obj"), object);
6669
6670  v8::Handle<Value> value;
6671
6672  // Check that the named access-control function is called every time
6673  // eventhough there is an interceptor on the object.
6674  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6675  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6676                     "obj.x")->Run();
6677  CHECK(value->IsNumber());
6678  CHECK_EQ(42, value->Int32Value());
6679  CHECK_EQ(21, named_access_count);
6680
6681  value = v8_compile("var p = 'x';")->Run();
6682  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6683  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6684                     "obj[p]")->Run();
6685  CHECK(value->IsNumber());
6686  CHECK_EQ(42, value->Int32Value());
6687  CHECK_EQ(42, named_access_count);
6688
6689  // Check that the indexed access-control function is called every
6690  // time eventhough there is an interceptor on the object.
6691  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6692  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6693                     "obj[0]")->Run();
6694  CHECK(value->IsNumber());
6695  CHECK_EQ(42, value->Int32Value());
6696  CHECK_EQ(21, indexed_access_count);
6697
6698  context1->Exit();
6699  context0->Exit();
6700  context1.Dispose();
6701  context0.Dispose();
6702}
6703
6704
6705THREADED_TEST(Version) {
6706  v8::V8::GetVersion();
6707}
6708
6709
6710static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6711  ApiTestFuzzer::Fuzz();
6712  return v8_num(12);
6713}
6714
6715
6716THREADED_TEST(InstanceProperties) {
6717  v8::HandleScope handle_scope;
6718  LocalContext context;
6719
6720  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6721  Local<ObjectTemplate> instance = t->InstanceTemplate();
6722
6723  instance->Set(v8_str("x"), v8_num(42));
6724  instance->Set(v8_str("f"),
6725                v8::FunctionTemplate::New(InstanceFunctionCallback));
6726
6727  Local<Value> o = t->GetFunction()->NewInstance();
6728
6729  context->Global()->Set(v8_str("i"), o);
6730  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6731  CHECK_EQ(42, value->Int32Value());
6732
6733  value = Script::Compile(v8_str("i.f()"))->Run();
6734  CHECK_EQ(12, value->Int32Value());
6735}
6736
6737
6738static v8::Handle<Value>
6739GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6740  ApiTestFuzzer::Fuzz();
6741  return v8::Handle<Value>();
6742}
6743
6744
6745THREADED_TEST(GlobalObjectInstanceProperties) {
6746  v8::HandleScope handle_scope;
6747
6748  Local<Value> global_object;
6749
6750  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6751  t->InstanceTemplate()->SetNamedPropertyHandler(
6752      GlobalObjectInstancePropertiesGet);
6753  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6754  instance_template->Set(v8_str("x"), v8_num(42));
6755  instance_template->Set(v8_str("f"),
6756                         v8::FunctionTemplate::New(InstanceFunctionCallback));
6757
6758  // The script to check how Crankshaft compiles missing global function
6759  // invocations.  function g is not defined and should throw on call.
6760  const char* script =
6761      "function wrapper(call) {"
6762      "  var x = 0, y = 1;"
6763      "  for (var i = 0; i < 1000; i++) {"
6764      "    x += i * 100;"
6765      "    y += i * 100;"
6766      "  }"
6767      "  if (call) g();"
6768      "}"
6769      "for (var i = 0; i < 17; i++) wrapper(false);"
6770      "var thrown = 0;"
6771      "try { wrapper(true); } catch (e) { thrown = 1; };"
6772      "thrown";
6773
6774  {
6775    LocalContext env(NULL, instance_template);
6776    // Hold on to the global object so it can be used again in another
6777    // environment initialization.
6778    global_object = env->Global();
6779
6780    Local<Value> value = Script::Compile(v8_str("x"))->Run();
6781    CHECK_EQ(42, value->Int32Value());
6782    value = Script::Compile(v8_str("f()"))->Run();
6783    CHECK_EQ(12, value->Int32Value());
6784    value = Script::Compile(v8_str(script))->Run();
6785    CHECK_EQ(1, value->Int32Value());
6786  }
6787
6788  {
6789    // Create new environment reusing the global object.
6790    LocalContext env(NULL, instance_template, global_object);
6791    Local<Value> value = Script::Compile(v8_str("x"))->Run();
6792    CHECK_EQ(42, value->Int32Value());
6793    value = Script::Compile(v8_str("f()"))->Run();
6794    CHECK_EQ(12, value->Int32Value());
6795    value = Script::Compile(v8_str(script))->Run();
6796    CHECK_EQ(1, value->Int32Value());
6797  }
6798}
6799
6800
6801THREADED_TEST(CallKnownGlobalReceiver) {
6802  v8::HandleScope handle_scope;
6803
6804  Local<Value> global_object;
6805
6806  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6807  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6808
6809  // The script to check that we leave global object not
6810  // global object proxy on stack when we deoptimize from inside
6811  // arguments evaluation.
6812  // To provoke error we need to both force deoptimization
6813  // from arguments evaluation and to force CallIC to take
6814  // CallIC_Miss code path that can't cope with global proxy.
6815  const char* script =
6816      "function bar(x, y) { try { } finally { } }"
6817      "function baz(x) { try { } finally { } }"
6818      "function bom(x) { try { } finally { } }"
6819      "function foo(x) { bar([x], bom(2)); }"
6820      "for (var i = 0; i < 10000; i++) foo(1);"
6821      "foo";
6822
6823  Local<Value> foo;
6824  {
6825    LocalContext env(NULL, instance_template);
6826    // Hold on to the global object so it can be used again in another
6827    // environment initialization.
6828    global_object = env->Global();
6829    foo = Script::Compile(v8_str(script))->Run();
6830  }
6831
6832  {
6833    // Create new environment reusing the global object.
6834    LocalContext env(NULL, instance_template, global_object);
6835    env->Global()->Set(v8_str("foo"), foo);
6836    Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
6837  }
6838}
6839
6840
6841static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6842  ApiTestFuzzer::Fuzz();
6843  return v8_num(42);
6844}
6845
6846
6847static int shadow_y;
6848static int shadow_y_setter_call_count;
6849static int shadow_y_getter_call_count;
6850
6851
6852static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
6853  shadow_y_setter_call_count++;
6854  shadow_y = 42;
6855}
6856
6857
6858static v8::Handle<Value> ShadowYGetter(Local<String> name,
6859                                       const AccessorInfo& info) {
6860  ApiTestFuzzer::Fuzz();
6861  shadow_y_getter_call_count++;
6862  return v8_num(shadow_y);
6863}
6864
6865
6866static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6867                                          const AccessorInfo& info) {
6868  return v8::Handle<Value>();
6869}
6870
6871
6872static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6873                                        const AccessorInfo&) {
6874  return v8::Handle<Value>();
6875}
6876
6877
6878THREADED_TEST(ShadowObject) {
6879  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6880  v8::HandleScope handle_scope;
6881
6882  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6883  LocalContext context(NULL, global_template);
6884
6885  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6886  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6887  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6888  Local<ObjectTemplate> proto = t->PrototypeTemplate();
6889  Local<ObjectTemplate> instance = t->InstanceTemplate();
6890
6891  // Only allow calls of f on instances of t.
6892  Local<v8::Signature> signature = v8::Signature::New(t);
6893  proto->Set(v8_str("f"),
6894             v8::FunctionTemplate::New(ShadowFunctionCallback,
6895                                       Local<Value>(),
6896                                       signature));
6897  proto->Set(v8_str("x"), v8_num(12));
6898
6899  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6900
6901  Local<Value> o = t->GetFunction()->NewInstance();
6902  context->Global()->Set(v8_str("__proto__"), o);
6903
6904  Local<Value> value =
6905      Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
6906  CHECK(value->IsBoolean());
6907  CHECK(!value->BooleanValue());
6908
6909  value = Script::Compile(v8_str("x"))->Run();
6910  CHECK_EQ(12, value->Int32Value());
6911
6912  value = Script::Compile(v8_str("f()"))->Run();
6913  CHECK_EQ(42, value->Int32Value());
6914
6915  Script::Compile(v8_str("y = 42"))->Run();
6916  CHECK_EQ(1, shadow_y_setter_call_count);
6917  value = Script::Compile(v8_str("y"))->Run();
6918  CHECK_EQ(1, shadow_y_getter_call_count);
6919  CHECK_EQ(42, value->Int32Value());
6920}
6921
6922
6923THREADED_TEST(HiddenPrototype) {
6924  v8::HandleScope handle_scope;
6925  LocalContext context;
6926
6927  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6928  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6929  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6930  t1->SetHiddenPrototype(true);
6931  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6932  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6933  t2->SetHiddenPrototype(true);
6934  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6935  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6936  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6937
6938  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6939  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6940  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6941  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6942
6943  // Setting the prototype on an object skips hidden prototypes.
6944  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6945  o0->Set(v8_str("__proto__"), o1);
6946  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6947  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6948  o0->Set(v8_str("__proto__"), o2);
6949  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6950  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6951  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6952  o0->Set(v8_str("__proto__"), o3);
6953  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6954  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6955  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6956  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6957
6958  // Getting the prototype of o0 should get the first visible one
6959  // which is o3.  Therefore, z should not be defined on the prototype
6960  // object.
6961  Local<Value> proto = o0->Get(v8_str("__proto__"));
6962  CHECK(proto->IsObject());
6963  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
6964}
6965
6966
6967THREADED_TEST(SetPrototype) {
6968  v8::HandleScope handle_scope;
6969  LocalContext context;
6970
6971  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6972  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6973  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6974  t1->SetHiddenPrototype(true);
6975  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6976  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6977  t2->SetHiddenPrototype(true);
6978  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6979  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6980  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6981
6982  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6983  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6984  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6985  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6986
6987  // Setting the prototype on an object does not skip hidden prototypes.
6988  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6989  CHECK(o0->SetPrototype(o1));
6990  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6991  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6992  CHECK(o1->SetPrototype(o2));
6993  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6994  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6995  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6996  CHECK(o2->SetPrototype(o3));
6997  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6998  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6999  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7000  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7001
7002  // Getting the prototype of o0 should get the first visible one
7003  // which is o3.  Therefore, z should not be defined on the prototype
7004  // object.
7005  Local<Value> proto = o0->Get(v8_str("__proto__"));
7006  CHECK(proto->IsObject());
7007  CHECK_EQ(proto.As<v8::Object>(), o3);
7008
7009  // However, Object::GetPrototype ignores hidden prototype.
7010  Local<Value> proto0 = o0->GetPrototype();
7011  CHECK(proto0->IsObject());
7012  CHECK_EQ(proto0.As<v8::Object>(), o1);
7013
7014  Local<Value> proto1 = o1->GetPrototype();
7015  CHECK(proto1->IsObject());
7016  CHECK_EQ(proto1.As<v8::Object>(), o2);
7017
7018  Local<Value> proto2 = o2->GetPrototype();
7019  CHECK(proto2->IsObject());
7020  CHECK_EQ(proto2.As<v8::Object>(), o3);
7021}
7022
7023
7024THREADED_TEST(SetPrototypeProperties) {
7025  v8::HandleScope handle_scope;
7026  LocalContext context;
7027
7028  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7029  t1->SetPrototypeAttributes(v8::DontDelete);
7030  context->Global()->Set(v8_str("func1"), t1->GetFunction());
7031  CHECK(CompileRun(
7032      "(function() {"
7033      "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7034      "  return (descriptor['writable'] == true) &&"
7035      "         (descriptor['enumerable'] == true) &&"
7036      "         (descriptor['configurable'] == false);"
7037      "})()")->BooleanValue());
7038
7039  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7040  t2->SetPrototypeAttributes(v8::DontEnum);
7041  context->Global()->Set(v8_str("func2"), t2->GetFunction());
7042  CHECK(CompileRun(
7043      "(function() {"
7044      "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7045      "  return (descriptor['writable'] == true) &&"
7046      "         (descriptor['enumerable'] == false) &&"
7047      "         (descriptor['configurable'] == true);"
7048      "})()")->BooleanValue());
7049
7050  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7051  t3->SetPrototypeAttributes(v8::ReadOnly);
7052  context->Global()->Set(v8_str("func3"), t3->GetFunction());
7053  CHECK(CompileRun(
7054      "(function() {"
7055      "  descriptor = Object.getOwnPropertyDescriptor(func3, 'prototype');"
7056      "  return (descriptor['writable'] == false) &&"
7057      "         (descriptor['enumerable'] == true) &&"
7058      "         (descriptor['configurable'] == true);"
7059      "})()")->BooleanValue());
7060
7061  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7062  t4->SetPrototypeAttributes(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
7063  context->Global()->Set(v8_str("func4"), t4->GetFunction());
7064  CHECK(CompileRun(
7065      "(function() {"
7066      "  descriptor = Object.getOwnPropertyDescriptor(func4, 'prototype');"
7067      "  return (descriptor['writable'] == false) &&"
7068      "         (descriptor['enumerable'] == false) &&"
7069      "         (descriptor['configurable'] == false);"
7070      "})()")->BooleanValue());
7071}
7072
7073
7074THREADED_TEST(SetPrototypeThrows) {
7075  v8::HandleScope handle_scope;
7076  LocalContext context;
7077
7078  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7079
7080  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7081  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7082
7083  CHECK(o0->SetPrototype(o1));
7084  // If setting the prototype leads to the cycle, SetPrototype should
7085  // return false and keep VM in sane state.
7086  v8::TryCatch try_catch;
7087  CHECK(!o1->SetPrototype(o0));
7088  CHECK(!try_catch.HasCaught());
7089  ASSERT(!i::Isolate::Current()->has_pending_exception());
7090
7091  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7092}
7093
7094
7095THREADED_TEST(GetterSetterExceptions) {
7096  v8::HandleScope handle_scope;
7097  LocalContext context;
7098  CompileRun(
7099    "function Foo() { };"
7100    "function Throw() { throw 5; };"
7101    "var x = { };"
7102    "x.__defineSetter__('set', Throw);"
7103    "x.__defineGetter__('get', Throw);");
7104  Local<v8::Object> x =
7105      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7106  v8::TryCatch try_catch;
7107  x->Set(v8_str("set"), v8::Integer::New(8));
7108  x->Get(v8_str("get"));
7109  x->Set(v8_str("set"), v8::Integer::New(8));
7110  x->Get(v8_str("get"));
7111  x->Set(v8_str("set"), v8::Integer::New(8));
7112  x->Get(v8_str("get"));
7113  x->Set(v8_str("set"), v8::Integer::New(8));
7114  x->Get(v8_str("get"));
7115}
7116
7117
7118THREADED_TEST(Constructor) {
7119  v8::HandleScope handle_scope;
7120  LocalContext context;
7121  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7122  templ->SetClassName(v8_str("Fun"));
7123  Local<Function> cons = templ->GetFunction();
7124  context->Global()->Set(v8_str("Fun"), cons);
7125  Local<v8::Object> inst = cons->NewInstance();
7126  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7127  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7128  CHECK(value->BooleanValue());
7129}
7130
7131
7132static Handle<Value> ConstructorCallback(const Arguments& args) {
7133  ApiTestFuzzer::Fuzz();
7134  Local<Object> This;
7135
7136  if (args.IsConstructCall()) {
7137    Local<Object> Holder = args.Holder();
7138    This = Object::New();
7139    Local<Value> proto = Holder->GetPrototype();
7140    if (proto->IsObject()) {
7141      This->SetPrototype(proto);
7142    }
7143  } else {
7144    This = args.This();
7145  }
7146
7147  This->Set(v8_str("a"), args[0]);
7148  return This;
7149}
7150
7151
7152static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7153  ApiTestFuzzer::Fuzz();
7154  return args[0];
7155}
7156
7157
7158THREADED_TEST(ConstructorForObject) {
7159  v8::HandleScope handle_scope;
7160  LocalContext context;
7161
7162  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7163    instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7164    Local<Object> instance = instance_template->NewInstance();
7165    context->Global()->Set(v8_str("obj"), instance);
7166    v8::TryCatch try_catch;
7167    Local<Value> value;
7168    CHECK(!try_catch.HasCaught());
7169
7170    // Call the Object's constructor with a 32-bit signed integer.
7171    value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7172    CHECK(!try_catch.HasCaught());
7173    CHECK(value->IsInt32());
7174    CHECK_EQ(28, value->Int32Value());
7175
7176    Local<Value> args1[] = { v8_num(28) };
7177    Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7178    CHECK(value_obj1->IsObject());
7179    Local<Object> object1 = Local<Object>::Cast(value_obj1);
7180    value = object1->Get(v8_str("a"));
7181    CHECK(value->IsInt32());
7182    CHECK(!try_catch.HasCaught());
7183    CHECK_EQ(28, value->Int32Value());
7184
7185    // Call the Object's constructor with a String.
7186    value = CompileRun(
7187        "(function() { var o = new obj('tipli'); return o.a; })()");
7188    CHECK(!try_catch.HasCaught());
7189    CHECK(value->IsString());
7190    String::AsciiValue string_value1(value->ToString());
7191    CHECK_EQ("tipli", *string_value1);
7192
7193    Local<Value> args2[] = { v8_str("tipli") };
7194    Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7195    CHECK(value_obj2->IsObject());
7196    Local<Object> object2 = Local<Object>::Cast(value_obj2);
7197    value = object2->Get(v8_str("a"));
7198    CHECK(!try_catch.HasCaught());
7199    CHECK(value->IsString());
7200    String::AsciiValue string_value2(value->ToString());
7201    CHECK_EQ("tipli", *string_value2);
7202
7203    // Call the Object's constructor with a Boolean.
7204    value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7205    CHECK(!try_catch.HasCaught());
7206    CHECK(value->IsBoolean());
7207    CHECK_EQ(true, value->BooleanValue());
7208
7209    Handle<Value> args3[] = { v8::Boolean::New(true) };
7210    Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7211    CHECK(value_obj3->IsObject());
7212    Local<Object> object3 = Local<Object>::Cast(value_obj3);
7213    value = object3->Get(v8_str("a"));
7214    CHECK(!try_catch.HasCaught());
7215    CHECK(value->IsBoolean());
7216    CHECK_EQ(true, value->BooleanValue());
7217
7218    // Call the Object's constructor with undefined.
7219    Handle<Value> args4[] = { v8::Undefined() };
7220    Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7221    CHECK(value_obj4->IsObject());
7222    Local<Object> object4 = Local<Object>::Cast(value_obj4);
7223    value = object4->Get(v8_str("a"));
7224    CHECK(!try_catch.HasCaught());
7225    CHECK(value->IsUndefined());
7226
7227    // Call the Object's constructor with null.
7228    Handle<Value> args5[] = { v8::Null() };
7229    Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7230    CHECK(value_obj5->IsObject());
7231    Local<Object> object5 = Local<Object>::Cast(value_obj5);
7232    value = object5->Get(v8_str("a"));
7233    CHECK(!try_catch.HasCaught());
7234    CHECK(value->IsNull());
7235  }
7236
7237  // Check exception handling when there is no constructor set for the Object.
7238  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7239    Local<Object> instance = instance_template->NewInstance();
7240    context->Global()->Set(v8_str("obj2"), instance);
7241    v8::TryCatch try_catch;
7242    Local<Value> value;
7243    CHECK(!try_catch.HasCaught());
7244
7245    value = CompileRun("new obj2(28)");
7246    CHECK(try_catch.HasCaught());
7247    String::AsciiValue exception_value1(try_catch.Exception());
7248    CHECK_EQ("TypeError: object is not a function", *exception_value1);
7249    try_catch.Reset();
7250
7251    Local<Value> args[] = { v8_num(29) };
7252    value = instance->CallAsConstructor(1, args);
7253    CHECK(try_catch.HasCaught());
7254    String::AsciiValue exception_value2(try_catch.Exception());
7255    CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7256    try_catch.Reset();
7257  }
7258
7259  // Check the case when constructor throws exception.
7260  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7261    instance_template->SetCallAsFunctionHandler(ThrowValue);
7262    Local<Object> instance = instance_template->NewInstance();
7263    context->Global()->Set(v8_str("obj3"), instance);
7264    v8::TryCatch try_catch;
7265    Local<Value> value;
7266    CHECK(!try_catch.HasCaught());
7267
7268    value = CompileRun("new obj3(22)");
7269    CHECK(try_catch.HasCaught());
7270    String::AsciiValue exception_value1(try_catch.Exception());
7271    CHECK_EQ("22", *exception_value1);
7272    try_catch.Reset();
7273
7274    Local<Value> args[] = { v8_num(23) };
7275    value = instance->CallAsConstructor(1, args);
7276    CHECK(try_catch.HasCaught());
7277    String::AsciiValue exception_value2(try_catch.Exception());
7278    CHECK_EQ("23", *exception_value2);
7279    try_catch.Reset();
7280  }
7281
7282  // Check whether constructor returns with an object or non-object.
7283  { Local<FunctionTemplate> function_template =
7284        FunctionTemplate::New(FakeConstructorCallback);
7285    Local<Function> function = function_template->GetFunction();
7286    Local<Object> instance1 = function;
7287    context->Global()->Set(v8_str("obj4"), instance1);
7288    v8::TryCatch try_catch;
7289    Local<Value> value;
7290    CHECK(!try_catch.HasCaught());
7291
7292    CHECK(instance1->IsObject());
7293    CHECK(instance1->IsFunction());
7294
7295    value = CompileRun("new obj4(28)");
7296    CHECK(!try_catch.HasCaught());
7297    CHECK(value->IsObject());
7298
7299    Local<Value> args1[] = { v8_num(28) };
7300    value = instance1->CallAsConstructor(1, args1);
7301    CHECK(!try_catch.HasCaught());
7302    CHECK(value->IsObject());
7303
7304    Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7305    instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7306    Local<Object> instance2 = instance_template->NewInstance();
7307    context->Global()->Set(v8_str("obj5"), instance2);
7308    CHECK(!try_catch.HasCaught());
7309
7310    CHECK(instance2->IsObject());
7311    CHECK(!instance2->IsFunction());
7312
7313    value = CompileRun("new obj5(28)");
7314    CHECK(!try_catch.HasCaught());
7315    CHECK(!value->IsObject());
7316
7317    Local<Value> args2[] = { v8_num(28) };
7318    value = instance2->CallAsConstructor(1, args2);
7319    CHECK(!try_catch.HasCaught());
7320    CHECK(!value->IsObject());
7321  }
7322}
7323
7324
7325THREADED_TEST(FunctionDescriptorException) {
7326  v8::HandleScope handle_scope;
7327  LocalContext context;
7328  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7329  templ->SetClassName(v8_str("Fun"));
7330  Local<Function> cons = templ->GetFunction();
7331  context->Global()->Set(v8_str("Fun"), cons);
7332  Local<Value> value = CompileRun(
7333    "function test() {"
7334    "  try {"
7335    "    (new Fun()).blah()"
7336    "  } catch (e) {"
7337    "    var str = String(e);"
7338    "    if (str.indexOf('TypeError') == -1) return 1;"
7339    "    if (str.indexOf('[object Fun]') != -1) return 2;"
7340    "    if (str.indexOf('#<Fun>') == -1) return 3;"
7341    "    return 0;"
7342    "  }"
7343    "  return 4;"
7344    "}"
7345    "test();");
7346  CHECK_EQ(0, value->Int32Value());
7347}
7348
7349
7350THREADED_TEST(EvalAliasedDynamic) {
7351  v8::HandleScope scope;
7352  LocalContext current;
7353
7354  // Tests where aliased eval can only be resolved dynamically.
7355  Local<Script> script =
7356      Script::Compile(v8_str("function f(x) { "
7357                             "  var foo = 2;"
7358                             "  with (x) { return eval('foo'); }"
7359                             "}"
7360                             "foo = 0;"
7361                             "result1 = f(new Object());"
7362                             "result2 = f(this);"
7363                             "var x = new Object();"
7364                             "x.eval = function(x) { return 1; };"
7365                             "result3 = f(x);"));
7366  script->Run();
7367  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7368  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7369  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7370
7371  v8::TryCatch try_catch;
7372  script =
7373    Script::Compile(v8_str("function f(x) { "
7374                           "  var bar = 2;"
7375                           "  with (x) { return eval('bar'); }"
7376                           "}"
7377                           "f(this)"));
7378  script->Run();
7379  CHECK(try_catch.HasCaught());
7380  try_catch.Reset();
7381}
7382
7383
7384THREADED_TEST(CrossEval) {
7385  v8::HandleScope scope;
7386  LocalContext other;
7387  LocalContext current;
7388
7389  Local<String> token = v8_str("<security token>");
7390  other->SetSecurityToken(token);
7391  current->SetSecurityToken(token);
7392
7393  // Setup reference from current to other.
7394  current->Global()->Set(v8_str("other"), other->Global());
7395
7396  // Check that new variables are introduced in other context.
7397  Local<Script> script =
7398      Script::Compile(v8_str("other.eval('var foo = 1234')"));
7399  script->Run();
7400  Local<Value> foo = other->Global()->Get(v8_str("foo"));
7401  CHECK_EQ(1234, foo->Int32Value());
7402  CHECK(!current->Global()->Has(v8_str("foo")));
7403
7404  // Check that writing to non-existing properties introduces them in
7405  // the other context.
7406  script =
7407      Script::Compile(v8_str("other.eval('na = 1234')"));
7408  script->Run();
7409  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7410  CHECK(!current->Global()->Has(v8_str("na")));
7411
7412  // Check that global variables in current context are not visible in other
7413  // context.
7414  v8::TryCatch try_catch;
7415  script =
7416      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7417  Local<Value> result = script->Run();
7418  CHECK(try_catch.HasCaught());
7419  try_catch.Reset();
7420
7421  // Check that local variables in current context are not visible in other
7422  // context.
7423  script =
7424      Script::Compile(v8_str("(function() { "
7425                             "  var baz = 87;"
7426                             "  return other.eval('baz');"
7427                             "})();"));
7428  result = script->Run();
7429  CHECK(try_catch.HasCaught());
7430  try_catch.Reset();
7431
7432  // Check that global variables in the other environment are visible
7433  // when evaluting code.
7434  other->Global()->Set(v8_str("bis"), v8_num(1234));
7435  script = Script::Compile(v8_str("other.eval('bis')"));
7436  CHECK_EQ(1234, script->Run()->Int32Value());
7437  CHECK(!try_catch.HasCaught());
7438
7439  // Check that the 'this' pointer points to the global object evaluating
7440  // code.
7441  other->Global()->Set(v8_str("t"), other->Global());
7442  script = Script::Compile(v8_str("other.eval('this == t')"));
7443  result = script->Run();
7444  CHECK(result->IsTrue());
7445  CHECK(!try_catch.HasCaught());
7446
7447  // Check that variables introduced in with-statement are not visible in
7448  // other context.
7449  script =
7450      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7451  result = script->Run();
7452  CHECK(try_catch.HasCaught());
7453  try_catch.Reset();
7454
7455  // Check that you cannot use 'eval.call' with another object than the
7456  // current global object.
7457  script =
7458      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7459  result = script->Run();
7460  CHECK(try_catch.HasCaught());
7461}
7462
7463
7464// Test that calling eval in a context which has been detached from
7465// its global throws an exception.  This behavior is consistent with
7466// other JavaScript implementations.
7467THREADED_TEST(EvalInDetachedGlobal) {
7468  v8::HandleScope scope;
7469
7470  v8::Persistent<Context> context0 = Context::New();
7471  v8::Persistent<Context> context1 = Context::New();
7472
7473  // Setup function in context0 that uses eval from context0.
7474  context0->Enter();
7475  v8::Handle<v8::Value> fun =
7476      CompileRun("var x = 42;"
7477                 "(function() {"
7478                 "  var e = eval;"
7479                 "  return function(s) { return e(s); }"
7480                 "})()");
7481  context0->Exit();
7482
7483  // Put the function into context1 and call it before and after
7484  // detaching the global.  Before detaching, the call succeeds and
7485  // after detaching and exception is thrown.
7486  context1->Enter();
7487  context1->Global()->Set(v8_str("fun"), fun);
7488  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7489  CHECK_EQ(42, x_value->Int32Value());
7490  context0->DetachGlobal();
7491  v8::TryCatch catcher;
7492  x_value = CompileRun("fun('x')");
7493  CHECK(x_value.IsEmpty());
7494  CHECK(catcher.HasCaught());
7495  context1->Exit();
7496
7497  context1.Dispose();
7498  context0.Dispose();
7499}
7500
7501
7502THREADED_TEST(CrossLazyLoad) {
7503  v8::HandleScope scope;
7504  LocalContext other;
7505  LocalContext current;
7506
7507  Local<String> token = v8_str("<security token>");
7508  other->SetSecurityToken(token);
7509  current->SetSecurityToken(token);
7510
7511  // Setup reference from current to other.
7512  current->Global()->Set(v8_str("other"), other->Global());
7513
7514  // Trigger lazy loading in other context.
7515  Local<Script> script =
7516      Script::Compile(v8_str("other.eval('new Date(42)')"));
7517  Local<Value> value = script->Run();
7518  CHECK_EQ(42.0, value->NumberValue());
7519}
7520
7521
7522static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7523  ApiTestFuzzer::Fuzz();
7524  if (args.IsConstructCall()) {
7525    if (args[0]->IsInt32()) {
7526       return v8_num(-args[0]->Int32Value());
7527    }
7528  }
7529
7530  return args[0];
7531}
7532
7533
7534// Test that a call handler can be set for objects which will allow
7535// non-function objects created through the API to be called as
7536// functions.
7537THREADED_TEST(CallAsFunction) {
7538  v8::HandleScope scope;
7539  LocalContext context;
7540
7541  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7542    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7543    instance_template->SetCallAsFunctionHandler(call_as_function);
7544    Local<v8::Object> instance = t->GetFunction()->NewInstance();
7545    context->Global()->Set(v8_str("obj"), instance);
7546    v8::TryCatch try_catch;
7547    Local<Value> value;
7548    CHECK(!try_catch.HasCaught());
7549
7550    value = CompileRun("obj(42)");
7551    CHECK(!try_catch.HasCaught());
7552    CHECK_EQ(42, value->Int32Value());
7553
7554    value = CompileRun("(function(o){return o(49)})(obj)");
7555    CHECK(!try_catch.HasCaught());
7556    CHECK_EQ(49, value->Int32Value());
7557
7558    // test special case of call as function
7559    value = CompileRun("[obj]['0'](45)");
7560    CHECK(!try_catch.HasCaught());
7561    CHECK_EQ(45, value->Int32Value());
7562
7563    value = CompileRun("obj.call = Function.prototype.call;"
7564                       "obj.call(null, 87)");
7565    CHECK(!try_catch.HasCaught());
7566    CHECK_EQ(87, value->Int32Value());
7567
7568    // Regression tests for bug #1116356: Calling call through call/apply
7569    // must work for non-function receivers.
7570    const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7571    value = CompileRun(apply_99);
7572    CHECK(!try_catch.HasCaught());
7573    CHECK_EQ(99, value->Int32Value());
7574
7575    const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7576    value = CompileRun(call_17);
7577    CHECK(!try_catch.HasCaught());
7578    CHECK_EQ(17, value->Int32Value());
7579
7580    // Check that the call-as-function handler can be called through
7581    // new.
7582    value = CompileRun("new obj(43)");
7583    CHECK(!try_catch.HasCaught());
7584    CHECK_EQ(-43, value->Int32Value());
7585
7586    // Check that the call-as-function handler can be called through
7587    // the API.
7588    v8::Handle<Value> args[] = { v8_num(28) };
7589    value = instance->CallAsFunction(instance, 1, args);
7590    CHECK(!try_catch.HasCaught());
7591    CHECK_EQ(28, value->Int32Value());
7592  }
7593
7594  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7595    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7596    Local<v8::Object> instance = t->GetFunction()->NewInstance();
7597    context->Global()->Set(v8_str("obj2"), instance);
7598    v8::TryCatch try_catch;
7599    Local<Value> value;
7600    CHECK(!try_catch.HasCaught());
7601
7602    // Call an object without call-as-function handler through the JS
7603    value = CompileRun("obj2(28)");
7604    CHECK(value.IsEmpty());
7605    CHECK(try_catch.HasCaught());
7606    String::AsciiValue exception_value1(try_catch.Exception());
7607    CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7608             *exception_value1);
7609    try_catch.Reset();
7610
7611    // Call an object without call-as-function handler through the API
7612    value = CompileRun("obj2(28)");
7613    v8::Handle<Value> args[] = { v8_num(28) };
7614    value = instance->CallAsFunction(instance, 1, args);
7615    CHECK(value.IsEmpty());
7616    CHECK(try_catch.HasCaught());
7617    String::AsciiValue exception_value2(try_catch.Exception());
7618    CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7619    try_catch.Reset();
7620  }
7621
7622  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7623    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7624    instance_template->SetCallAsFunctionHandler(ThrowValue);
7625    Local<v8::Object> instance = t->GetFunction()->NewInstance();
7626    context->Global()->Set(v8_str("obj3"), instance);
7627    v8::TryCatch try_catch;
7628    Local<Value> value;
7629    CHECK(!try_catch.HasCaught());
7630
7631    // Catch the exception which is thrown by call-as-function handler
7632    value = CompileRun("obj3(22)");
7633    CHECK(try_catch.HasCaught());
7634    String::AsciiValue exception_value1(try_catch.Exception());
7635    CHECK_EQ("22", *exception_value1);
7636    try_catch.Reset();
7637
7638    v8::Handle<Value> args[] = { v8_num(23) };
7639    value = instance->CallAsFunction(instance, 1, args);
7640    CHECK(try_catch.HasCaught());
7641    String::AsciiValue exception_value2(try_catch.Exception());
7642    CHECK_EQ("23", *exception_value2);
7643    try_catch.Reset();
7644  }
7645}
7646
7647
7648// Check whether a non-function object is callable.
7649THREADED_TEST(CallableObject) {
7650  v8::HandleScope scope;
7651  LocalContext context;
7652
7653  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7654    instance_template->SetCallAsFunctionHandler(call_as_function);
7655    Local<Object> instance = instance_template->NewInstance();
7656    v8::TryCatch try_catch;
7657
7658    CHECK(instance->IsCallable());
7659    CHECK(!try_catch.HasCaught());
7660  }
7661
7662  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7663    Local<Object> instance = instance_template->NewInstance();
7664    v8::TryCatch try_catch;
7665
7666    CHECK(!instance->IsCallable());
7667    CHECK(!try_catch.HasCaught());
7668  }
7669
7670  { Local<FunctionTemplate> function_template =
7671        FunctionTemplate::New(call_as_function);
7672    Local<Function> function = function_template->GetFunction();
7673    Local<Object> instance = function;
7674    v8::TryCatch try_catch;
7675
7676    CHECK(instance->IsCallable());
7677    CHECK(!try_catch.HasCaught());
7678  }
7679
7680  { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7681    Local<Function> function = function_template->GetFunction();
7682    Local<Object> instance = function;
7683    v8::TryCatch try_catch;
7684
7685    CHECK(instance->IsCallable());
7686    CHECK(!try_catch.HasCaught());
7687  }
7688}
7689
7690
7691static int CountHandles() {
7692  return v8::HandleScope::NumberOfHandles();
7693}
7694
7695
7696static int Recurse(int depth, int iterations) {
7697  v8::HandleScope scope;
7698  if (depth == 0) return CountHandles();
7699  for (int i = 0; i < iterations; i++) {
7700    Local<v8::Number> n = v8::Integer::New(42);
7701  }
7702  return Recurse(depth - 1, iterations);
7703}
7704
7705
7706THREADED_TEST(HandleIteration) {
7707  static const int kIterations = 500;
7708  static const int kNesting = 200;
7709  CHECK_EQ(0, CountHandles());
7710  {
7711    v8::HandleScope scope1;
7712    CHECK_EQ(0, CountHandles());
7713    for (int i = 0; i < kIterations; i++) {
7714      Local<v8::Number> n = v8::Integer::New(42);
7715      CHECK_EQ(i + 1, CountHandles());
7716    }
7717
7718    CHECK_EQ(kIterations, CountHandles());
7719    {
7720      v8::HandleScope scope2;
7721      for (int j = 0; j < kIterations; j++) {
7722        Local<v8::Number> n = v8::Integer::New(42);
7723        CHECK_EQ(j + 1 + kIterations, CountHandles());
7724      }
7725    }
7726    CHECK_EQ(kIterations, CountHandles());
7727  }
7728  CHECK_EQ(0, CountHandles());
7729  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7730}
7731
7732
7733static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7734    Local<String> name,
7735    const AccessorInfo& info) {
7736  ApiTestFuzzer::Fuzz();
7737  return v8::Handle<Value>();
7738}
7739
7740
7741THREADED_TEST(InterceptorHasOwnProperty) {
7742  v8::HandleScope scope;
7743  LocalContext context;
7744  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7745  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7746  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7747  Local<Function> function = fun_templ->GetFunction();
7748  context->Global()->Set(v8_str("constructor"), function);
7749  v8::Handle<Value> value = CompileRun(
7750      "var o = new constructor();"
7751      "o.hasOwnProperty('ostehaps');");
7752  CHECK_EQ(false, value->BooleanValue());
7753  value = CompileRun(
7754      "o.ostehaps = 42;"
7755      "o.hasOwnProperty('ostehaps');");
7756  CHECK_EQ(true, value->BooleanValue());
7757  value = CompileRun(
7758      "var p = new constructor();"
7759      "p.hasOwnProperty('ostehaps');");
7760  CHECK_EQ(false, value->BooleanValue());
7761}
7762
7763
7764static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7765    Local<String> name,
7766    const AccessorInfo& info) {
7767  ApiTestFuzzer::Fuzz();
7768  HEAP->CollectAllGarbage(false);
7769  return v8::Handle<Value>();
7770}
7771
7772
7773THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7774  v8::HandleScope scope;
7775  LocalContext context;
7776  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7777  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7778  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7779  Local<Function> function = fun_templ->GetFunction();
7780  context->Global()->Set(v8_str("constructor"), function);
7781  // Let's first make some stuff so we can be sure to get a good GC.
7782  CompileRun(
7783      "function makestr(size) {"
7784      "  switch (size) {"
7785      "    case 1: return 'f';"
7786      "    case 2: return 'fo';"
7787      "    case 3: return 'foo';"
7788      "  }"
7789      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
7790      "}"
7791      "var x = makestr(12345);"
7792      "x = makestr(31415);"
7793      "x = makestr(23456);");
7794  v8::Handle<Value> value = CompileRun(
7795      "var o = new constructor();"
7796      "o.__proto__ = new String(x);"
7797      "o.hasOwnProperty('ostehaps');");
7798  CHECK_EQ(false, value->BooleanValue());
7799}
7800
7801
7802typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7803                                                 const AccessorInfo& info);
7804
7805
7806static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7807                                   const char* source,
7808                                   int expected) {
7809  v8::HandleScope scope;
7810  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7811  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
7812  LocalContext context;
7813  context->Global()->Set(v8_str("o"), templ->NewInstance());
7814  v8::Handle<Value> value = CompileRun(source);
7815  CHECK_EQ(expected, value->Int32Value());
7816}
7817
7818
7819static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7820                                                 const AccessorInfo& info) {
7821  ApiTestFuzzer::Fuzz();
7822  CHECK_EQ(v8_str("data"), info.Data());
7823  CHECK_EQ(v8_str("x"), name);
7824  return v8::Integer::New(42);
7825}
7826
7827
7828// This test should hit the load IC for the interceptor case.
7829THREADED_TEST(InterceptorLoadIC) {
7830  CheckInterceptorLoadIC(InterceptorLoadICGetter,
7831    "var result = 0;"
7832    "for (var i = 0; i < 1000; i++) {"
7833    "  result = o.x;"
7834    "}",
7835    42);
7836}
7837
7838
7839// Below go several tests which verify that JITing for various
7840// configurations of interceptor and explicit fields works fine
7841// (those cases are special cased to get better performance).
7842
7843static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7844                                                 const AccessorInfo& info) {
7845  ApiTestFuzzer::Fuzz();
7846  return v8_str("x")->Equals(name)
7847      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7848}
7849
7850
7851THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7852  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7853    "var result = 0;"
7854    "o.y = 239;"
7855    "for (var i = 0; i < 1000; i++) {"
7856    "  result = o.y;"
7857    "}",
7858    239);
7859}
7860
7861
7862THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7863  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7864    "var result = 0;"
7865    "o.__proto__ = { 'y': 239 };"
7866    "for (var i = 0; i < 1000; i++) {"
7867    "  result = o.y + o.x;"
7868    "}",
7869    239 + 42);
7870}
7871
7872
7873THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7874  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7875    "var result = 0;"
7876    "o.__proto__.y = 239;"
7877    "for (var i = 0; i < 1000; i++) {"
7878    "  result = o.y + o.x;"
7879    "}",
7880    239 + 42);
7881}
7882
7883
7884THREADED_TEST(InterceptorLoadICUndefined) {
7885  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7886    "var result = 0;"
7887    "for (var i = 0; i < 1000; i++) {"
7888    "  result = (o.y == undefined) ? 239 : 42;"
7889    "}",
7890    239);
7891}
7892
7893
7894THREADED_TEST(InterceptorLoadICWithOverride) {
7895  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7896    "fst = new Object();  fst.__proto__ = o;"
7897    "snd = new Object();  snd.__proto__ = fst;"
7898    "var result1 = 0;"
7899    "for (var i = 0; i < 1000;  i++) {"
7900    "  result1 = snd.x;"
7901    "}"
7902    "fst.x = 239;"
7903    "var result = 0;"
7904    "for (var i = 0; i < 1000; i++) {"
7905    "  result = snd.x;"
7906    "}"
7907    "result + result1",
7908    239 + 42);
7909}
7910
7911
7912// Test the case when we stored field into
7913// a stub, but interceptor produced value on its own.
7914THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7915  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7916    "proto = new Object();"
7917    "o.__proto__ = proto;"
7918    "proto.x = 239;"
7919    "for (var i = 0; i < 1000; i++) {"
7920    "  o.x;"
7921    // Now it should be ICed and keep a reference to x defined on proto
7922    "}"
7923    "var result = 0;"
7924    "for (var i = 0; i < 1000; i++) {"
7925    "  result += o.x;"
7926    "}"
7927    "result;",
7928    42 * 1000);
7929}
7930
7931
7932// Test the case when we stored field into
7933// a stub, but it got invalidated later on.
7934THREADED_TEST(InterceptorLoadICInvalidatedField) {
7935  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7936    "proto1 = new Object();"
7937    "proto2 = new Object();"
7938    "o.__proto__ = proto1;"
7939    "proto1.__proto__ = proto2;"
7940    "proto2.y = 239;"
7941    "for (var i = 0; i < 1000; i++) {"
7942    "  o.y;"
7943    // Now it should be ICed and keep a reference to y defined on proto2
7944    "}"
7945    "proto1.y = 42;"
7946    "var result = 0;"
7947    "for (var i = 0; i < 1000; i++) {"
7948    "  result += o.y;"
7949    "}"
7950    "result;",
7951    42 * 1000);
7952}
7953
7954
7955static int interceptor_load_not_handled_calls = 0;
7956static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7957                                                   const AccessorInfo& info) {
7958  ++interceptor_load_not_handled_calls;
7959  return v8::Handle<v8::Value>();
7960}
7961
7962
7963// Test how post-interceptor lookups are done in the non-cacheable
7964// case: the interceptor should not be invoked during this lookup.
7965THREADED_TEST(InterceptorLoadICPostInterceptor) {
7966  interceptor_load_not_handled_calls = 0;
7967  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7968    "receiver = new Object();"
7969    "receiver.__proto__ = o;"
7970    "proto = new Object();"
7971    "/* Make proto a slow-case object. */"
7972    "for (var i = 0; i < 1000; i++) {"
7973    "  proto[\"xxxxxxxx\" + i] = [];"
7974    "}"
7975    "proto.x = 17;"
7976    "o.__proto__ = proto;"
7977    "var result = 0;"
7978    "for (var i = 0; i < 1000; i++) {"
7979    "  result += receiver.x;"
7980    "}"
7981    "result;",
7982    17 * 1000);
7983  CHECK_EQ(1000, interceptor_load_not_handled_calls);
7984}
7985
7986
7987// Test the case when we stored field into
7988// a stub, but it got invalidated later on due to override on
7989// global object which is between interceptor and fields' holders.
7990THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7991  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7992    "o.__proto__ = this;"  // set a global to be a proto of o.
7993    "this.__proto__.y = 239;"
7994    "for (var i = 0; i < 10; i++) {"
7995    "  if (o.y != 239) throw 'oops: ' + o.y;"
7996    // Now it should be ICed and keep a reference to y defined on field_holder.
7997    "}"
7998    "this.y = 42;"  // Assign on a global.
7999    "var result = 0;"
8000    "for (var i = 0; i < 10; i++) {"
8001    "  result += o.y;"
8002    "}"
8003    "result;",
8004    42 * 10);
8005}
8006
8007
8008static void SetOnThis(Local<String> name,
8009                      Local<Value> value,
8010                      const AccessorInfo& info) {
8011  info.This()->ForceSet(name, value);
8012}
8013
8014
8015THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8016  v8::HandleScope scope;
8017  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8018  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8019  templ->SetAccessor(v8_str("y"), Return239);
8020  LocalContext context;
8021  context->Global()->Set(v8_str("o"), templ->NewInstance());
8022
8023  // Check the case when receiver and interceptor's holder
8024  // are the same objects.
8025  v8::Handle<Value> value = CompileRun(
8026      "var result = 0;"
8027      "for (var i = 0; i < 7; i++) {"
8028      "  result = o.y;"
8029      "}");
8030  CHECK_EQ(239, value->Int32Value());
8031
8032  // Check the case when interceptor's holder is in proto chain
8033  // of receiver.
8034  value = CompileRun(
8035      "r = { __proto__: o };"
8036      "var result = 0;"
8037      "for (var i = 0; i < 7; i++) {"
8038      "  result = r.y;"
8039      "}");
8040  CHECK_EQ(239, value->Int32Value());
8041}
8042
8043
8044THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8045  v8::HandleScope scope;
8046  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8047  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8048  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8049  templ_p->SetAccessor(v8_str("y"), Return239);
8050
8051  LocalContext context;
8052  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8053  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8054
8055  // Check the case when receiver and interceptor's holder
8056  // are the same objects.
8057  v8::Handle<Value> value = CompileRun(
8058      "o.__proto__ = p;"
8059      "var result = 0;"
8060      "for (var i = 0; i < 7; i++) {"
8061      "  result = o.x + o.y;"
8062      "}");
8063  CHECK_EQ(239 + 42, value->Int32Value());
8064
8065  // Check the case when interceptor's holder is in proto chain
8066  // of receiver.
8067  value = CompileRun(
8068      "r = { __proto__: o };"
8069      "var result = 0;"
8070      "for (var i = 0; i < 7; i++) {"
8071      "  result = r.x + r.y;"
8072      "}");
8073  CHECK_EQ(239 + 42, value->Int32Value());
8074}
8075
8076
8077THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8078  v8::HandleScope scope;
8079  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8080  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8081  templ->SetAccessor(v8_str("y"), Return239);
8082
8083  LocalContext context;
8084  context->Global()->Set(v8_str("o"), templ->NewInstance());
8085
8086  v8::Handle<Value> value = CompileRun(
8087    "fst = new Object();  fst.__proto__ = o;"
8088    "snd = new Object();  snd.__proto__ = fst;"
8089    "var result1 = 0;"
8090    "for (var i = 0; i < 7;  i++) {"
8091    "  result1 = snd.x;"
8092    "}"
8093    "fst.x = 239;"
8094    "var result = 0;"
8095    "for (var i = 0; i < 7; i++) {"
8096    "  result = snd.x;"
8097    "}"
8098    "result + result1");
8099  CHECK_EQ(239 + 42, value->Int32Value());
8100}
8101
8102
8103// Test the case when we stored callback into
8104// a stub, but interceptor produced value on its own.
8105THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8106  v8::HandleScope scope;
8107  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8108  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8109  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8110  templ_p->SetAccessor(v8_str("y"), Return239);
8111
8112  LocalContext context;
8113  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8114  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8115
8116  v8::Handle<Value> value = CompileRun(
8117    "o.__proto__ = p;"
8118    "for (var i = 0; i < 7; i++) {"
8119    "  o.x;"
8120    // Now it should be ICed and keep a reference to x defined on p
8121    "}"
8122    "var result = 0;"
8123    "for (var i = 0; i < 7; i++) {"
8124    "  result += o.x;"
8125    "}"
8126    "result");
8127  CHECK_EQ(42 * 7, value->Int32Value());
8128}
8129
8130
8131// Test the case when we stored callback into
8132// a stub, but it got invalidated later on.
8133THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8134  v8::HandleScope scope;
8135  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8136  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8137  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8138  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8139
8140  LocalContext context;
8141  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8142  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8143
8144  v8::Handle<Value> value = CompileRun(
8145    "inbetween = new Object();"
8146    "o.__proto__ = inbetween;"
8147    "inbetween.__proto__ = p;"
8148    "for (var i = 0; i < 10; i++) {"
8149    "  o.y;"
8150    // Now it should be ICed and keep a reference to y defined on p
8151    "}"
8152    "inbetween.y = 42;"
8153    "var result = 0;"
8154    "for (var i = 0; i < 10; i++) {"
8155    "  result += o.y;"
8156    "}"
8157    "result");
8158  CHECK_EQ(42 * 10, value->Int32Value());
8159}
8160
8161
8162// Test the case when we stored callback into
8163// a stub, but it got invalidated later on due to override on
8164// global object which is between interceptor and callbacks' holders.
8165THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8166  v8::HandleScope scope;
8167  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8168  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8169  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8170  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8171
8172  LocalContext context;
8173  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8174  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8175
8176  v8::Handle<Value> value = CompileRun(
8177    "o.__proto__ = this;"
8178    "this.__proto__ = p;"
8179    "for (var i = 0; i < 10; i++) {"
8180    "  if (o.y != 239) throw 'oops: ' + o.y;"
8181    // Now it should be ICed and keep a reference to y defined on p
8182    "}"
8183    "this.y = 42;"
8184    "var result = 0;"
8185    "for (var i = 0; i < 10; i++) {"
8186    "  result += o.y;"
8187    "}"
8188    "result");
8189  CHECK_EQ(42 * 10, value->Int32Value());
8190}
8191
8192
8193static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8194                                                  const AccessorInfo& info) {
8195  ApiTestFuzzer::Fuzz();
8196  CHECK(v8_str("x")->Equals(name));
8197  return v8::Integer::New(0);
8198}
8199
8200
8201THREADED_TEST(InterceptorReturningZero) {
8202  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8203     "o.x == undefined ? 1 : 0",
8204     0);
8205}
8206
8207
8208static v8::Handle<Value> InterceptorStoreICSetter(
8209    Local<String> key, Local<Value> value, const AccessorInfo&) {
8210  CHECK(v8_str("x")->Equals(key));
8211  CHECK_EQ(42, value->Int32Value());
8212  return value;
8213}
8214
8215
8216// This test should hit the store IC for the interceptor case.
8217THREADED_TEST(InterceptorStoreIC) {
8218  v8::HandleScope scope;
8219  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8220  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
8221                                 InterceptorStoreICSetter,
8222                                 0, 0, 0, v8_str("data"));
8223  LocalContext context;
8224  context->Global()->Set(v8_str("o"), templ->NewInstance());
8225  v8::Handle<Value> value = CompileRun(
8226    "for (var i = 0; i < 1000; i++) {"
8227    "  o.x = 42;"
8228    "}");
8229}
8230
8231
8232THREADED_TEST(InterceptorStoreICWithNoSetter) {
8233  v8::HandleScope scope;
8234  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8235  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8236  LocalContext context;
8237  context->Global()->Set(v8_str("o"), templ->NewInstance());
8238  v8::Handle<Value> value = CompileRun(
8239    "for (var i = 0; i < 1000; i++) {"
8240    "  o.y = 239;"
8241    "}"
8242    "42 + o.y");
8243  CHECK_EQ(239 + 42, value->Int32Value());
8244}
8245
8246
8247
8248
8249v8::Handle<Value> call_ic_function;
8250v8::Handle<Value> call_ic_function2;
8251v8::Handle<Value> call_ic_function3;
8252
8253static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8254                                                 const AccessorInfo& info) {
8255  ApiTestFuzzer::Fuzz();
8256  CHECK(v8_str("x")->Equals(name));
8257  return call_ic_function;
8258}
8259
8260
8261// This test should hit the call IC for the interceptor case.
8262THREADED_TEST(InterceptorCallIC) {
8263  v8::HandleScope scope;
8264  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8265  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8266  LocalContext context;
8267  context->Global()->Set(v8_str("o"), templ->NewInstance());
8268  call_ic_function =
8269      v8_compile("function f(x) { return x + 1; }; f")->Run();
8270  v8::Handle<Value> value = CompileRun(
8271    "var result = 0;"
8272    "for (var i = 0; i < 1000; i++) {"
8273    "  result = o.x(41);"
8274    "}");
8275  CHECK_EQ(42, value->Int32Value());
8276}
8277
8278
8279// This test checks that if interceptor doesn't provide
8280// a value, we can fetch regular value.
8281THREADED_TEST(InterceptorCallICSeesOthers) {
8282  v8::HandleScope scope;
8283  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8284  templ->SetNamedPropertyHandler(NoBlockGetterX);
8285  LocalContext context;
8286  context->Global()->Set(v8_str("o"), templ->NewInstance());
8287  v8::Handle<Value> value = CompileRun(
8288    "o.x = function f(x) { return x + 1; };"
8289    "var result = 0;"
8290    "for (var i = 0; i < 7; i++) {"
8291    "  result = o.x(41);"
8292    "}");
8293  CHECK_EQ(42, value->Int32Value());
8294}
8295
8296
8297static v8::Handle<Value> call_ic_function4;
8298static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8299                                                  const AccessorInfo& info) {
8300  ApiTestFuzzer::Fuzz();
8301  CHECK(v8_str("x")->Equals(name));
8302  return call_ic_function4;
8303}
8304
8305
8306// This test checks that if interceptor provides a function,
8307// even if we cached shadowed variant, interceptor's function
8308// is invoked
8309THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8310  v8::HandleScope scope;
8311  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8312  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8313  LocalContext context;
8314  context->Global()->Set(v8_str("o"), templ->NewInstance());
8315  call_ic_function4 =
8316      v8_compile("function f(x) { return x - 1; }; f")->Run();
8317  v8::Handle<Value> value = CompileRun(
8318    "o.__proto__.x = function(x) { return x + 1; };"
8319    "var result = 0;"
8320    "for (var i = 0; i < 1000; i++) {"
8321    "  result = o.x(42);"
8322    "}");
8323  CHECK_EQ(41, value->Int32Value());
8324}
8325
8326
8327// Test the case when we stored cacheable lookup into
8328// a stub, but it got invalidated later on
8329THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8330  v8::HandleScope scope;
8331  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8332  templ->SetNamedPropertyHandler(NoBlockGetterX);
8333  LocalContext context;
8334  context->Global()->Set(v8_str("o"), templ->NewInstance());
8335  v8::Handle<Value> value = CompileRun(
8336    "proto1 = new Object();"
8337    "proto2 = new Object();"
8338    "o.__proto__ = proto1;"
8339    "proto1.__proto__ = proto2;"
8340    "proto2.y = function(x) { return x + 1; };"
8341    // Invoke it many times to compile a stub
8342    "for (var i = 0; i < 7; i++) {"
8343    "  o.y(42);"
8344    "}"
8345    "proto1.y = function(x) { return x - 1; };"
8346    "var result = 0;"
8347    "for (var i = 0; i < 7; i++) {"
8348    "  result += o.y(42);"
8349    "}");
8350  CHECK_EQ(41 * 7, value->Int32Value());
8351}
8352
8353
8354static v8::Handle<Value> call_ic_function5;
8355static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8356                                                  const AccessorInfo& info) {
8357  ApiTestFuzzer::Fuzz();
8358  if (v8_str("x")->Equals(name))
8359    return call_ic_function5;
8360  else
8361    return Local<Value>();
8362}
8363
8364
8365// This test checks that if interceptor doesn't provide a function,
8366// cached constant function is used
8367THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8368  v8::HandleScope scope;
8369  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8370  templ->SetNamedPropertyHandler(NoBlockGetterX);
8371  LocalContext context;
8372  context->Global()->Set(v8_str("o"), templ->NewInstance());
8373  v8::Handle<Value> value = CompileRun(
8374    "function inc(x) { return x + 1; };"
8375    "inc(1);"
8376    "o.x = inc;"
8377    "var result = 0;"
8378    "for (var i = 0; i < 1000; i++) {"
8379    "  result = o.x(42);"
8380    "}");
8381  CHECK_EQ(43, value->Int32Value());
8382}
8383
8384
8385// This test checks that if interceptor provides a function,
8386// even if we cached constant function, interceptor's function
8387// is invoked
8388THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8389  v8::HandleScope scope;
8390  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8391  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8392  LocalContext context;
8393  context->Global()->Set(v8_str("o"), templ->NewInstance());
8394  call_ic_function5 =
8395      v8_compile("function f(x) { return x - 1; }; f")->Run();
8396  v8::Handle<Value> value = CompileRun(
8397    "function inc(x) { return x + 1; };"
8398    "inc(1);"
8399    "o.x = inc;"
8400    "var result = 0;"
8401    "for (var i = 0; i < 1000; i++) {"
8402    "  result = o.x(42);"
8403    "}");
8404  CHECK_EQ(41, value->Int32Value());
8405}
8406
8407
8408// Test the case when we stored constant function into
8409// a stub, but it got invalidated later on
8410THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8411  v8::HandleScope scope;
8412  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8413  templ->SetNamedPropertyHandler(NoBlockGetterX);
8414  LocalContext context;
8415  context->Global()->Set(v8_str("o"), templ->NewInstance());
8416  v8::Handle<Value> value = CompileRun(
8417    "function inc(x) { return x + 1; };"
8418    "inc(1);"
8419    "proto1 = new Object();"
8420    "proto2 = new Object();"
8421    "o.__proto__ = proto1;"
8422    "proto1.__proto__ = proto2;"
8423    "proto2.y = inc;"
8424    // Invoke it many times to compile a stub
8425    "for (var i = 0; i < 7; i++) {"
8426    "  o.y(42);"
8427    "}"
8428    "proto1.y = function(x) { return x - 1; };"
8429    "var result = 0;"
8430    "for (var i = 0; i < 7; i++) {"
8431    "  result += o.y(42);"
8432    "}");
8433  CHECK_EQ(41 * 7, value->Int32Value());
8434}
8435
8436
8437// Test the case when we stored constant function into
8438// a stub, but it got invalidated later on due to override on
8439// global object which is between interceptor and constant function' holders.
8440THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8441  v8::HandleScope scope;
8442  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8443  templ->SetNamedPropertyHandler(NoBlockGetterX);
8444  LocalContext context;
8445  context->Global()->Set(v8_str("o"), templ->NewInstance());
8446  v8::Handle<Value> value = CompileRun(
8447    "function inc(x) { return x + 1; };"
8448    "inc(1);"
8449    "o.__proto__ = this;"
8450    "this.__proto__.y = inc;"
8451    // Invoke it many times to compile a stub
8452    "for (var i = 0; i < 7; i++) {"
8453    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8454    "}"
8455    "this.y = function(x) { return x - 1; };"
8456    "var result = 0;"
8457    "for (var i = 0; i < 7; i++) {"
8458    "  result += o.y(42);"
8459    "}");
8460  CHECK_EQ(41 * 7, value->Int32Value());
8461}
8462
8463
8464// Test the case when actual function to call sits on global object.
8465THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8466  v8::HandleScope scope;
8467  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8468  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8469
8470  LocalContext context;
8471  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8472
8473  v8::Handle<Value> value = CompileRun(
8474    "try {"
8475    "  o.__proto__ = this;"
8476    "  for (var i = 0; i < 10; i++) {"
8477    "    var v = o.parseFloat('239');"
8478    "    if (v != 239) throw v;"
8479      // Now it should be ICed and keep a reference to parseFloat.
8480    "  }"
8481    "  var result = 0;"
8482    "  for (var i = 0; i < 10; i++) {"
8483    "    result += o.parseFloat('239');"
8484    "  }"
8485    "  result"
8486    "} catch(e) {"
8487    "  e"
8488    "};");
8489  CHECK_EQ(239 * 10, value->Int32Value());
8490}
8491
8492static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8493                                                  const AccessorInfo& info) {
8494  ApiTestFuzzer::Fuzz();
8495  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8496  ++(*call_count);
8497  if ((*call_count) % 20 == 0) {
8498    HEAP->CollectAllGarbage(true);
8499  }
8500  return v8::Handle<Value>();
8501}
8502
8503static v8::Handle<Value> FastApiCallback_TrivialSignature(
8504    const v8::Arguments& args) {
8505  ApiTestFuzzer::Fuzz();
8506  CHECK_EQ(args.This(), args.Holder());
8507  CHECK(args.Data()->Equals(v8_str("method_data")));
8508  return v8::Integer::New(args[0]->Int32Value() + 1);
8509}
8510
8511static v8::Handle<Value> FastApiCallback_SimpleSignature(
8512    const v8::Arguments& args) {
8513  ApiTestFuzzer::Fuzz();
8514  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8515  CHECK(args.Data()->Equals(v8_str("method_data")));
8516  // Note, we're using HasRealNamedProperty instead of Has to avoid
8517  // invoking the interceptor again.
8518  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8519  return v8::Integer::New(args[0]->Int32Value() + 1);
8520}
8521
8522// Helper to maximize the odds of object moving.
8523static void GenerateSomeGarbage() {
8524  CompileRun(
8525      "var garbage;"
8526      "for (var i = 0; i < 1000; i++) {"
8527      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8528      "}"
8529      "garbage = undefined;");
8530}
8531
8532
8533v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8534  static int count = 0;
8535  if (count++ % 3 == 0) {
8536    HEAP->  CollectAllGarbage(true);  // This should move the stub
8537    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
8538  }
8539  return v8::Handle<v8::Value>();
8540}
8541
8542
8543THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8544  v8::HandleScope scope;
8545  LocalContext context;
8546  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8547  nativeobject_templ->Set("callback",
8548                          v8::FunctionTemplate::New(DirectApiCallback));
8549  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8550  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8551  // call the api function multiple times to ensure direct call stub creation.
8552  CompileRun(
8553        "function f() {"
8554        "  for (var i = 1; i <= 30; i++) {"
8555        "    nativeobject.callback();"
8556        "  }"
8557        "}"
8558        "f();");
8559}
8560
8561
8562v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8563  return v8::ThrowException(v8_str("g"));
8564}
8565
8566
8567THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8568  v8::HandleScope scope;
8569  LocalContext context;
8570  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8571  nativeobject_templ->Set("callback",
8572                          v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8573  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8574  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8575  // call the api function multiple times to ensure direct call stub creation.
8576  v8::Handle<Value> result = CompileRun(
8577      "var result = '';"
8578      "function f() {"
8579      "  for (var i = 1; i <= 5; i++) {"
8580      "    try { nativeobject.callback(); } catch (e) { result += e; }"
8581      "  }"
8582      "}"
8583      "f(); result;");
8584  CHECK_EQ(v8_str("ggggg"), result);
8585}
8586
8587
8588v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8589                                           const v8::AccessorInfo& info) {
8590  if (++p_getter_count % 3 == 0) {
8591    HEAP->CollectAllGarbage(true);
8592    GenerateSomeGarbage();
8593  }
8594  return v8::Handle<v8::Value>();
8595}
8596
8597
8598THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8599  v8::HandleScope scope;
8600  LocalContext context;
8601  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8602  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8603  context->Global()->Set(v8_str("o1"), obj->NewInstance());
8604  p_getter_count = 0;
8605  CompileRun(
8606      "function f() {"
8607      "  for (var i = 0; i < 30; i++) o1.p1;"
8608      "}"
8609      "f();");
8610  CHECK_EQ(30, p_getter_count);
8611}
8612
8613
8614v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8615    Local<String> name, const v8::AccessorInfo& info) {
8616  return v8::ThrowException(v8_str("g"));
8617}
8618
8619
8620THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8621  v8::HandleScope scope;
8622  LocalContext context;
8623  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8624  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8625  context->Global()->Set(v8_str("o1"), obj->NewInstance());
8626  v8::Handle<Value> result = CompileRun(
8627      "var result = '';"
8628      "for (var i = 0; i < 5; i++) {"
8629      "    try { o1.p1; } catch (e) { result += e; }"
8630      "}"
8631      "result;");
8632  CHECK_EQ(v8_str("ggggg"), result);
8633}
8634
8635
8636THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8637  int interceptor_call_count = 0;
8638  v8::HandleScope scope;
8639  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8640  v8::Handle<v8::FunctionTemplate> method_templ =
8641      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8642                                v8_str("method_data"),
8643                                v8::Handle<v8::Signature>());
8644  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8645  proto_templ->Set(v8_str("method"), method_templ);
8646  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8647  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8648                                 NULL, NULL, NULL, NULL,
8649                                 v8::External::Wrap(&interceptor_call_count));
8650  LocalContext context;
8651  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8652  GenerateSomeGarbage();
8653  context->Global()->Set(v8_str("o"), fun->NewInstance());
8654  v8::Handle<Value> value = CompileRun(
8655      "var result = 0;"
8656      "for (var i = 0; i < 100; i++) {"
8657      "  result = o.method(41);"
8658      "}");
8659  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8660  CHECK_EQ(100, interceptor_call_count);
8661}
8662
8663THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8664  int interceptor_call_count = 0;
8665  v8::HandleScope scope;
8666  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8667  v8::Handle<v8::FunctionTemplate> method_templ =
8668      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8669                                v8_str("method_data"),
8670                                v8::Signature::New(fun_templ));
8671  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8672  proto_templ->Set(v8_str("method"), method_templ);
8673  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8674  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8675                                 NULL, NULL, NULL, NULL,
8676                                 v8::External::Wrap(&interceptor_call_count));
8677  LocalContext context;
8678  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8679  GenerateSomeGarbage();
8680  context->Global()->Set(v8_str("o"), fun->NewInstance());
8681  v8::Handle<Value> value = CompileRun(
8682      "o.foo = 17;"
8683      "var receiver = {};"
8684      "receiver.__proto__ = o;"
8685      "var result = 0;"
8686      "for (var i = 0; i < 100; i++) {"
8687      "  result = receiver.method(41);"
8688      "}");
8689  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8690  CHECK_EQ(100, interceptor_call_count);
8691}
8692
8693THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8694  int interceptor_call_count = 0;
8695  v8::HandleScope scope;
8696  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8697  v8::Handle<v8::FunctionTemplate> method_templ =
8698      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8699                                v8_str("method_data"),
8700                                v8::Signature::New(fun_templ));
8701  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8702  proto_templ->Set(v8_str("method"), method_templ);
8703  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8704  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8705                                 NULL, NULL, NULL, NULL,
8706                                 v8::External::Wrap(&interceptor_call_count));
8707  LocalContext context;
8708  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8709  GenerateSomeGarbage();
8710  context->Global()->Set(v8_str("o"), fun->NewInstance());
8711  v8::Handle<Value> value = CompileRun(
8712      "o.foo = 17;"
8713      "var receiver = {};"
8714      "receiver.__proto__ = o;"
8715      "var result = 0;"
8716      "var saved_result = 0;"
8717      "for (var i = 0; i < 100; i++) {"
8718      "  result = receiver.method(41);"
8719      "  if (i == 50) {"
8720      "    saved_result = result;"
8721      "    receiver = {method: function(x) { return x - 1 }};"
8722      "  }"
8723      "}");
8724  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8725  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8726  CHECK_GE(interceptor_call_count, 50);
8727}
8728
8729THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8730  int interceptor_call_count = 0;
8731  v8::HandleScope scope;
8732  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8733  v8::Handle<v8::FunctionTemplate> method_templ =
8734      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8735                                v8_str("method_data"),
8736                                v8::Signature::New(fun_templ));
8737  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8738  proto_templ->Set(v8_str("method"), method_templ);
8739  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8740  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8741                                 NULL, NULL, NULL, NULL,
8742                                 v8::External::Wrap(&interceptor_call_count));
8743  LocalContext context;
8744  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8745  GenerateSomeGarbage();
8746  context->Global()->Set(v8_str("o"), fun->NewInstance());
8747  v8::Handle<Value> value = CompileRun(
8748      "o.foo = 17;"
8749      "var receiver = {};"
8750      "receiver.__proto__ = o;"
8751      "var result = 0;"
8752      "var saved_result = 0;"
8753      "for (var i = 0; i < 100; i++) {"
8754      "  result = receiver.method(41);"
8755      "  if (i == 50) {"
8756      "    saved_result = result;"
8757      "    o.method = function(x) { return x - 1 };"
8758      "  }"
8759      "}");
8760  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8761  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8762  CHECK_GE(interceptor_call_count, 50);
8763}
8764
8765THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8766  int interceptor_call_count = 0;
8767  v8::HandleScope scope;
8768  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8769  v8::Handle<v8::FunctionTemplate> method_templ =
8770      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8771                                v8_str("method_data"),
8772                                v8::Signature::New(fun_templ));
8773  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8774  proto_templ->Set(v8_str("method"), method_templ);
8775  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8776  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8777                                 NULL, NULL, NULL, NULL,
8778                                 v8::External::Wrap(&interceptor_call_count));
8779  LocalContext context;
8780  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8781  GenerateSomeGarbage();
8782  context->Global()->Set(v8_str("o"), fun->NewInstance());
8783  v8::TryCatch try_catch;
8784  v8::Handle<Value> value = CompileRun(
8785      "o.foo = 17;"
8786      "var receiver = {};"
8787      "receiver.__proto__ = o;"
8788      "var result = 0;"
8789      "var saved_result = 0;"
8790      "for (var i = 0; i < 100; i++) {"
8791      "  result = receiver.method(41);"
8792      "  if (i == 50) {"
8793      "    saved_result = result;"
8794      "    receiver = 333;"
8795      "  }"
8796      "}");
8797  CHECK(try_catch.HasCaught());
8798  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8799           try_catch.Exception()->ToString());
8800  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8801  CHECK_GE(interceptor_call_count, 50);
8802}
8803
8804THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8805  int interceptor_call_count = 0;
8806  v8::HandleScope scope;
8807  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8808  v8::Handle<v8::FunctionTemplate> method_templ =
8809      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8810                                v8_str("method_data"),
8811                                v8::Signature::New(fun_templ));
8812  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8813  proto_templ->Set(v8_str("method"), method_templ);
8814  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8815  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8816                                 NULL, NULL, NULL, NULL,
8817                                 v8::External::Wrap(&interceptor_call_count));
8818  LocalContext context;
8819  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8820  GenerateSomeGarbage();
8821  context->Global()->Set(v8_str("o"), fun->NewInstance());
8822  v8::TryCatch try_catch;
8823  v8::Handle<Value> value = CompileRun(
8824      "o.foo = 17;"
8825      "var receiver = {};"
8826      "receiver.__proto__ = o;"
8827      "var result = 0;"
8828      "var saved_result = 0;"
8829      "for (var i = 0; i < 100; i++) {"
8830      "  result = receiver.method(41);"
8831      "  if (i == 50) {"
8832      "    saved_result = result;"
8833      "    receiver = {method: receiver.method};"
8834      "  }"
8835      "}");
8836  CHECK(try_catch.HasCaught());
8837  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8838           try_catch.Exception()->ToString());
8839  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8840  CHECK_GE(interceptor_call_count, 50);
8841}
8842
8843THREADED_TEST(CallICFastApi_TrivialSignature) {
8844  v8::HandleScope scope;
8845  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8846  v8::Handle<v8::FunctionTemplate> method_templ =
8847      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8848                                v8_str("method_data"),
8849                                v8::Handle<v8::Signature>());
8850  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8851  proto_templ->Set(v8_str("method"), method_templ);
8852  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8853  LocalContext context;
8854  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8855  GenerateSomeGarbage();
8856  context->Global()->Set(v8_str("o"), fun->NewInstance());
8857  v8::Handle<Value> value = CompileRun(
8858      "var result = 0;"
8859      "for (var i = 0; i < 100; i++) {"
8860      "  result = o.method(41);"
8861      "}");
8862
8863  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8864}
8865
8866THREADED_TEST(CallICFastApi_SimpleSignature) {
8867  v8::HandleScope scope;
8868  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8869  v8::Handle<v8::FunctionTemplate> method_templ =
8870      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8871                                v8_str("method_data"),
8872                                v8::Signature::New(fun_templ));
8873  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8874  proto_templ->Set(v8_str("method"), method_templ);
8875  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8876  LocalContext context;
8877  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8878  GenerateSomeGarbage();
8879  context->Global()->Set(v8_str("o"), fun->NewInstance());
8880  v8::Handle<Value> value = CompileRun(
8881      "o.foo = 17;"
8882      "var receiver = {};"
8883      "receiver.__proto__ = o;"
8884      "var result = 0;"
8885      "for (var i = 0; i < 100; i++) {"
8886      "  result = receiver.method(41);"
8887      "}");
8888
8889  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8890}
8891
8892THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
8893  v8::HandleScope scope;
8894  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8895  v8::Handle<v8::FunctionTemplate> method_templ =
8896      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8897                                v8_str("method_data"),
8898                                v8::Signature::New(fun_templ));
8899  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8900  proto_templ->Set(v8_str("method"), method_templ);
8901  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8902  LocalContext context;
8903  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8904  GenerateSomeGarbage();
8905  context->Global()->Set(v8_str("o"), fun->NewInstance());
8906  v8::Handle<Value> value = CompileRun(
8907      "o.foo = 17;"
8908      "var receiver = {};"
8909      "receiver.__proto__ = o;"
8910      "var result = 0;"
8911      "var saved_result = 0;"
8912      "for (var i = 0; i < 100; i++) {"
8913      "  result = receiver.method(41);"
8914      "  if (i == 50) {"
8915      "    saved_result = result;"
8916      "    receiver = {method: function(x) { return x - 1 }};"
8917      "  }"
8918      "}");
8919  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8920  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8921}
8922
8923THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8924  v8::HandleScope scope;
8925  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8926  v8::Handle<v8::FunctionTemplate> method_templ =
8927      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8928                                v8_str("method_data"),
8929                                v8::Signature::New(fun_templ));
8930  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8931  proto_templ->Set(v8_str("method"), method_templ);
8932  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8933  LocalContext context;
8934  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8935  GenerateSomeGarbage();
8936  context->Global()->Set(v8_str("o"), fun->NewInstance());
8937  v8::TryCatch try_catch;
8938  v8::Handle<Value> value = CompileRun(
8939      "o.foo = 17;"
8940      "var receiver = {};"
8941      "receiver.__proto__ = o;"
8942      "var result = 0;"
8943      "var saved_result = 0;"
8944      "for (var i = 0; i < 100; i++) {"
8945      "  result = receiver.method(41);"
8946      "  if (i == 50) {"
8947      "    saved_result = result;"
8948      "    receiver = 333;"
8949      "  }"
8950      "}");
8951  CHECK(try_catch.HasCaught());
8952  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8953           try_catch.Exception()->ToString());
8954  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8955}
8956
8957
8958v8::Handle<Value> keyed_call_ic_function;
8959
8960static v8::Handle<Value> InterceptorKeyedCallICGetter(
8961    Local<String> name, const AccessorInfo& info) {
8962  ApiTestFuzzer::Fuzz();
8963  if (v8_str("x")->Equals(name)) {
8964    return keyed_call_ic_function;
8965  }
8966  return v8::Handle<Value>();
8967}
8968
8969
8970// Test the case when we stored cacheable lookup into
8971// a stub, but the function name changed (to another cacheable function).
8972THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8973  v8::HandleScope scope;
8974  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8975  templ->SetNamedPropertyHandler(NoBlockGetterX);
8976  LocalContext context;
8977  context->Global()->Set(v8_str("o"), templ->NewInstance());
8978  v8::Handle<Value> value = CompileRun(
8979    "proto = new Object();"
8980    "proto.y = function(x) { return x + 1; };"
8981    "proto.z = function(x) { return x - 1; };"
8982    "o.__proto__ = proto;"
8983    "var result = 0;"
8984    "var method = 'y';"
8985    "for (var i = 0; i < 10; i++) {"
8986    "  if (i == 5) { method = 'z'; };"
8987    "  result += o[method](41);"
8988    "}");
8989  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8990}
8991
8992
8993// Test the case when we stored cacheable lookup into
8994// a stub, but the function name changed (and the new function is present
8995// both before and after the interceptor in the prototype chain).
8996THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8997  v8::HandleScope scope;
8998  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8999  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9000  LocalContext context;
9001  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9002  keyed_call_ic_function =
9003      v8_compile("function f(x) { return x - 1; }; f")->Run();
9004  v8::Handle<Value> value = CompileRun(
9005    "o = new Object();"
9006    "proto2 = new Object();"
9007    "o.y = function(x) { return x + 1; };"
9008    "proto2.y = function(x) { return x + 2; };"
9009    "o.__proto__ = proto1;"
9010    "proto1.__proto__ = proto2;"
9011    "var result = 0;"
9012    "var method = 'x';"
9013    "for (var i = 0; i < 10; i++) {"
9014    "  if (i == 5) { method = 'y'; };"
9015    "  result += o[method](41);"
9016    "}");
9017  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9018}
9019
9020
9021// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9022// on the global object.
9023THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9024  v8::HandleScope scope;
9025  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9026  templ->SetNamedPropertyHandler(NoBlockGetterX);
9027  LocalContext context;
9028  context->Global()->Set(v8_str("o"), templ->NewInstance());
9029  v8::Handle<Value> value = CompileRun(
9030    "function inc(x) { return x + 1; };"
9031    "inc(1);"
9032    "function dec(x) { return x - 1; };"
9033    "dec(1);"
9034    "o.__proto__ = this;"
9035    "this.__proto__.x = inc;"
9036    "this.__proto__.y = dec;"
9037    "var result = 0;"
9038    "var method = 'x';"
9039    "for (var i = 0; i < 10; i++) {"
9040    "  if (i == 5) { method = 'y'; };"
9041    "  result += o[method](41);"
9042    "}");
9043  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9044}
9045
9046
9047// Test the case when actual function to call sits on global object.
9048THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9049  v8::HandleScope scope;
9050  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9051  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9052  LocalContext context;
9053  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9054
9055  v8::Handle<Value> value = CompileRun(
9056    "function len(x) { return x.length; };"
9057    "o.__proto__ = this;"
9058    "var m = 'parseFloat';"
9059    "var result = 0;"
9060    "for (var i = 0; i < 10; i++) {"
9061    "  if (i == 5) {"
9062    "    m = 'len';"
9063    "    saved_result = result;"
9064    "  };"
9065    "  result = o[m]('239');"
9066    "}");
9067  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9068  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9069}
9070
9071// Test the map transition before the interceptor.
9072THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9073  v8::HandleScope scope;
9074  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9075  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9076  LocalContext context;
9077  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9078
9079  v8::Handle<Value> value = CompileRun(
9080    "var o = new Object();"
9081    "o.__proto__ = proto;"
9082    "o.method = function(x) { return x + 1; };"
9083    "var m = 'method';"
9084    "var result = 0;"
9085    "for (var i = 0; i < 10; i++) {"
9086    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
9087    "  result += o[m](41);"
9088    "}");
9089  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9090}
9091
9092
9093// Test the map transition after the interceptor.
9094THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9095  v8::HandleScope scope;
9096  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9097  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9098  LocalContext context;
9099  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9100
9101  v8::Handle<Value> value = CompileRun(
9102    "var proto = new Object();"
9103    "o.__proto__ = proto;"
9104    "proto.method = function(x) { return x + 1; };"
9105    "var m = 'method';"
9106    "var result = 0;"
9107    "for (var i = 0; i < 10; i++) {"
9108    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9109    "  result += o[m](41);"
9110    "}");
9111  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9112}
9113
9114
9115static int interceptor_call_count = 0;
9116
9117static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9118                                                     const AccessorInfo& info) {
9119  ApiTestFuzzer::Fuzz();
9120  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9121    return call_ic_function2;
9122  }
9123  return v8::Handle<Value>();
9124}
9125
9126
9127// This test should hit load and call ICs for the interceptor case.
9128// Once in a while, the interceptor will reply that a property was not
9129// found in which case we should get a reference error.
9130THREADED_TEST(InterceptorICReferenceErrors) {
9131  v8::HandleScope scope;
9132  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9133  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9134  LocalContext context(0, templ, v8::Handle<Value>());
9135  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9136  v8::Handle<Value> value = CompileRun(
9137    "function f() {"
9138    "  for (var i = 0; i < 1000; i++) {"
9139    "    try { x; } catch(e) { return true; }"
9140    "  }"
9141    "  return false;"
9142    "};"
9143    "f();");
9144  CHECK_EQ(true, value->BooleanValue());
9145  interceptor_call_count = 0;
9146  value = CompileRun(
9147    "function g() {"
9148    "  for (var i = 0; i < 1000; i++) {"
9149    "    try { x(42); } catch(e) { return true; }"
9150    "  }"
9151    "  return false;"
9152    "};"
9153    "g();");
9154  CHECK_EQ(true, value->BooleanValue());
9155}
9156
9157
9158static int interceptor_ic_exception_get_count = 0;
9159
9160static v8::Handle<Value> InterceptorICExceptionGetter(
9161    Local<String> name,
9162    const AccessorInfo& info) {
9163  ApiTestFuzzer::Fuzz();
9164  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9165    return call_ic_function3;
9166  }
9167  if (interceptor_ic_exception_get_count == 20) {
9168    return v8::ThrowException(v8_num(42));
9169  }
9170  // Do not handle get for properties other than x.
9171  return v8::Handle<Value>();
9172}
9173
9174// Test interceptor load/call IC where the interceptor throws an
9175// exception once in a while.
9176THREADED_TEST(InterceptorICGetterExceptions) {
9177  interceptor_ic_exception_get_count = 0;
9178  v8::HandleScope scope;
9179  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9180  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9181  LocalContext context(0, templ, v8::Handle<Value>());
9182  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9183  v8::Handle<Value> value = CompileRun(
9184    "function f() {"
9185    "  for (var i = 0; i < 100; i++) {"
9186    "    try { x; } catch(e) { return true; }"
9187    "  }"
9188    "  return false;"
9189    "};"
9190    "f();");
9191  CHECK_EQ(true, value->BooleanValue());
9192  interceptor_ic_exception_get_count = 0;
9193  value = CompileRun(
9194    "function f() {"
9195    "  for (var i = 0; i < 100; i++) {"
9196    "    try { x(42); } catch(e) { return true; }"
9197    "  }"
9198    "  return false;"
9199    "};"
9200    "f();");
9201  CHECK_EQ(true, value->BooleanValue());
9202}
9203
9204
9205static int interceptor_ic_exception_set_count = 0;
9206
9207static v8::Handle<Value> InterceptorICExceptionSetter(
9208      Local<String> key, Local<Value> value, const AccessorInfo&) {
9209  ApiTestFuzzer::Fuzz();
9210  if (++interceptor_ic_exception_set_count > 20) {
9211    return v8::ThrowException(v8_num(42));
9212  }
9213  // Do not actually handle setting.
9214  return v8::Handle<Value>();
9215}
9216
9217// Test interceptor store IC where the interceptor throws an exception
9218// once in a while.
9219THREADED_TEST(InterceptorICSetterExceptions) {
9220  interceptor_ic_exception_set_count = 0;
9221  v8::HandleScope scope;
9222  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9223  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9224  LocalContext context(0, templ, v8::Handle<Value>());
9225  v8::Handle<Value> value = CompileRun(
9226    "function f() {"
9227    "  for (var i = 0; i < 100; i++) {"
9228    "    try { x = 42; } catch(e) { return true; }"
9229    "  }"
9230    "  return false;"
9231    "};"
9232    "f();");
9233  CHECK_EQ(true, value->BooleanValue());
9234}
9235
9236
9237// Test that we ignore null interceptors.
9238THREADED_TEST(NullNamedInterceptor) {
9239  v8::HandleScope scope;
9240  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9241  templ->SetNamedPropertyHandler(0);
9242  LocalContext context;
9243  templ->Set("x", v8_num(42));
9244  v8::Handle<v8::Object> obj = templ->NewInstance();
9245  context->Global()->Set(v8_str("obj"), obj);
9246  v8::Handle<Value> value = CompileRun("obj.x");
9247  CHECK(value->IsInt32());
9248  CHECK_EQ(42, value->Int32Value());
9249}
9250
9251
9252// Test that we ignore null interceptors.
9253THREADED_TEST(NullIndexedInterceptor) {
9254  v8::HandleScope scope;
9255  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9256  templ->SetIndexedPropertyHandler(0);
9257  LocalContext context;
9258  templ->Set("42", v8_num(42));
9259  v8::Handle<v8::Object> obj = templ->NewInstance();
9260  context->Global()->Set(v8_str("obj"), obj);
9261  v8::Handle<Value> value = CompileRun("obj[42]");
9262  CHECK(value->IsInt32());
9263  CHECK_EQ(42, value->Int32Value());
9264}
9265
9266
9267THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9268  v8::HandleScope scope;
9269  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9270  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9271  LocalContext env;
9272  env->Global()->Set(v8_str("obj"),
9273                     templ->GetFunction()->NewInstance());
9274  ExpectTrue("obj.x === 42");
9275  ExpectTrue("!obj.propertyIsEnumerable('x')");
9276}
9277
9278
9279static Handle<Value> ThrowingGetter(Local<String> name,
9280                                    const AccessorInfo& info) {
9281  ApiTestFuzzer::Fuzz();
9282  ThrowException(Handle<Value>());
9283  return Undefined();
9284}
9285
9286
9287THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9288  HandleScope scope;
9289  LocalContext context;
9290
9291  Local<FunctionTemplate> templ = FunctionTemplate::New();
9292  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9293  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9294
9295  Local<Object> instance = templ->GetFunction()->NewInstance();
9296
9297  Local<Object> another = Object::New();
9298  another->SetPrototype(instance);
9299
9300  Local<Object> with_js_getter = CompileRun(
9301      "o = {};\n"
9302      "o.__defineGetter__('f', function() { throw undefined; });\n"
9303      "o\n").As<Object>();
9304  CHECK(!with_js_getter.IsEmpty());
9305
9306  TryCatch try_catch;
9307
9308  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9309  CHECK(try_catch.HasCaught());
9310  try_catch.Reset();
9311  CHECK(result.IsEmpty());
9312
9313  result = another->GetRealNamedProperty(v8_str("f"));
9314  CHECK(try_catch.HasCaught());
9315  try_catch.Reset();
9316  CHECK(result.IsEmpty());
9317
9318  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9319  CHECK(try_catch.HasCaught());
9320  try_catch.Reset();
9321  CHECK(result.IsEmpty());
9322
9323  result = another->Get(v8_str("f"));
9324  CHECK(try_catch.HasCaught());
9325  try_catch.Reset();
9326  CHECK(result.IsEmpty());
9327
9328  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9329  CHECK(try_catch.HasCaught());
9330  try_catch.Reset();
9331  CHECK(result.IsEmpty());
9332
9333  result = with_js_getter->Get(v8_str("f"));
9334  CHECK(try_catch.HasCaught());
9335  try_catch.Reset();
9336  CHECK(result.IsEmpty());
9337}
9338
9339
9340static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9341  TryCatch try_catch;
9342  // Verboseness is important: it triggers message delivery which can call into
9343  // external code.
9344  try_catch.SetVerbose(true);
9345  CompileRun("throw 'from JS';");
9346  CHECK(try_catch.HasCaught());
9347  CHECK(!i::Isolate::Current()->has_pending_exception());
9348  CHECK(!i::Isolate::Current()->has_scheduled_exception());
9349  return Undefined();
9350}
9351
9352
9353static int call_depth;
9354
9355
9356static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9357  TryCatch try_catch;
9358}
9359
9360
9361static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9362  if (--call_depth) CompileRun("throw 'ThrowInJS';");
9363}
9364
9365
9366static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9367  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9368}
9369
9370
9371static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9372  Handle<String> errorMessageString = message->Get();
9373  CHECK(!errorMessageString.IsEmpty());
9374  message->GetStackTrace();
9375  message->GetScriptResourceName();
9376}
9377
9378THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9379  HandleScope scope;
9380  LocalContext context;
9381
9382  Local<Function> func =
9383      FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9384  context->Global()->Set(v8_str("func"), func);
9385
9386  MessageCallback callbacks[] =
9387      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9388  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9389    MessageCallback callback = callbacks[i];
9390    if (callback != NULL) {
9391      V8::AddMessageListener(callback);
9392    }
9393    // Some small number to control number of times message handler should
9394    // throw an exception.
9395    call_depth = 5;
9396    ExpectFalse(
9397        "var thrown = false;\n"
9398        "try { func(); } catch(e) { thrown = true; }\n"
9399        "thrown\n");
9400    if (callback != NULL) {
9401      V8::RemoveMessageListeners(callback);
9402    }
9403  }
9404}
9405
9406
9407static v8::Handle<Value> ParentGetter(Local<String> name,
9408                                      const AccessorInfo& info) {
9409  ApiTestFuzzer::Fuzz();
9410  return v8_num(1);
9411}
9412
9413
9414static v8::Handle<Value> ChildGetter(Local<String> name,
9415                                     const AccessorInfo& info) {
9416  ApiTestFuzzer::Fuzz();
9417  return v8_num(42);
9418}
9419
9420
9421THREADED_TEST(Overriding) {
9422  v8::HandleScope scope;
9423  LocalContext context;
9424
9425  // Parent template.
9426  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9427  Local<ObjectTemplate> parent_instance_templ =
9428      parent_templ->InstanceTemplate();
9429  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9430
9431  // Template that inherits from the parent template.
9432  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9433  Local<ObjectTemplate> child_instance_templ =
9434      child_templ->InstanceTemplate();
9435  child_templ->Inherit(parent_templ);
9436  // Override 'f'.  The child version of 'f' should get called for child
9437  // instances.
9438  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9439  // Add 'g' twice.  The 'g' added last should get called for instances.
9440  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9441  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9442
9443  // Add 'h' as an accessor to the proto template with ReadOnly attributes
9444  // so 'h' can be shadowed on the instance object.
9445  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9446  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9447      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9448
9449  // Add 'i' as an accessor to the instance template with ReadOnly attributes
9450  // but the attribute does not have effect because it is duplicated with
9451  // NULL setter.
9452  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9453      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9454
9455
9456
9457  // Instantiate the child template.
9458  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9459
9460  // Check that the child function overrides the parent one.
9461  context->Global()->Set(v8_str("o"), instance);
9462  Local<Value> value = v8_compile("o.f")->Run();
9463  // Check that the 'g' that was added last is hit.
9464  CHECK_EQ(42, value->Int32Value());
9465  value = v8_compile("o.g")->Run();
9466  CHECK_EQ(42, value->Int32Value());
9467
9468  // Check 'h' can be shadowed.
9469  value = v8_compile("o.h = 3; o.h")->Run();
9470  CHECK_EQ(3, value->Int32Value());
9471
9472  // Check 'i' is cannot be shadowed or changed.
9473  value = v8_compile("o.i = 3; o.i")->Run();
9474  CHECK_EQ(42, value->Int32Value());
9475}
9476
9477
9478static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9479  ApiTestFuzzer::Fuzz();
9480  if (args.IsConstructCall()) {
9481    return v8::Boolean::New(true);
9482  }
9483  return v8::Boolean::New(false);
9484}
9485
9486
9487THREADED_TEST(IsConstructCall) {
9488  v8::HandleScope scope;
9489
9490  // Function template with call handler.
9491  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9492  templ->SetCallHandler(IsConstructHandler);
9493
9494  LocalContext context;
9495
9496  context->Global()->Set(v8_str("f"), templ->GetFunction());
9497  Local<Value> value = v8_compile("f()")->Run();
9498  CHECK(!value->BooleanValue());
9499  value = v8_compile("new f()")->Run();
9500  CHECK(value->BooleanValue());
9501}
9502
9503
9504THREADED_TEST(ObjectProtoToString) {
9505  v8::HandleScope scope;
9506  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9507  templ->SetClassName(v8_str("MyClass"));
9508
9509  LocalContext context;
9510
9511  Local<String> customized_tostring = v8_str("customized toString");
9512
9513  // Replace Object.prototype.toString
9514  v8_compile("Object.prototype.toString = function() {"
9515                  "  return 'customized toString';"
9516                  "}")->Run();
9517
9518  // Normal ToString call should call replaced Object.prototype.toString
9519  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9520  Local<String> value = instance->ToString();
9521  CHECK(value->IsString() && value->Equals(customized_tostring));
9522
9523  // ObjectProtoToString should not call replace toString function.
9524  value = instance->ObjectProtoToString();
9525  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9526
9527  // Check global
9528  value = context->Global()->ObjectProtoToString();
9529  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9530
9531  // Check ordinary object
9532  Local<Value> object = v8_compile("new Object()")->Run();
9533  value = object.As<v8::Object>()->ObjectProtoToString();
9534  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9535}
9536
9537
9538THREADED_TEST(ObjectGetConstructorName) {
9539  v8::HandleScope scope;
9540  LocalContext context;
9541  v8_compile("function Parent() {};"
9542             "function Child() {};"
9543             "Child.prototype = new Parent();"
9544             "var outer = { inner: function() { } };"
9545             "var p = new Parent();"
9546             "var c = new Child();"
9547             "var x = new outer.inner();")->Run();
9548
9549  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9550  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9551      v8_str("Parent")));
9552
9553  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9554  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9555      v8_str("Child")));
9556
9557  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9558  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9559      v8_str("outer.inner")));
9560}
9561
9562
9563bool ApiTestFuzzer::fuzzing_ = false;
9564i::Semaphore* ApiTestFuzzer::all_tests_done_=
9565  i::OS::CreateSemaphore(0);
9566int ApiTestFuzzer::active_tests_;
9567int ApiTestFuzzer::tests_being_run_;
9568int ApiTestFuzzer::current_;
9569
9570
9571// We are in a callback and want to switch to another thread (if we
9572// are currently running the thread fuzzing test).
9573void ApiTestFuzzer::Fuzz() {
9574  if (!fuzzing_) return;
9575  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9576  test->ContextSwitch();
9577}
9578
9579
9580// Let the next thread go.  Since it is also waiting on the V8 lock it may
9581// not start immediately.
9582bool ApiTestFuzzer::NextThread() {
9583  int test_position = GetNextTestNumber();
9584  const char* test_name = RegisterThreadedTest::nth(current_)->name();
9585  if (test_position == current_) {
9586    if (kLogThreading)
9587      printf("Stay with %s\n", test_name);
9588    return false;
9589  }
9590  if (kLogThreading) {
9591    printf("Switch from %s to %s\n",
9592           test_name,
9593           RegisterThreadedTest::nth(test_position)->name());
9594  }
9595  current_ = test_position;
9596  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9597  return true;
9598}
9599
9600
9601void ApiTestFuzzer::Run() {
9602  // When it is our turn...
9603  gate_->Wait();
9604  {
9605    // ... get the V8 lock and start running the test.
9606    v8::Locker locker;
9607    CallTest();
9608  }
9609  // This test finished.
9610  active_ = false;
9611  active_tests_--;
9612  // If it was the last then signal that fact.
9613  if (active_tests_ == 0) {
9614    all_tests_done_->Signal();
9615  } else {
9616    // Otherwise select a new test and start that.
9617    NextThread();
9618  }
9619}
9620
9621
9622static unsigned linear_congruential_generator;
9623
9624
9625void ApiTestFuzzer::Setup(PartOfTest part) {
9626  linear_congruential_generator = i::FLAG_testing_prng_seed;
9627  fuzzing_ = true;
9628  int count = RegisterThreadedTest::count();
9629  int start =  count * part / (LAST_PART + 1);
9630  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9631  active_tests_ = tests_being_run_ = end - start + 1;
9632  for (int i = 0; i < tests_being_run_; i++) {
9633    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
9634  }
9635  for (int i = 0; i < active_tests_; i++) {
9636    RegisterThreadedTest::nth(i)->fuzzer_->Start();
9637  }
9638}
9639
9640
9641static void CallTestNumber(int test_number) {
9642  (RegisterThreadedTest::nth(test_number)->callback())();
9643}
9644
9645
9646void ApiTestFuzzer::RunAllTests() {
9647  // Set off the first test.
9648  current_ = -1;
9649  NextThread();
9650  // Wait till they are all done.
9651  all_tests_done_->Wait();
9652}
9653
9654
9655int ApiTestFuzzer::GetNextTestNumber() {
9656  int next_test;
9657  do {
9658    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9659    linear_congruential_generator *= 1664525u;
9660    linear_congruential_generator += 1013904223u;
9661  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9662  return next_test;
9663}
9664
9665
9666void ApiTestFuzzer::ContextSwitch() {
9667  // If the new thread is the same as the current thread there is nothing to do.
9668  if (NextThread()) {
9669    // Now it can start.
9670    v8::Unlocker unlocker;
9671    // Wait till someone starts us again.
9672    gate_->Wait();
9673    // And we're off.
9674  }
9675}
9676
9677
9678void ApiTestFuzzer::TearDown() {
9679  fuzzing_ = false;
9680  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9681    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9682    if (fuzzer != NULL) fuzzer->Join();
9683  }
9684}
9685
9686
9687// Lets not be needlessly self-referential.
9688TEST(Threading) {
9689  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9690  ApiTestFuzzer::RunAllTests();
9691  ApiTestFuzzer::TearDown();
9692}
9693
9694TEST(Threading2) {
9695  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9696  ApiTestFuzzer::RunAllTests();
9697  ApiTestFuzzer::TearDown();
9698}
9699
9700TEST(Threading3) {
9701  ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9702  ApiTestFuzzer::RunAllTests();
9703  ApiTestFuzzer::TearDown();
9704}
9705
9706TEST(Threading4) {
9707  ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9708  ApiTestFuzzer::RunAllTests();
9709  ApiTestFuzzer::TearDown();
9710}
9711
9712void ApiTestFuzzer::CallTest() {
9713  if (kLogThreading)
9714    printf("Start test %d\n", test_number_);
9715  CallTestNumber(test_number_);
9716  if (kLogThreading)
9717    printf("End test %d\n", test_number_);
9718}
9719
9720
9721static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
9722  CHECK(v8::Locker::IsLocked());
9723  ApiTestFuzzer::Fuzz();
9724  v8::Unlocker unlocker;
9725  const char* code = "throw 7;";
9726  {
9727    v8::Locker nested_locker;
9728    v8::HandleScope scope;
9729    v8::Handle<Value> exception;
9730    { v8::TryCatch try_catch;
9731      v8::Handle<Value> value = CompileRun(code);
9732      CHECK(value.IsEmpty());
9733      CHECK(try_catch.HasCaught());
9734      // Make sure to wrap the exception in a new handle because
9735      // the handle returned from the TryCatch is destroyed
9736      // when the TryCatch is destroyed.
9737      exception = Local<Value>::New(try_catch.Exception());
9738    }
9739    return v8::ThrowException(exception);
9740  }
9741}
9742
9743
9744static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
9745  CHECK(v8::Locker::IsLocked());
9746  ApiTestFuzzer::Fuzz();
9747  v8::Unlocker unlocker;
9748  const char* code = "throw 7;";
9749  {
9750    v8::Locker nested_locker;
9751    v8::HandleScope scope;
9752    v8::Handle<Value> value = CompileRun(code);
9753    CHECK(value.IsEmpty());
9754    return v8_str("foo");
9755  }
9756}
9757
9758
9759// These are locking tests that don't need to be run again
9760// as part of the locking aggregation tests.
9761TEST(NestedLockers) {
9762  v8::Locker locker;
9763  CHECK(v8::Locker::IsLocked());
9764  v8::HandleScope scope;
9765  LocalContext env;
9766  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9767  Local<Function> fun = fun_templ->GetFunction();
9768  env->Global()->Set(v8_str("throw_in_js"), fun);
9769  Local<Script> script = v8_compile("(function () {"
9770                                    "  try {"
9771                                    "    throw_in_js();"
9772                                    "    return 42;"
9773                                    "  } catch (e) {"
9774                                    "    return e * 13;"
9775                                    "  }"
9776                                    "})();");
9777  CHECK_EQ(91, script->Run()->Int32Value());
9778}
9779
9780
9781// These are locking tests that don't need to be run again
9782// as part of the locking aggregation tests.
9783TEST(NestedLockersNoTryCatch) {
9784  v8::Locker locker;
9785  v8::HandleScope scope;
9786  LocalContext env;
9787  Local<v8::FunctionTemplate> fun_templ =
9788      v8::FunctionTemplate::New(ThrowInJSNoCatch);
9789  Local<Function> fun = fun_templ->GetFunction();
9790  env->Global()->Set(v8_str("throw_in_js"), fun);
9791  Local<Script> script = v8_compile("(function () {"
9792                                    "  try {"
9793                                    "    throw_in_js();"
9794                                    "    return 42;"
9795                                    "  } catch (e) {"
9796                                    "    return e * 13;"
9797                                    "  }"
9798                                    "})();");
9799  CHECK_EQ(91, script->Run()->Int32Value());
9800}
9801
9802
9803THREADED_TEST(RecursiveLocking) {
9804  v8::Locker locker;
9805  {
9806    v8::Locker locker2;
9807    CHECK(v8::Locker::IsLocked());
9808  }
9809}
9810
9811
9812static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9813  ApiTestFuzzer::Fuzz();
9814  v8::Unlocker unlocker;
9815  return v8::Undefined();
9816}
9817
9818
9819THREADED_TEST(LockUnlockLock) {
9820  {
9821    v8::Locker locker;
9822    v8::HandleScope scope;
9823    LocalContext env;
9824    Local<v8::FunctionTemplate> fun_templ =
9825        v8::FunctionTemplate::New(UnlockForAMoment);
9826    Local<Function> fun = fun_templ->GetFunction();
9827    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9828    Local<Script> script = v8_compile("(function () {"
9829                                      "  unlock_for_a_moment();"
9830                                      "  return 42;"
9831                                      "})();");
9832    CHECK_EQ(42, script->Run()->Int32Value());
9833  }
9834  {
9835    v8::Locker locker;
9836    v8::HandleScope scope;
9837    LocalContext env;
9838    Local<v8::FunctionTemplate> fun_templ =
9839        v8::FunctionTemplate::New(UnlockForAMoment);
9840    Local<Function> fun = fun_templ->GetFunction();
9841    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9842    Local<Script> script = v8_compile("(function () {"
9843                                      "  unlock_for_a_moment();"
9844                                      "  return 42;"
9845                                      "})();");
9846    CHECK_EQ(42, script->Run()->Int32Value());
9847  }
9848}
9849
9850
9851static int GetGlobalObjectsCount() {
9852  int count = 0;
9853  i::HeapIterator it;
9854  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9855    if (object->IsJSGlobalObject()) count++;
9856  return count;
9857}
9858
9859
9860static void CheckSurvivingGlobalObjectsCount(int expected) {
9861  // We need to collect all garbage twice to be sure that everything
9862  // has been collected.  This is because inline caches are cleared in
9863  // the first garbage collection but some of the maps have already
9864  // been marked at that point.  Therefore some of the maps are not
9865  // collected until the second garbage collection.
9866  HEAP->global_context_map();
9867  HEAP->CollectAllGarbage(false);
9868  HEAP->CollectAllGarbage(false);
9869  int count = GetGlobalObjectsCount();
9870#ifdef DEBUG
9871  if (count != expected) HEAP->TracePathToGlobal();
9872#endif
9873  CHECK_EQ(expected, count);
9874}
9875
9876
9877TEST(DontLeakGlobalObjects) {
9878  // Regression test for issues 1139850 and 1174891.
9879
9880  v8::V8::Initialize();
9881
9882  for (int i = 0; i < 5; i++) {
9883    { v8::HandleScope scope;
9884      LocalContext context;
9885    }
9886    CheckSurvivingGlobalObjectsCount(0);
9887
9888    { v8::HandleScope scope;
9889      LocalContext context;
9890      v8_compile("Date")->Run();
9891    }
9892    CheckSurvivingGlobalObjectsCount(0);
9893
9894    { v8::HandleScope scope;
9895      LocalContext context;
9896      v8_compile("/aaa/")->Run();
9897    }
9898    CheckSurvivingGlobalObjectsCount(0);
9899
9900    { v8::HandleScope scope;
9901      const char* extension_list[] = { "v8/gc" };
9902      v8::ExtensionConfiguration extensions(1, extension_list);
9903      LocalContext context(&extensions);
9904      v8_compile("gc();")->Run();
9905    }
9906    CheckSurvivingGlobalObjectsCount(0);
9907  }
9908}
9909
9910
9911v8::Persistent<v8::Object> some_object;
9912v8::Persistent<v8::Object> bad_handle;
9913
9914void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
9915  v8::HandleScope scope;
9916  bad_handle = v8::Persistent<v8::Object>::New(some_object);
9917  handle.Dispose();
9918}
9919
9920
9921THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9922  LocalContext context;
9923
9924  v8::Persistent<v8::Object> handle1, handle2;
9925  {
9926    v8::HandleScope scope;
9927    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9928    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9929    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9930  }
9931  // Note: order is implementation dependent alas: currently
9932  // global handle nodes are processed by PostGarbageCollectionProcessing
9933  // in reverse allocation order, so if second allocated handle is deleted,
9934  // weak callback of the first handle would be able to 'reallocate' it.
9935  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9936  handle2.Dispose();
9937  HEAP->CollectAllGarbage(false);
9938}
9939
9940
9941v8::Persistent<v8::Object> to_be_disposed;
9942
9943void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9944  to_be_disposed.Dispose();
9945  HEAP->CollectAllGarbage(false);
9946  handle.Dispose();
9947}
9948
9949
9950THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9951  LocalContext context;
9952
9953  v8::Persistent<v8::Object> handle1, handle2;
9954  {
9955    v8::HandleScope scope;
9956    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9957    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9958  }
9959  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9960  to_be_disposed = handle2;
9961  HEAP->CollectAllGarbage(false);
9962}
9963
9964void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9965  handle.Dispose();
9966}
9967
9968void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9969  v8::HandleScope scope;
9970  v8::Persistent<v8::Object>::New(v8::Object::New());
9971  handle.Dispose();
9972}
9973
9974
9975THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9976  LocalContext context;
9977
9978  v8::Persistent<v8::Object> handle1, handle2, handle3;
9979  {
9980    v8::HandleScope scope;
9981    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9982    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9983    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9984  }
9985  handle2.MakeWeak(NULL, DisposingCallback);
9986  handle3.MakeWeak(NULL, HandleCreatingCallback);
9987  HEAP->CollectAllGarbage(false);
9988}
9989
9990
9991THREADED_TEST(CheckForCrossContextObjectLiterals) {
9992  v8::V8::Initialize();
9993
9994  const int nof = 2;
9995  const char* sources[nof] = {
9996    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9997    "Object()"
9998  };
9999
10000  for (int i = 0; i < nof; i++) {
10001    const char* source = sources[i];
10002    { v8::HandleScope scope;
10003      LocalContext context;
10004      CompileRun(source);
10005    }
10006    { v8::HandleScope scope;
10007      LocalContext context;
10008      CompileRun(source);
10009    }
10010  }
10011}
10012
10013
10014static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10015  v8::HandleScope inner;
10016  env->Enter();
10017  v8::Handle<Value> three = v8_num(3);
10018  v8::Handle<Value> value = inner.Close(three);
10019  env->Exit();
10020  return value;
10021}
10022
10023
10024THREADED_TEST(NestedHandleScopeAndContexts) {
10025  v8::HandleScope outer;
10026  v8::Persistent<Context> env = Context::New();
10027  env->Enter();
10028  v8::Handle<Value> value = NestedScope(env);
10029  v8::Handle<String> str = value->ToString();
10030  env->Exit();
10031  env.Dispose();
10032}
10033
10034
10035THREADED_TEST(ExternalAllocatedMemory) {
10036  v8::HandleScope outer;
10037  v8::Persistent<Context> env = Context::New();
10038  const int kSize = 1024*1024;
10039  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10040  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10041}
10042
10043
10044THREADED_TEST(DisposeEnteredContext) {
10045  v8::HandleScope scope;
10046  LocalContext outer;
10047  { v8::Persistent<v8::Context> inner = v8::Context::New();
10048    inner->Enter();
10049    inner.Dispose();
10050    inner.Clear();
10051    inner->Exit();
10052  }
10053}
10054
10055
10056// Regression test for issue 54, object templates with internal fields
10057// but no accessors or interceptors did not get their internal field
10058// count set on instances.
10059THREADED_TEST(Regress54) {
10060  v8::HandleScope outer;
10061  LocalContext context;
10062  static v8::Persistent<v8::ObjectTemplate> templ;
10063  if (templ.IsEmpty()) {
10064    v8::HandleScope inner;
10065    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10066    local->SetInternalFieldCount(1);
10067    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10068  }
10069  v8::Handle<v8::Object> result = templ->NewInstance();
10070  CHECK_EQ(1, result->InternalFieldCount());
10071}
10072
10073
10074// If part of the threaded tests, this test makes ThreadingTest fail
10075// on mac.
10076TEST(CatchStackOverflow) {
10077  v8::HandleScope scope;
10078  LocalContext context;
10079  v8::TryCatch try_catch;
10080  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10081    "function f() {"
10082    "  return f();"
10083    "}"
10084    ""
10085    "f();"));
10086  v8::Handle<v8::Value> result = script->Run();
10087  CHECK(result.IsEmpty());
10088}
10089
10090
10091static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10092                                    const char* resource_name,
10093                                    int line_offset) {
10094  v8::HandleScope scope;
10095  v8::TryCatch try_catch;
10096  v8::Handle<v8::Value> result = script->Run();
10097  CHECK(result.IsEmpty());
10098  CHECK(try_catch.HasCaught());
10099  v8::Handle<v8::Message> message = try_catch.Message();
10100  CHECK(!message.IsEmpty());
10101  CHECK_EQ(10 + line_offset, message->GetLineNumber());
10102  CHECK_EQ(91, message->GetStartPosition());
10103  CHECK_EQ(92, message->GetEndPosition());
10104  CHECK_EQ(2, message->GetStartColumn());
10105  CHECK_EQ(3, message->GetEndColumn());
10106  v8::String::AsciiValue line(message->GetSourceLine());
10107  CHECK_EQ("  throw 'nirk';", *line);
10108  v8::String::AsciiValue name(message->GetScriptResourceName());
10109  CHECK_EQ(resource_name, *name);
10110}
10111
10112
10113THREADED_TEST(TryCatchSourceInfo) {
10114  v8::HandleScope scope;
10115  LocalContext context;
10116  v8::Handle<v8::String> source = v8::String::New(
10117      "function Foo() {\n"
10118      "  return Bar();\n"
10119      "}\n"
10120      "\n"
10121      "function Bar() {\n"
10122      "  return Baz();\n"
10123      "}\n"
10124      "\n"
10125      "function Baz() {\n"
10126      "  throw 'nirk';\n"
10127      "}\n"
10128      "\n"
10129      "Foo();\n");
10130
10131  const char* resource_name;
10132  v8::Handle<v8::Script> script;
10133  resource_name = "test.js";
10134  script = v8::Script::Compile(source, v8::String::New(resource_name));
10135  CheckTryCatchSourceInfo(script, resource_name, 0);
10136
10137  resource_name = "test1.js";
10138  v8::ScriptOrigin origin1(v8::String::New(resource_name));
10139  script = v8::Script::Compile(source, &origin1);
10140  CheckTryCatchSourceInfo(script, resource_name, 0);
10141
10142  resource_name = "test2.js";
10143  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10144  script = v8::Script::Compile(source, &origin2);
10145  CheckTryCatchSourceInfo(script, resource_name, 7);
10146}
10147
10148
10149THREADED_TEST(CompilationCache) {
10150  v8::HandleScope scope;
10151  LocalContext context;
10152  v8::Handle<v8::String> source0 = v8::String::New("1234");
10153  v8::Handle<v8::String> source1 = v8::String::New("1234");
10154  v8::Handle<v8::Script> script0 =
10155      v8::Script::Compile(source0, v8::String::New("test.js"));
10156  v8::Handle<v8::Script> script1 =
10157      v8::Script::Compile(source1, v8::String::New("test.js"));
10158  v8::Handle<v8::Script> script2 =
10159      v8::Script::Compile(source0);  // different origin
10160  CHECK_EQ(1234, script0->Run()->Int32Value());
10161  CHECK_EQ(1234, script1->Run()->Int32Value());
10162  CHECK_EQ(1234, script2->Run()->Int32Value());
10163}
10164
10165
10166static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10167  ApiTestFuzzer::Fuzz();
10168  return v8_num(42);
10169}
10170
10171
10172THREADED_TEST(CallbackFunctionName) {
10173  v8::HandleScope scope;
10174  LocalContext context;
10175  Local<ObjectTemplate> t = ObjectTemplate::New();
10176  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10177  context->Global()->Set(v8_str("obj"), t->NewInstance());
10178  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10179  CHECK(value->IsString());
10180  v8::String::AsciiValue name(value);
10181  CHECK_EQ("asdf", *name);
10182}
10183
10184
10185THREADED_TEST(DateAccess) {
10186  v8::HandleScope scope;
10187  LocalContext context;
10188  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10189  CHECK(date->IsDate());
10190  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
10191}
10192
10193
10194void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
10195  v8::Handle<v8::Object> obj = val.As<v8::Object>();
10196  v8::Handle<v8::Array> props = obj->GetPropertyNames();
10197  CHECK_EQ(elmc, props->Length());
10198  for (int i = 0; i < elmc; i++) {
10199    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10200    CHECK_EQ(elmv[i], *elm);
10201  }
10202}
10203
10204
10205void CheckOwnProperties(v8::Handle<v8::Value> val,
10206                        int elmc,
10207                        const char* elmv[]) {
10208  v8::Handle<v8::Object> obj = val.As<v8::Object>();
10209  v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10210  CHECK_EQ(elmc, props->Length());
10211  for (int i = 0; i < elmc; i++) {
10212    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10213    CHECK_EQ(elmv[i], *elm);
10214  }
10215}
10216
10217
10218THREADED_TEST(PropertyEnumeration) {
10219  v8::HandleScope scope;
10220  LocalContext context;
10221  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10222      "var result = [];"
10223      "result[0] = {};"
10224      "result[1] = {a: 1, b: 2};"
10225      "result[2] = [1, 2, 3];"
10226      "var proto = {x: 1, y: 2, z: 3};"
10227      "var x = { __proto__: proto, w: 0, z: 1 };"
10228      "result[3] = x;"
10229      "result;"))->Run();
10230  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10231  CHECK_EQ(4, elms->Length());
10232  int elmc0 = 0;
10233  const char** elmv0 = NULL;
10234  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10235  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10236  int elmc1 = 2;
10237  const char* elmv1[] = {"a", "b"};
10238  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10239  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10240  int elmc2 = 3;
10241  const char* elmv2[] = {"0", "1", "2"};
10242  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10243  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10244  int elmc3 = 4;
10245  const char* elmv3[] = {"w", "z", "x", "y"};
10246  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
10247  int elmc4 = 2;
10248  const char* elmv4[] = {"w", "z"};
10249  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
10250}
10251
10252THREADED_TEST(PropertyEnumeration2) {
10253  v8::HandleScope scope;
10254  LocalContext context;
10255  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10256      "var result = [];"
10257      "result[0] = {};"
10258      "result[1] = {a: 1, b: 2};"
10259      "result[2] = [1, 2, 3];"
10260      "var proto = {x: 1, y: 2, z: 3};"
10261      "var x = { __proto__: proto, w: 0, z: 1 };"
10262      "result[3] = x;"
10263      "result;"))->Run();
10264  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10265  CHECK_EQ(4, elms->Length());
10266  int elmc0 = 0;
10267  const char** elmv0 = NULL;
10268  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10269
10270  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10271  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10272  CHECK_EQ(0, props->Length());
10273  for (uint32_t i = 0; i < props->Length(); i++) {
10274    printf("p[%d]\n", i);
10275  }
10276}
10277
10278static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10279                                  Local<Value> name,
10280                                  v8::AccessType type,
10281                                  Local<Value> data) {
10282  return type != v8::ACCESS_SET;
10283}
10284
10285
10286static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10287                                    uint32_t key,
10288                                    v8::AccessType type,
10289                                    Local<Value> data) {
10290  return type != v8::ACCESS_SET;
10291}
10292
10293
10294THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10295  v8::HandleScope scope;
10296  LocalContext context;
10297  Local<ObjectTemplate> templ = ObjectTemplate::New();
10298  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10299                                 IndexedSetAccessBlocker);
10300  templ->Set(v8_str("x"), v8::True());
10301  Local<v8::Object> instance = templ->NewInstance();
10302  context->Global()->Set(v8_str("obj"), instance);
10303  Local<Value> value = CompileRun("obj.x");
10304  CHECK(value->BooleanValue());
10305}
10306
10307
10308static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10309                                  Local<Value> name,
10310                                  v8::AccessType type,
10311                                  Local<Value> data) {
10312  return false;
10313}
10314
10315
10316static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10317                                    uint32_t key,
10318                                    v8::AccessType type,
10319                                    Local<Value> data) {
10320  return false;
10321}
10322
10323
10324
10325THREADED_TEST(AccessChecksReenabledCorrectly) {
10326  v8::HandleScope scope;
10327  LocalContext context;
10328  Local<ObjectTemplate> templ = ObjectTemplate::New();
10329  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10330                                 IndexedGetAccessBlocker);
10331  templ->Set(v8_str("a"), v8_str("a"));
10332  // Add more than 8 (see kMaxFastProperties) properties
10333  // so that the constructor will force copying map.
10334  // Cannot sprintf, gcc complains unsafety.
10335  char buf[4];
10336  for (char i = '0'; i <= '9' ; i++) {
10337    buf[0] = i;
10338    for (char j = '0'; j <= '9'; j++) {
10339      buf[1] = j;
10340      for (char k = '0'; k <= '9'; k++) {
10341        buf[2] = k;
10342        buf[3] = 0;
10343        templ->Set(v8_str(buf), v8::Number::New(k));
10344      }
10345    }
10346  }
10347
10348  Local<v8::Object> instance_1 = templ->NewInstance();
10349  context->Global()->Set(v8_str("obj_1"), instance_1);
10350
10351  Local<Value> value_1 = CompileRun("obj_1.a");
10352  CHECK(value_1->IsUndefined());
10353
10354  Local<v8::Object> instance_2 = templ->NewInstance();
10355  context->Global()->Set(v8_str("obj_2"), instance_2);
10356
10357  Local<Value> value_2 = CompileRun("obj_2.a");
10358  CHECK(value_2->IsUndefined());
10359}
10360
10361
10362// This tests that access check information remains on the global
10363// object template when creating contexts.
10364THREADED_TEST(AccessControlRepeatedContextCreation) {
10365  v8::HandleScope handle_scope;
10366  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10367  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10368                                           IndexedSetAccessBlocker);
10369  i::Handle<i::ObjectTemplateInfo> internal_template =
10370      v8::Utils::OpenHandle(*global_template);
10371  CHECK(!internal_template->constructor()->IsUndefined());
10372  i::Handle<i::FunctionTemplateInfo> constructor(
10373      i::FunctionTemplateInfo::cast(internal_template->constructor()));
10374  CHECK(!constructor->access_check_info()->IsUndefined());
10375  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10376  CHECK(!constructor->access_check_info()->IsUndefined());
10377}
10378
10379
10380THREADED_TEST(TurnOnAccessCheck) {
10381  v8::HandleScope handle_scope;
10382
10383  // Create an environment with access check to the global object disabled by
10384  // default.
10385  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10386  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10387                                           IndexedGetAccessBlocker,
10388                                           v8::Handle<v8::Value>(),
10389                                           false);
10390  v8::Persistent<Context> context = Context::New(NULL, global_template);
10391  Context::Scope context_scope(context);
10392
10393  // Set up a property and a number of functions.
10394  context->Global()->Set(v8_str("a"), v8_num(1));
10395  CompileRun("function f1() {return a;}"
10396             "function f2() {return a;}"
10397             "function g1() {return h();}"
10398             "function g2() {return h();}"
10399             "function h() {return 1;}");
10400  Local<Function> f1 =
10401      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10402  Local<Function> f2 =
10403      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10404  Local<Function> g1 =
10405      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10406  Local<Function> g2 =
10407      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10408  Local<Function> h =
10409      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10410
10411  // Get the global object.
10412  v8::Handle<v8::Object> global = context->Global();
10413
10414  // Call f1 one time and f2 a number of times. This will ensure that f1 still
10415  // uses the runtime system to retreive property a whereas f2 uses global load
10416  // inline cache.
10417  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10418  for (int i = 0; i < 4; i++) {
10419    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10420  }
10421
10422  // Same for g1 and g2.
10423  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10424  for (int i = 0; i < 4; i++) {
10425    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10426  }
10427
10428  // Detach the global and turn on access check.
10429  context->DetachGlobal();
10430  context->Global()->TurnOnAccessCheck();
10431
10432  // Failing access check to property get results in undefined.
10433  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10434  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10435
10436  // Failing access check to function call results in exception.
10437  CHECK(g1->Call(global, 0, NULL).IsEmpty());
10438  CHECK(g2->Call(global, 0, NULL).IsEmpty());
10439
10440  // No failing access check when just returning a constant.
10441  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10442}
10443
10444
10445v8::Handle<v8::String> a;
10446v8::Handle<v8::String> h;
10447
10448static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10449                                       Local<Value> name,
10450                                       v8::AccessType type,
10451                                       Local<Value> data) {
10452  return !(name->Equals(a) || name->Equals(h));
10453}
10454
10455
10456THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10457  v8::HandleScope handle_scope;
10458
10459  // Create an environment with access check to the global object disabled by
10460  // default. When the registered access checker will block access to properties
10461  // a and h
10462  a = v8_str("a");
10463  h = v8_str("h");
10464  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10465  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10466                                           IndexedGetAccessBlocker,
10467                                           v8::Handle<v8::Value>(),
10468                                           false);
10469  v8::Persistent<Context> context = Context::New(NULL, global_template);
10470  Context::Scope context_scope(context);
10471
10472  // Set up a property and a number of functions.
10473  context->Global()->Set(v8_str("a"), v8_num(1));
10474  static const char* source = "function f1() {return a;}"
10475                              "function f2() {return a;}"
10476                              "function g1() {return h();}"
10477                              "function g2() {return h();}"
10478                              "function h() {return 1;}";
10479
10480  CompileRun(source);
10481  Local<Function> f1;
10482  Local<Function> f2;
10483  Local<Function> g1;
10484  Local<Function> g2;
10485  Local<Function> h;
10486  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10487  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10488  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10489  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10490  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10491
10492  // Get the global object.
10493  v8::Handle<v8::Object> global = context->Global();
10494
10495  // Call f1 one time and f2 a number of times. This will ensure that f1 still
10496  // uses the runtime system to retreive property a whereas f2 uses global load
10497  // inline cache.
10498  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10499  for (int i = 0; i < 4; i++) {
10500    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10501  }
10502
10503  // Same for g1 and g2.
10504  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10505  for (int i = 0; i < 4; i++) {
10506    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10507  }
10508
10509  // Detach the global and turn on access check now blocking access to property
10510  // a and function h.
10511  context->DetachGlobal();
10512  context->Global()->TurnOnAccessCheck();
10513
10514  // Failing access check to property get results in undefined.
10515  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10516  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10517
10518  // Failing access check to function call results in exception.
10519  CHECK(g1->Call(global, 0, NULL).IsEmpty());
10520  CHECK(g2->Call(global, 0, NULL).IsEmpty());
10521
10522  // No failing access check when just returning a constant.
10523  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10524
10525  // Now compile the source again. And get the newly compiled functions, except
10526  // for h for which access is blocked.
10527  CompileRun(source);
10528  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10529  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10530  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10531  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10532  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10533
10534  // Failing access check to property get results in undefined.
10535  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10536  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10537
10538  // Failing access check to function call results in exception.
10539  CHECK(g1->Call(global, 0, NULL).IsEmpty());
10540  CHECK(g2->Call(global, 0, NULL).IsEmpty());
10541}
10542
10543
10544// This test verifies that pre-compilation (aka preparsing) can be called
10545// without initializing the whole VM. Thus we cannot run this test in a
10546// multi-threaded setup.
10547TEST(PreCompile) {
10548  // TODO(155): This test would break without the initialization of V8. This is
10549  // a workaround for now to make this test not fail.
10550  v8::V8::Initialize();
10551  const char* script = "function foo(a) { return a+1; }";
10552  v8::ScriptData* sd =
10553      v8::ScriptData::PreCompile(script, i::StrLength(script));
10554  CHECK_NE(sd->Length(), 0);
10555  CHECK_NE(sd->Data(), NULL);
10556  CHECK(!sd->HasError());
10557  delete sd;
10558}
10559
10560
10561TEST(PreCompileWithError) {
10562  v8::V8::Initialize();
10563  const char* script = "function foo(a) { return 1 * * 2; }";
10564  v8::ScriptData* sd =
10565      v8::ScriptData::PreCompile(script, i::StrLength(script));
10566  CHECK(sd->HasError());
10567  delete sd;
10568}
10569
10570
10571TEST(Regress31661) {
10572  v8::V8::Initialize();
10573  const char* script = " The Definintive Guide";
10574  v8::ScriptData* sd =
10575      v8::ScriptData::PreCompile(script, i::StrLength(script));
10576  CHECK(sd->HasError());
10577  delete sd;
10578}
10579
10580
10581// Tests that ScriptData can be serialized and deserialized.
10582TEST(PreCompileSerialization) {
10583  v8::V8::Initialize();
10584  const char* script = "function foo(a) { return a+1; }";
10585  v8::ScriptData* sd =
10586      v8::ScriptData::PreCompile(script, i::StrLength(script));
10587
10588  // Serialize.
10589  int serialized_data_length = sd->Length();
10590  char* serialized_data = i::NewArray<char>(serialized_data_length);
10591  memcpy(serialized_data, sd->Data(), serialized_data_length);
10592
10593  // Deserialize.
10594  v8::ScriptData* deserialized_sd =
10595      v8::ScriptData::New(serialized_data, serialized_data_length);
10596
10597  // Verify that the original is the same as the deserialized.
10598  CHECK_EQ(sd->Length(), deserialized_sd->Length());
10599  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10600  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10601
10602  delete sd;
10603  delete deserialized_sd;
10604}
10605
10606
10607// Attempts to deserialize bad data.
10608TEST(PreCompileDeserializationError) {
10609  v8::V8::Initialize();
10610  const char* data = "DONT CARE";
10611  int invalid_size = 3;
10612  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10613
10614  CHECK_EQ(0, sd->Length());
10615
10616  delete sd;
10617}
10618
10619
10620// Attempts to deserialize bad data.
10621TEST(PreCompileInvalidPreparseDataError) {
10622  v8::V8::Initialize();
10623  v8::HandleScope scope;
10624  LocalContext context;
10625
10626  const char* script = "function foo(){ return 5;}\n"
10627      "function bar(){ return 6 + 7;}  foo();";
10628  v8::ScriptData* sd =
10629      v8::ScriptData::PreCompile(script, i::StrLength(script));
10630  CHECK(!sd->HasError());
10631  // ScriptDataImpl private implementation details
10632  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
10633  const int kFunctionEntrySize = i::FunctionEntry::kSize;
10634  const int kFunctionEntryStartOffset = 0;
10635  const int kFunctionEntryEndOffset = 1;
10636  unsigned* sd_data =
10637      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
10638
10639  // Overwrite function bar's end position with 0.
10640  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10641  v8::TryCatch try_catch;
10642
10643  Local<String> source = String::New(script);
10644  Local<Script> compiled_script = Script::New(source, NULL, sd);
10645  CHECK(try_catch.HasCaught());
10646  String::AsciiValue exception_value(try_catch.Message()->Get());
10647  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10648           *exception_value);
10649
10650  try_catch.Reset();
10651
10652  // Overwrite function bar's start position with 200.  The function entry
10653  // will not be found when searching for it by position and we should fall
10654  // back on eager compilation.
10655  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10656  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
10657  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10658      200;
10659  compiled_script = Script::New(source, NULL, sd);
10660  CHECK(!try_catch.HasCaught());
10661
10662  delete sd;
10663}
10664
10665
10666// Verifies that the Handle<String> and const char* versions of the API produce
10667// the same results (at least for one trivial case).
10668TEST(PreCompileAPIVariationsAreSame) {
10669  v8::V8::Initialize();
10670  v8::HandleScope scope;
10671
10672  const char* cstring = "function foo(a) { return a+1; }";
10673
10674  v8::ScriptData* sd_from_cstring =
10675      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10676
10677  TestAsciiResource* resource = new TestAsciiResource(cstring);
10678  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
10679      v8::String::NewExternal(resource));
10680
10681  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10682      v8::String::New(cstring));
10683
10684  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
10685  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10686                     sd_from_external_string->Data(),
10687                     sd_from_cstring->Length()));
10688
10689  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10690  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10691                     sd_from_string->Data(),
10692                     sd_from_cstring->Length()));
10693
10694
10695  delete sd_from_cstring;
10696  delete sd_from_external_string;
10697  delete sd_from_string;
10698}
10699
10700
10701// This tests that we do not allow dictionary load/call inline caches
10702// to use functions that have not yet been compiled.  The potential
10703// problem of loading a function that has not yet been compiled can
10704// arise because we share code between contexts via the compilation
10705// cache.
10706THREADED_TEST(DictionaryICLoadedFunction) {
10707  v8::HandleScope scope;
10708  // Test LoadIC.
10709  for (int i = 0; i < 2; i++) {
10710    LocalContext context;
10711    context->Global()->Set(v8_str("tmp"), v8::True());
10712    context->Global()->Delete(v8_str("tmp"));
10713    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10714  }
10715  // Test CallIC.
10716  for (int i = 0; i < 2; i++) {
10717    LocalContext context;
10718    context->Global()->Set(v8_str("tmp"), v8::True());
10719    context->Global()->Delete(v8_str("tmp"));
10720    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10721  }
10722}
10723
10724
10725// Test that cross-context new calls use the context of the callee to
10726// create the new JavaScript object.
10727THREADED_TEST(CrossContextNew) {
10728  v8::HandleScope scope;
10729  v8::Persistent<Context> context0 = Context::New();
10730  v8::Persistent<Context> context1 = Context::New();
10731
10732  // Allow cross-domain access.
10733  Local<String> token = v8_str("<security token>");
10734  context0->SetSecurityToken(token);
10735  context1->SetSecurityToken(token);
10736
10737  // Set an 'x' property on the Object prototype and define a
10738  // constructor function in context0.
10739  context0->Enter();
10740  CompileRun("Object.prototype.x = 42; function C() {};");
10741  context0->Exit();
10742
10743  // Call the constructor function from context0 and check that the
10744  // result has the 'x' property.
10745  context1->Enter();
10746  context1->Global()->Set(v8_str("other"), context0->Global());
10747  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10748  CHECK(value->IsInt32());
10749  CHECK_EQ(42, value->Int32Value());
10750  context1->Exit();
10751
10752  // Dispose the contexts to allow them to be garbage collected.
10753  context0.Dispose();
10754  context1.Dispose();
10755}
10756
10757
10758class RegExpInterruptTest {
10759 public:
10760  RegExpInterruptTest() : block_(NULL) {}
10761  ~RegExpInterruptTest() { delete block_; }
10762  void RunTest() {
10763    block_ = i::OS::CreateSemaphore(0);
10764    gc_count_ = 0;
10765    gc_during_regexp_ = 0;
10766    regexp_success_ = false;
10767    gc_success_ = false;
10768    GCThread gc_thread(this);
10769    gc_thread.Start();
10770    v8::Locker::StartPreemption(1);
10771
10772    LongRunningRegExp();
10773    {
10774      v8::Unlocker unlock;
10775      gc_thread.Join();
10776    }
10777    v8::Locker::StopPreemption();
10778    CHECK(regexp_success_);
10779    CHECK(gc_success_);
10780  }
10781
10782 private:
10783  // Number of garbage collections required.
10784  static const int kRequiredGCs = 5;
10785
10786  class GCThread : public i::Thread {
10787   public:
10788    explicit GCThread(RegExpInterruptTest* test)
10789        : Thread("GCThread"), test_(test) {}
10790    virtual void Run() {
10791      test_->CollectGarbage();
10792    }
10793   private:
10794     RegExpInterruptTest* test_;
10795  };
10796
10797  void CollectGarbage() {
10798    block_->Wait();
10799    while (gc_during_regexp_ < kRequiredGCs) {
10800      {
10801        v8::Locker lock;
10802        // TODO(lrn): Perhaps create some garbage before collecting.
10803        HEAP->CollectAllGarbage(false);
10804        gc_count_++;
10805      }
10806      i::OS::Sleep(1);
10807    }
10808    gc_success_ = true;
10809  }
10810
10811  void LongRunningRegExp() {
10812    block_->Signal();  // Enable garbage collection thread on next preemption.
10813    int rounds = 0;
10814    while (gc_during_regexp_ < kRequiredGCs) {
10815      int gc_before = gc_count_;
10816      {
10817        // Match 15-30 "a"'s against 14 and a "b".
10818        const char* c_source =
10819            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10820            ".exec('aaaaaaaaaaaaaaab') === null";
10821        Local<String> source = String::New(c_source);
10822        Local<Script> script = Script::Compile(source);
10823        Local<Value> result = script->Run();
10824        if (!result->BooleanValue()) {
10825          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
10826          return;
10827        }
10828      }
10829      {
10830        // Match 15-30 "a"'s against 15 and a "b".
10831        const char* c_source =
10832            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10833            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10834        Local<String> source = String::New(c_source);
10835        Local<Script> script = Script::Compile(source);
10836        Local<Value> result = script->Run();
10837        if (!result->BooleanValue()) {
10838          gc_during_regexp_ = kRequiredGCs;
10839          return;
10840        }
10841      }
10842      int gc_after = gc_count_;
10843      gc_during_regexp_ += gc_after - gc_before;
10844      rounds++;
10845      i::OS::Sleep(1);
10846    }
10847    regexp_success_ = true;
10848  }
10849
10850  i::Semaphore* block_;
10851  int gc_count_;
10852  int gc_during_regexp_;
10853  bool regexp_success_;
10854  bool gc_success_;
10855};
10856
10857
10858// Test that a regular expression execution can be interrupted and
10859// survive a garbage collection.
10860TEST(RegExpInterruption) {
10861  v8::Locker lock;
10862  v8::V8::Initialize();
10863  v8::HandleScope scope;
10864  Local<Context> local_env;
10865  {
10866    LocalContext env;
10867    local_env = env.local();
10868  }
10869
10870  // Local context should still be live.
10871  CHECK(!local_env.IsEmpty());
10872  local_env->Enter();
10873
10874  // Should complete without problems.
10875  RegExpInterruptTest().RunTest();
10876
10877  local_env->Exit();
10878}
10879
10880
10881class ApplyInterruptTest {
10882 public:
10883  ApplyInterruptTest() : block_(NULL) {}
10884  ~ApplyInterruptTest() { delete block_; }
10885  void RunTest() {
10886    block_ = i::OS::CreateSemaphore(0);
10887    gc_count_ = 0;
10888    gc_during_apply_ = 0;
10889    apply_success_ = false;
10890    gc_success_ = false;
10891    GCThread gc_thread(this);
10892    gc_thread.Start();
10893    v8::Locker::StartPreemption(1);
10894
10895    LongRunningApply();
10896    {
10897      v8::Unlocker unlock;
10898      gc_thread.Join();
10899    }
10900    v8::Locker::StopPreemption();
10901    CHECK(apply_success_);
10902    CHECK(gc_success_);
10903  }
10904
10905 private:
10906  // Number of garbage collections required.
10907  static const int kRequiredGCs = 2;
10908
10909  class GCThread : public i::Thread {
10910   public:
10911    explicit GCThread(ApplyInterruptTest* test)
10912        : Thread("GCThread"), test_(test) {}
10913    virtual void Run() {
10914      test_->CollectGarbage();
10915    }
10916   private:
10917     ApplyInterruptTest* test_;
10918  };
10919
10920  void CollectGarbage() {
10921    block_->Wait();
10922    while (gc_during_apply_ < kRequiredGCs) {
10923      {
10924        v8::Locker lock;
10925        HEAP->CollectAllGarbage(false);
10926        gc_count_++;
10927      }
10928      i::OS::Sleep(1);
10929    }
10930    gc_success_ = true;
10931  }
10932
10933  void LongRunningApply() {
10934    block_->Signal();
10935    int rounds = 0;
10936    while (gc_during_apply_ < kRequiredGCs) {
10937      int gc_before = gc_count_;
10938      {
10939        const char* c_source =
10940            "function do_very_little(bar) {"
10941            "  this.foo = bar;"
10942            "}"
10943            "for (var i = 0; i < 100000; i++) {"
10944            "  do_very_little.apply(this, ['bar']);"
10945            "}";
10946        Local<String> source = String::New(c_source);
10947        Local<Script> script = Script::Compile(source);
10948        Local<Value> result = script->Run();
10949        // Check that no exception was thrown.
10950        CHECK(!result.IsEmpty());
10951      }
10952      int gc_after = gc_count_;
10953      gc_during_apply_ += gc_after - gc_before;
10954      rounds++;
10955    }
10956    apply_success_ = true;
10957  }
10958
10959  i::Semaphore* block_;
10960  int gc_count_;
10961  int gc_during_apply_;
10962  bool apply_success_;
10963  bool gc_success_;
10964};
10965
10966
10967// Test that nothing bad happens if we get a preemption just when we were
10968// about to do an apply().
10969TEST(ApplyInterruption) {
10970  v8::Locker lock;
10971  v8::V8::Initialize();
10972  v8::HandleScope scope;
10973  Local<Context> local_env;
10974  {
10975    LocalContext env;
10976    local_env = env.local();
10977  }
10978
10979  // Local context should still be live.
10980  CHECK(!local_env.IsEmpty());
10981  local_env->Enter();
10982
10983  // Should complete without problems.
10984  ApplyInterruptTest().RunTest();
10985
10986  local_env->Exit();
10987}
10988
10989
10990// Verify that we can clone an object
10991TEST(ObjectClone) {
10992  v8::HandleScope scope;
10993  LocalContext env;
10994
10995  const char* sample =
10996    "var rv = {};"      \
10997    "rv.alpha = 'hello';" \
10998    "rv.beta = 123;"     \
10999    "rv;";
11000
11001  // Create an object, verify basics.
11002  Local<Value> val = CompileRun(sample);
11003  CHECK(val->IsObject());
11004  Local<v8::Object> obj = val.As<v8::Object>();
11005  obj->Set(v8_str("gamma"), v8_str("cloneme"));
11006
11007  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11008  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11009  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11010
11011  // Clone it.
11012  Local<v8::Object> clone = obj->Clone();
11013  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11014  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11015  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11016
11017  // Set a property on the clone, verify each object.
11018  clone->Set(v8_str("beta"), v8::Integer::New(456));
11019  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11020  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11021}
11022
11023
11024class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11025 public:
11026  explicit AsciiVectorResource(i::Vector<const char> vector)
11027      : data_(vector) {}
11028  virtual ~AsciiVectorResource() {}
11029  virtual size_t length() const { return data_.length(); }
11030  virtual const char* data() const { return data_.start(); }
11031 private:
11032  i::Vector<const char> data_;
11033};
11034
11035
11036class UC16VectorResource : public v8::String::ExternalStringResource {
11037 public:
11038  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11039      : data_(vector) {}
11040  virtual ~UC16VectorResource() {}
11041  virtual size_t length() const { return data_.length(); }
11042  virtual const i::uc16* data() const { return data_.start(); }
11043 private:
11044  i::Vector<const i::uc16> data_;
11045};
11046
11047
11048static void MorphAString(i::String* string,
11049                         AsciiVectorResource* ascii_resource,
11050                         UC16VectorResource* uc16_resource) {
11051  CHECK(i::StringShape(string).IsExternal());
11052  if (string->IsAsciiRepresentation()) {
11053    // Check old map is not symbol or long.
11054    CHECK(string->map() == HEAP->external_ascii_string_map());
11055    // Morph external string to be TwoByte string.
11056    string->set_map(HEAP->external_string_map());
11057    i::ExternalTwoByteString* morphed =
11058         i::ExternalTwoByteString::cast(string);
11059    morphed->set_resource(uc16_resource);
11060  } else {
11061    // Check old map is not symbol or long.
11062    CHECK(string->map() == HEAP->external_string_map());
11063    // Morph external string to be ASCII string.
11064    string->set_map(HEAP->external_ascii_string_map());
11065    i::ExternalAsciiString* morphed =
11066         i::ExternalAsciiString::cast(string);
11067    morphed->set_resource(ascii_resource);
11068  }
11069}
11070
11071
11072// Test that we can still flatten a string if the components it is built up
11073// from have been turned into 16 bit strings in the mean time.
11074THREADED_TEST(MorphCompositeStringTest) {
11075  const char* c_string = "Now is the time for all good men"
11076                         " to come to the aid of the party";
11077  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11078  {
11079    v8::HandleScope scope;
11080    LocalContext env;
11081    AsciiVectorResource ascii_resource(
11082        i::Vector<const char>(c_string, i::StrLength(c_string)));
11083    UC16VectorResource uc16_resource(
11084        i::Vector<const uint16_t>(two_byte_string,
11085                                  i::StrLength(c_string)));
11086
11087    Local<String> lhs(v8::Utils::ToLocal(
11088        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11089    Local<String> rhs(v8::Utils::ToLocal(
11090        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11091
11092    env->Global()->Set(v8_str("lhs"), lhs);
11093    env->Global()->Set(v8_str("rhs"), rhs);
11094
11095    CompileRun(
11096        "var cons = lhs + rhs;"
11097        "var slice = lhs.substring(1, lhs.length - 1);"
11098        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11099
11100    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11101    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11102
11103    // Now do some stuff to make sure the strings are flattened, etc.
11104    CompileRun(
11105        "/[^a-z]/.test(cons);"
11106        "/[^a-z]/.test(slice);"
11107        "/[^a-z]/.test(slice_on_cons);");
11108    const char* expected_cons =
11109        "Now is the time for all good men to come to the aid of the party"
11110        "Now is the time for all good men to come to the aid of the party";
11111    const char* expected_slice =
11112        "ow is the time for all good men to come to the aid of the part";
11113    const char* expected_slice_on_cons =
11114        "ow is the time for all good men to come to the aid of the party"
11115        "Now is the time for all good men to come to the aid of the part";
11116    CHECK_EQ(String::New(expected_cons),
11117             env->Global()->Get(v8_str("cons")));
11118    CHECK_EQ(String::New(expected_slice),
11119             env->Global()->Get(v8_str("slice")));
11120    CHECK_EQ(String::New(expected_slice_on_cons),
11121             env->Global()->Get(v8_str("slice_on_cons")));
11122  }
11123  i::DeleteArray(two_byte_string);
11124}
11125
11126
11127TEST(CompileExternalTwoByteSource) {
11128  v8::HandleScope scope;
11129  LocalContext context;
11130
11131  // This is a very short list of sources, which currently is to check for a
11132  // regression caused by r2703.
11133  const char* ascii_sources[] = {
11134    "0.5",
11135    "-0.5",   // This mainly testes PushBack in the Scanner.
11136    "--0.5",  // This mainly testes PushBack in the Scanner.
11137    NULL
11138  };
11139
11140  // Compile the sources as external two byte strings.
11141  for (int i = 0; ascii_sources[i] != NULL; i++) {
11142    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11143    UC16VectorResource uc16_resource(
11144        i::Vector<const uint16_t>(two_byte_string,
11145                                  i::StrLength(ascii_sources[i])));
11146    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11147    v8::Script::Compile(source);
11148    i::DeleteArray(two_byte_string);
11149  }
11150}
11151
11152
11153class RegExpStringModificationTest {
11154 public:
11155  RegExpStringModificationTest()
11156      : block_(i::OS::CreateSemaphore(0)),
11157        morphs_(0),
11158        morphs_during_regexp_(0),
11159        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11160        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11161  ~RegExpStringModificationTest() { delete block_; }
11162  void RunTest() {
11163    regexp_success_ = false;
11164    morph_success_ = false;
11165
11166    // Initialize the contents of two_byte_content_ to be a uc16 representation
11167    // of "aaaaaaaaaaaaaab".
11168    for (int i = 0; i < 14; i++) {
11169      two_byte_content_[i] = 'a';
11170    }
11171    two_byte_content_[14] = 'b';
11172
11173    // Create the input string for the regexp - the one we are going to change
11174    // properties of.
11175    input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
11176
11177    // Inject the input as a global variable.
11178    i::Handle<i::String> input_name =
11179        FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11180    i::Isolate::Current()->global_context()->global()->SetProperty(
11181        *input_name,
11182        *input_,
11183        NONE,
11184        i::kNonStrictMode)->ToObjectChecked();
11185
11186    MorphThread morph_thread(this);
11187    morph_thread.Start();
11188    v8::Locker::StartPreemption(1);
11189    LongRunningRegExp();
11190    {
11191      v8::Unlocker unlock;
11192      morph_thread.Join();
11193    }
11194    v8::Locker::StopPreemption();
11195    CHECK(regexp_success_);
11196    CHECK(morph_success_);
11197  }
11198
11199 private:
11200  // Number of string modifications required.
11201  static const int kRequiredModifications = 5;
11202  static const int kMaxModifications = 100;
11203
11204  class MorphThread : public i::Thread {
11205   public:
11206    explicit MorphThread(RegExpStringModificationTest* test)
11207        : Thread("MorphThread"), test_(test) {}
11208    virtual void Run() {
11209      test_->MorphString();
11210    }
11211   private:
11212     RegExpStringModificationTest* test_;
11213  };
11214
11215  void MorphString() {
11216    block_->Wait();
11217    while (morphs_during_regexp_ < kRequiredModifications &&
11218           morphs_ < kMaxModifications) {
11219      {
11220        v8::Locker lock;
11221        // Swap string between ascii and two-byte representation.
11222        i::String* string = *input_;
11223        MorphAString(string, &ascii_resource_, &uc16_resource_);
11224        morphs_++;
11225      }
11226      i::OS::Sleep(1);
11227    }
11228    morph_success_ = true;
11229  }
11230
11231  void LongRunningRegExp() {
11232    block_->Signal();  // Enable morphing thread on next preemption.
11233    while (morphs_during_regexp_ < kRequiredModifications &&
11234           morphs_ < kMaxModifications) {
11235      int morphs_before = morphs_;
11236      {
11237        v8::HandleScope scope;
11238        // Match 15-30 "a"'s against 14 and a "b".
11239        const char* c_source =
11240            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11241            ".exec(input) === null";
11242        Local<String> source = String::New(c_source);
11243        Local<Script> script = Script::Compile(source);
11244        Local<Value> result = script->Run();
11245        CHECK(result->IsTrue());
11246      }
11247      int morphs_after = morphs_;
11248      morphs_during_regexp_ += morphs_after - morphs_before;
11249    }
11250    regexp_success_ = true;
11251  }
11252
11253  i::uc16 two_byte_content_[15];
11254  i::Semaphore* block_;
11255  int morphs_;
11256  int morphs_during_regexp_;
11257  bool regexp_success_;
11258  bool morph_success_;
11259  i::Handle<i::String> input_;
11260  AsciiVectorResource ascii_resource_;
11261  UC16VectorResource uc16_resource_;
11262};
11263
11264
11265// Test that a regular expression execution can be interrupted and
11266// the string changed without failing.
11267TEST(RegExpStringModification) {
11268  v8::Locker lock;
11269  v8::V8::Initialize();
11270  v8::HandleScope scope;
11271  Local<Context> local_env;
11272  {
11273    LocalContext env;
11274    local_env = env.local();
11275  }
11276
11277  // Local context should still be live.
11278  CHECK(!local_env.IsEmpty());
11279  local_env->Enter();
11280
11281  // Should complete without problems.
11282  RegExpStringModificationTest().RunTest();
11283
11284  local_env->Exit();
11285}
11286
11287
11288// Test that we can set a property on the global object even if there
11289// is a read-only property in the prototype chain.
11290TEST(ReadOnlyPropertyInGlobalProto) {
11291  v8::HandleScope scope;
11292  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11293  LocalContext context(0, templ);
11294  v8::Handle<v8::Object> global = context->Global();
11295  v8::Handle<v8::Object> global_proto =
11296      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11297  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11298  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11299  // Check without 'eval' or 'with'.
11300  v8::Handle<v8::Value> res =
11301      CompileRun("function f() { x = 42; return x; }; f()");
11302  // Check with 'eval'.
11303  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11304  CHECK_EQ(v8::Integer::New(42), res);
11305  // Check with 'with'.
11306  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11307  CHECK_EQ(v8::Integer::New(42), res);
11308}
11309
11310static int force_set_set_count = 0;
11311static int force_set_get_count = 0;
11312bool pass_on_get = false;
11313
11314static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11315                                            const v8::AccessorInfo& info) {
11316  force_set_get_count++;
11317  if (pass_on_get) {
11318    return v8::Handle<v8::Value>();
11319  } else {
11320    return v8::Int32::New(3);
11321  }
11322}
11323
11324static void ForceSetSetter(v8::Local<v8::String> name,
11325                           v8::Local<v8::Value> value,
11326                           const v8::AccessorInfo& info) {
11327  force_set_set_count++;
11328}
11329
11330static v8::Handle<v8::Value> ForceSetInterceptSetter(
11331    v8::Local<v8::String> name,
11332    v8::Local<v8::Value> value,
11333    const v8::AccessorInfo& info) {
11334  force_set_set_count++;
11335  return v8::Undefined();
11336}
11337
11338TEST(ForceSet) {
11339  force_set_get_count = 0;
11340  force_set_set_count = 0;
11341  pass_on_get = false;
11342
11343  v8::HandleScope scope;
11344  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11345  v8::Handle<v8::String> access_property = v8::String::New("a");
11346  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11347  LocalContext context(NULL, templ);
11348  v8::Handle<v8::Object> global = context->Global();
11349
11350  // Ordinary properties
11351  v8::Handle<v8::String> simple_property = v8::String::New("p");
11352  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11353  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11354  // This should fail because the property is read-only
11355  global->Set(simple_property, v8::Int32::New(5));
11356  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11357  // This should succeed even though the property is read-only
11358  global->ForceSet(simple_property, v8::Int32::New(6));
11359  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11360
11361  // Accessors
11362  CHECK_EQ(0, force_set_set_count);
11363  CHECK_EQ(0, force_set_get_count);
11364  CHECK_EQ(3, global->Get(access_property)->Int32Value());
11365  // CHECK_EQ the property shouldn't override it, just call the setter
11366  // which in this case does nothing.
11367  global->Set(access_property, v8::Int32::New(7));
11368  CHECK_EQ(3, global->Get(access_property)->Int32Value());
11369  CHECK_EQ(1, force_set_set_count);
11370  CHECK_EQ(2, force_set_get_count);
11371  // Forcing the property to be set should override the accessor without
11372  // calling it
11373  global->ForceSet(access_property, v8::Int32::New(8));
11374  CHECK_EQ(8, global->Get(access_property)->Int32Value());
11375  CHECK_EQ(1, force_set_set_count);
11376  CHECK_EQ(2, force_set_get_count);
11377}
11378
11379TEST(ForceSetWithInterceptor) {
11380  force_set_get_count = 0;
11381  force_set_set_count = 0;
11382  pass_on_get = false;
11383
11384  v8::HandleScope scope;
11385  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11386  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11387  LocalContext context(NULL, templ);
11388  v8::Handle<v8::Object> global = context->Global();
11389
11390  v8::Handle<v8::String> some_property = v8::String::New("a");
11391  CHECK_EQ(0, force_set_set_count);
11392  CHECK_EQ(0, force_set_get_count);
11393  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11394  // Setting the property shouldn't override it, just call the setter
11395  // which in this case does nothing.
11396  global->Set(some_property, v8::Int32::New(7));
11397  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11398  CHECK_EQ(1, force_set_set_count);
11399  CHECK_EQ(2, force_set_get_count);
11400  // Getting the property when the interceptor returns an empty handle
11401  // should yield undefined, since the property isn't present on the
11402  // object itself yet.
11403  pass_on_get = true;
11404  CHECK(global->Get(some_property)->IsUndefined());
11405  CHECK_EQ(1, force_set_set_count);
11406  CHECK_EQ(3, force_set_get_count);
11407  // Forcing the property to be set should cause the value to be
11408  // set locally without calling the interceptor.
11409  global->ForceSet(some_property, v8::Int32::New(8));
11410  CHECK_EQ(8, global->Get(some_property)->Int32Value());
11411  CHECK_EQ(1, force_set_set_count);
11412  CHECK_EQ(4, force_set_get_count);
11413  // Reenabling the interceptor should cause it to take precedence over
11414  // the property
11415  pass_on_get = false;
11416  CHECK_EQ(3, global->Get(some_property)->Int32Value());
11417  CHECK_EQ(1, force_set_set_count);
11418  CHECK_EQ(5, force_set_get_count);
11419  // The interceptor should also work for other properties
11420  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11421  CHECK_EQ(1, force_set_set_count);
11422  CHECK_EQ(6, force_set_get_count);
11423}
11424
11425
11426THREADED_TEST(ForceDelete) {
11427  v8::HandleScope scope;
11428  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11429  LocalContext context(NULL, templ);
11430  v8::Handle<v8::Object> global = context->Global();
11431
11432  // Ordinary properties
11433  v8::Handle<v8::String> simple_property = v8::String::New("p");
11434  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11435  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11436  // This should fail because the property is dont-delete.
11437  CHECK(!global->Delete(simple_property));
11438  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11439  // This should succeed even though the property is dont-delete.
11440  CHECK(global->ForceDelete(simple_property));
11441  CHECK(global->Get(simple_property)->IsUndefined());
11442}
11443
11444
11445static int force_delete_interceptor_count = 0;
11446static bool pass_on_delete = false;
11447
11448
11449static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11450    v8::Local<v8::String> name,
11451    const v8::AccessorInfo& info) {
11452  force_delete_interceptor_count++;
11453  if (pass_on_delete) {
11454    return v8::Handle<v8::Boolean>();
11455  } else {
11456    return v8::True();
11457  }
11458}
11459
11460
11461THREADED_TEST(ForceDeleteWithInterceptor) {
11462  force_delete_interceptor_count = 0;
11463  pass_on_delete = false;
11464
11465  v8::HandleScope scope;
11466  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11467  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11468  LocalContext context(NULL, templ);
11469  v8::Handle<v8::Object> global = context->Global();
11470
11471  v8::Handle<v8::String> some_property = v8::String::New("a");
11472  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11473
11474  // Deleting a property should get intercepted and nothing should
11475  // happen.
11476  CHECK_EQ(0, force_delete_interceptor_count);
11477  CHECK(global->Delete(some_property));
11478  CHECK_EQ(1, force_delete_interceptor_count);
11479  CHECK_EQ(42, global->Get(some_property)->Int32Value());
11480  // Deleting the property when the interceptor returns an empty
11481  // handle should not delete the property since it is DontDelete.
11482  pass_on_delete = true;
11483  CHECK(!global->Delete(some_property));
11484  CHECK_EQ(2, force_delete_interceptor_count);
11485  CHECK_EQ(42, global->Get(some_property)->Int32Value());
11486  // Forcing the property to be deleted should delete the value
11487  // without calling the interceptor.
11488  CHECK(global->ForceDelete(some_property));
11489  CHECK(global->Get(some_property)->IsUndefined());
11490  CHECK_EQ(2, force_delete_interceptor_count);
11491}
11492
11493
11494// Make sure that forcing a delete invalidates any IC stubs, so we
11495// don't read the hole value.
11496THREADED_TEST(ForceDeleteIC) {
11497  v8::HandleScope scope;
11498  LocalContext context;
11499  // Create a DontDelete variable on the global object.
11500  CompileRun("this.__proto__ = { foo: 'horse' };"
11501             "var foo = 'fish';"
11502             "function f() { return foo.length; }");
11503  // Initialize the IC for foo in f.
11504  CompileRun("for (var i = 0; i < 4; i++) f();");
11505  // Make sure the value of foo is correct before the deletion.
11506  CHECK_EQ(4, CompileRun("f()")->Int32Value());
11507  // Force the deletion of foo.
11508  CHECK(context->Global()->ForceDelete(v8_str("foo")));
11509  // Make sure the value for foo is read from the prototype, and that
11510  // we don't get in trouble with reading the deleted cell value
11511  // sentinel.
11512  CHECK_EQ(5, CompileRun("f()")->Int32Value());
11513}
11514
11515
11516v8::Persistent<Context> calling_context0;
11517v8::Persistent<Context> calling_context1;
11518v8::Persistent<Context> calling_context2;
11519
11520
11521// Check that the call to the callback is initiated in
11522// calling_context2, the directly calling context is calling_context1
11523// and the callback itself is in calling_context0.
11524static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11525  ApiTestFuzzer::Fuzz();
11526  CHECK(Context::GetCurrent() == calling_context0);
11527  CHECK(Context::GetCalling() == calling_context1);
11528  CHECK(Context::GetEntered() == calling_context2);
11529  return v8::Integer::New(42);
11530}
11531
11532
11533THREADED_TEST(GetCallingContext) {
11534  v8::HandleScope scope;
11535
11536  calling_context0 = Context::New();
11537  calling_context1 = Context::New();
11538  calling_context2 = Context::New();
11539
11540  // Allow cross-domain access.
11541  Local<String> token = v8_str("<security token>");
11542  calling_context0->SetSecurityToken(token);
11543  calling_context1->SetSecurityToken(token);
11544  calling_context2->SetSecurityToken(token);
11545
11546  // Create an object with a C++ callback in context0.
11547  calling_context0->Enter();
11548  Local<v8::FunctionTemplate> callback_templ =
11549      v8::FunctionTemplate::New(GetCallingContextCallback);
11550  calling_context0->Global()->Set(v8_str("callback"),
11551                                  callback_templ->GetFunction());
11552  calling_context0->Exit();
11553
11554  // Expose context0 in context1 and setup a function that calls the
11555  // callback function.
11556  calling_context1->Enter();
11557  calling_context1->Global()->Set(v8_str("context0"),
11558                                  calling_context0->Global());
11559  CompileRun("function f() { context0.callback() }");
11560  calling_context1->Exit();
11561
11562  // Expose context1 in context2 and call the callback function in
11563  // context0 indirectly through f in context1.
11564  calling_context2->Enter();
11565  calling_context2->Global()->Set(v8_str("context1"),
11566                                  calling_context1->Global());
11567  CompileRun("context1.f()");
11568  calling_context2->Exit();
11569
11570  // Dispose the contexts to allow them to be garbage collected.
11571  calling_context0.Dispose();
11572  calling_context1.Dispose();
11573  calling_context2.Dispose();
11574  calling_context0.Clear();
11575  calling_context1.Clear();
11576  calling_context2.Clear();
11577}
11578
11579
11580// Check that a variable declaration with no explicit initialization
11581// value does not shadow an existing property in the prototype chain.
11582//
11583// This is consistent with Firefox and Safari.
11584//
11585// See http://crbug.com/12548.
11586THREADED_TEST(InitGlobalVarInProtoChain) {
11587  v8::HandleScope scope;
11588  LocalContext context;
11589  // Introduce a variable in the prototype chain.
11590  CompileRun("__proto__.x = 42");
11591  v8::Handle<v8::Value> result = CompileRun("var x; x");
11592  CHECK(!result->IsUndefined());
11593  CHECK_EQ(42, result->Int32Value());
11594}
11595
11596
11597// Regression test for issue 398.
11598// If a function is added to an object, creating a constant function
11599// field, and the result is cloned, replacing the constant function on the
11600// original should not affect the clone.
11601// See http://code.google.com/p/v8/issues/detail?id=398
11602THREADED_TEST(ReplaceConstantFunction) {
11603  v8::HandleScope scope;
11604  LocalContext context;
11605  v8::Handle<v8::Object> obj = v8::Object::New();
11606  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11607  v8::Handle<v8::String> foo_string = v8::String::New("foo");
11608  obj->Set(foo_string, func_templ->GetFunction());
11609  v8::Handle<v8::Object> obj_clone = obj->Clone();
11610  obj_clone->Set(foo_string, v8::String::New("Hello"));
11611  CHECK(!obj->Get(foo_string)->IsUndefined());
11612}
11613
11614
11615// Regression test for http://crbug.com/16276.
11616THREADED_TEST(Regress16276) {
11617  v8::HandleScope scope;
11618  LocalContext context;
11619  // Force the IC in f to be a dictionary load IC.
11620  CompileRun("function f(obj) { return obj.x; }\n"
11621             "var obj = { x: { foo: 42 }, y: 87 };\n"
11622             "var x = obj.x;\n"
11623             "delete obj.y;\n"
11624             "for (var i = 0; i < 5; i++) f(obj);");
11625  // Detach the global object to make 'this' refer directly to the
11626  // global object (not the proxy), and make sure that the dictionary
11627  // load IC doesn't mess up loading directly from the global object.
11628  context->DetachGlobal();
11629  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11630}
11631
11632
11633THREADED_TEST(PixelArray) {
11634  v8::HandleScope scope;
11635  LocalContext context;
11636  const int kElementCount = 260;
11637  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
11638  i::Handle<i::ExternalPixelArray> pixels =
11639      i::Handle<i::ExternalPixelArray>::cast(
11640          FACTORY->NewExternalArray(kElementCount,
11641                                       v8::kExternalPixelArray,
11642                                       pixel_data));
11643  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11644  for (int i = 0; i < kElementCount; i++) {
11645    pixels->set(i, i % 256);
11646  }
11647  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
11648  for (int i = 0; i < kElementCount; i++) {
11649    CHECK_EQ(i % 256, pixels->get(i));
11650    CHECK_EQ(i % 256, pixel_data[i]);
11651  }
11652
11653  v8::Handle<v8::Object> obj = v8::Object::New();
11654  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11655  // Set the elements to be the pixels.
11656  // jsobj->set_elements(*pixels);
11657  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
11658  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11659  obj->Set(v8_str("field"), v8::Int32::New(1503));
11660  context->Global()->Set(v8_str("pixels"), obj);
11661  v8::Handle<v8::Value> result = CompileRun("pixels.field");
11662  CHECK_EQ(1503, result->Int32Value());
11663  result = CompileRun("pixels[1]");
11664  CHECK_EQ(1, result->Int32Value());
11665
11666  result = CompileRun("var sum = 0;"
11667                      "for (var i = 0; i < 8; i++) {"
11668                      "  sum += pixels[i] = pixels[i] = -i;"
11669                      "}"
11670                      "sum;");
11671  CHECK_EQ(-28, result->Int32Value());
11672
11673  result = CompileRun("var sum = 0;"
11674                      "for (var i = 0; i < 8; i++) {"
11675                      "  sum += pixels[i] = pixels[i] = 0;"
11676                      "}"
11677                      "sum;");
11678  CHECK_EQ(0, result->Int32Value());
11679
11680  result = CompileRun("var sum = 0;"
11681                      "for (var i = 0; i < 8; i++) {"
11682                      "  sum += pixels[i] = pixels[i] = 255;"
11683                      "}"
11684                      "sum;");
11685  CHECK_EQ(8 * 255, result->Int32Value());
11686
11687  result = CompileRun("var sum = 0;"
11688                      "for (var i = 0; i < 8; i++) {"
11689                      "  sum += pixels[i] = pixels[i] = 256 + i;"
11690                      "}"
11691                      "sum;");
11692  CHECK_EQ(2076, result->Int32Value());
11693
11694  result = CompileRun("var sum = 0;"
11695                      "for (var i = 0; i < 8; i++) {"
11696                      "  sum += pixels[i] = pixels[i] = i;"
11697                      "}"
11698                      "sum;");
11699  CHECK_EQ(28, result->Int32Value());
11700
11701  result = CompileRun("var sum = 0;"
11702                      "for (var i = 0; i < 8; i++) {"
11703                      "  sum += pixels[i];"
11704                      "}"
11705                      "sum;");
11706  CHECK_EQ(28, result->Int32Value());
11707
11708  i::Handle<i::Smi> value(i::Smi::FromInt(2));
11709  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11710  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11711  *value.location() = i::Smi::FromInt(256);
11712  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11713  CHECK_EQ(255,
11714           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11715  *value.location() = i::Smi::FromInt(-1);
11716  i::SetElement(jsobj, 1, value, i::kNonStrictMode);
11717  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11718
11719  result = CompileRun("for (var i = 0; i < 8; i++) {"
11720                      "  pixels[i] = (i * 65) - 109;"
11721                      "}"
11722                      "pixels[1] + pixels[6];");
11723  CHECK_EQ(255, result->Int32Value());
11724  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11725  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11726  CHECK_EQ(21,
11727           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11728  CHECK_EQ(86,
11729           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11730  CHECK_EQ(151,
11731           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11732  CHECK_EQ(216,
11733           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11734  CHECK_EQ(255,
11735           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11736  CHECK_EQ(255,
11737           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11738  result = CompileRun("var sum = 0;"
11739                      "for (var i = 0; i < 8; i++) {"
11740                      "  sum += pixels[i];"
11741                      "}"
11742                      "sum;");
11743  CHECK_EQ(984, result->Int32Value());
11744
11745  result = CompileRun("for (var i = 0; i < 8; i++) {"
11746                      "  pixels[i] = (i * 1.1);"
11747                      "}"
11748                      "pixels[1] + pixels[6];");
11749  CHECK_EQ(8, result->Int32Value());
11750  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11751  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11752  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11753  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11754  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11755  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11756  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11757  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11758
11759  result = CompileRun("for (var i = 0; i < 8; i++) {"
11760                      "  pixels[7] = undefined;"
11761                      "}"
11762                      "pixels[7];");
11763  CHECK_EQ(0, result->Int32Value());
11764  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
11765
11766  result = CompileRun("for (var i = 0; i < 8; i++) {"
11767                      "  pixels[6] = '2.3';"
11768                      "}"
11769                      "pixels[6];");
11770  CHECK_EQ(2, result->Int32Value());
11771  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11772
11773  result = CompileRun("for (var i = 0; i < 8; i++) {"
11774                      "  pixels[5] = NaN;"
11775                      "}"
11776                      "pixels[5];");
11777  CHECK_EQ(0, result->Int32Value());
11778  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11779
11780  result = CompileRun("for (var i = 0; i < 8; i++) {"
11781                      "  pixels[8] = Infinity;"
11782                      "}"
11783                      "pixels[8];");
11784  CHECK_EQ(255, result->Int32Value());
11785  CHECK_EQ(255,
11786           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
11787
11788  result = CompileRun("for (var i = 0; i < 8; i++) {"
11789                      "  pixels[9] = -Infinity;"
11790                      "}"
11791                      "pixels[9];");
11792  CHECK_EQ(0, result->Int32Value());
11793  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
11794
11795  result = CompileRun("pixels[3] = 33;"
11796                      "delete pixels[3];"
11797                      "pixels[3];");
11798  CHECK_EQ(33, result->Int32Value());
11799
11800  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11801                      "pixels[2] = 12; pixels[3] = 13;"
11802                      "pixels.__defineGetter__('2',"
11803                      "function() { return 120; });"
11804                      "pixels[2];");
11805  CHECK_EQ(12, result->Int32Value());
11806
11807  result = CompileRun("var js_array = new Array(40);"
11808                      "js_array[0] = 77;"
11809                      "js_array;");
11810  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11811
11812  result = CompileRun("pixels[1] = 23;"
11813                      "pixels.__proto__ = [];"
11814                      "js_array.__proto__ = pixels;"
11815                      "js_array.concat(pixels);");
11816  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11817  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11818
11819  result = CompileRun("pixels[1] = 23;");
11820  CHECK_EQ(23, result->Int32Value());
11821
11822  // Test for index greater than 255.  Regression test for:
11823  // http://code.google.com/p/chromium/issues/detail?id=26337.
11824  result = CompileRun("pixels[256] = 255;");
11825  CHECK_EQ(255, result->Int32Value());
11826  result = CompileRun("var i = 0;"
11827                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11828                      "i");
11829  CHECK_EQ(255, result->Int32Value());
11830
11831  // Make sure that pixel array ICs recognize when a non-pixel array
11832  // is passed to it.
11833  result = CompileRun("function pa_load(p) {"
11834                      "  var sum = 0;"
11835                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11836                      "  return sum;"
11837                      "}"
11838                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11839                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11840                      "just_ints = new Object();"
11841                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11842                      "for (var i = 0; i < 10; ++i) {"
11843                      "  result = pa_load(just_ints);"
11844                      "}"
11845                      "result");
11846  CHECK_EQ(32640, result->Int32Value());
11847
11848  // Make sure that pixel array ICs recognize out-of-bound accesses.
11849  result = CompileRun("function pa_load(p, start) {"
11850                      "  var sum = 0;"
11851                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11852                      "  return sum;"
11853                      "}"
11854                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11855                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11856                      "for (var i = 0; i < 10; ++i) {"
11857                      "  result = pa_load(pixels,-10);"
11858                      "}"
11859                      "result");
11860  CHECK_EQ(0, result->Int32Value());
11861
11862  // Make sure that generic ICs properly handles a pixel array.
11863  result = CompileRun("function pa_load(p) {"
11864                      "  var sum = 0;"
11865                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11866                      "  return sum;"
11867                      "}"
11868                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11869                      "just_ints = new Object();"
11870                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11871                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11872                      "for (var i = 0; i < 10; ++i) {"
11873                      "  result = pa_load(pixels);"
11874                      "}"
11875                      "result");
11876  CHECK_EQ(32640, result->Int32Value());
11877
11878  // Make sure that generic load ICs recognize out-of-bound accesses in
11879  // pixel arrays.
11880  result = CompileRun("function pa_load(p, start) {"
11881                      "  var sum = 0;"
11882                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
11883                      "  return sum;"
11884                      "}"
11885                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11886                      "just_ints = new Object();"
11887                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11888                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11889                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11890                      "for (var i = 0; i < 10; ++i) {"
11891                      "  result = pa_load(pixels,-10);"
11892                      "}"
11893                      "result");
11894  CHECK_EQ(0, result->Int32Value());
11895
11896  // Make sure that generic ICs properly handles other types than pixel
11897  // arrays (that the inlined fast pixel array test leaves the right information
11898  // in the right registers).
11899  result = CompileRun("function pa_load(p) {"
11900                      "  var sum = 0;"
11901                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
11902                      "  return sum;"
11903                      "}"
11904                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11905                      "just_ints = new Object();"
11906                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11907                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11908                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11909                      "sparse_array = new Object();"
11910                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11911                      "sparse_array[1000000] = 3;"
11912                      "for (var i = 0; i < 10; ++i) {"
11913                      "  result = pa_load(sparse_array);"
11914                      "}"
11915                      "result");
11916  CHECK_EQ(32640, result->Int32Value());
11917
11918  // Make sure that pixel array store ICs clamp values correctly.
11919  result = CompileRun("function pa_store(p) {"
11920                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11921                      "}"
11922                      "pa_store(pixels);"
11923                      "var sum = 0;"
11924                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11925                      "sum");
11926  CHECK_EQ(48896, result->Int32Value());
11927
11928  // Make sure that pixel array stores correctly handle accesses outside
11929  // of the pixel array..
11930  result = CompileRun("function pa_store(p,start) {"
11931                      "  for (var j = 0; j < 256; j++) {"
11932                      "    p[j+start] = j * 2;"
11933                      "  }"
11934                      "}"
11935                      "pa_store(pixels,0);"
11936                      "pa_store(pixels,-128);"
11937                      "var sum = 0;"
11938                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11939                      "sum");
11940  CHECK_EQ(65280, result->Int32Value());
11941
11942  // Make sure that the generic store stub correctly handle accesses outside
11943  // of the pixel array..
11944  result = CompileRun("function pa_store(p,start) {"
11945                      "  for (var j = 0; j < 256; j++) {"
11946                      "    p[j+start] = j * 2;"
11947                      "  }"
11948                      "}"
11949                      "pa_store(pixels,0);"
11950                      "just_ints = new Object();"
11951                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11952                      "pa_store(just_ints, 0);"
11953                      "pa_store(pixels,-128);"
11954                      "var sum = 0;"
11955                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11956                      "sum");
11957  CHECK_EQ(65280, result->Int32Value());
11958
11959  // Make sure that the generic keyed store stub clamps pixel array values
11960  // correctly.
11961  result = CompileRun("function pa_store(p) {"
11962                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11963                      "}"
11964                      "pa_store(pixels);"
11965                      "just_ints = new Object();"
11966                      "pa_store(just_ints);"
11967                      "pa_store(pixels);"
11968                      "var sum = 0;"
11969                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11970                      "sum");
11971  CHECK_EQ(48896, result->Int32Value());
11972
11973  // Make sure that pixel array loads are optimized by crankshaft.
11974  result = CompileRun("function pa_load(p) {"
11975                      "  var sum = 0;"
11976                      "  for (var i=0; i<256; ++i) {"
11977                      "    sum += p[i];"
11978                      "  }"
11979                      "  return sum; "
11980                      "}"
11981                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11982                      "for (var i = 0; i < 5000; ++i) {"
11983                      "  result = pa_load(pixels);"
11984                      "}"
11985                      "result");
11986  CHECK_EQ(32640, result->Int32Value());
11987
11988  // Make sure that pixel array stores are optimized by crankshaft.
11989  result = CompileRun("function pa_init(p) {"
11990                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11991                      "}"
11992                      "function pa_load(p) {"
11993                      "  var sum = 0;"
11994                      "  for (var i=0; i<256; ++i) {"
11995                      "    sum += p[i];"
11996                      "  }"
11997                      "  return sum; "
11998                      "}"
11999                      "for (var i = 0; i < 5000; ++i) {"
12000                      "  pa_init(pixels);"
12001                      "}"
12002                      "result = pa_load(pixels);"
12003                      "result");
12004  CHECK_EQ(32640, result->Int32Value());
12005
12006  free(pixel_data);
12007}
12008
12009
12010THREADED_TEST(PixelArrayInfo) {
12011  v8::HandleScope scope;
12012  LocalContext context;
12013  for (int size = 0; size < 100; size += 10) {
12014    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12015    v8::Handle<v8::Object> obj = v8::Object::New();
12016    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12017    CHECK(obj->HasIndexedPropertiesInPixelData());
12018    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12019    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12020    free(pixel_data);
12021  }
12022}
12023
12024
12025static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12026    uint32_t index,
12027    const AccessorInfo& info) {
12028  ApiTestFuzzer::Fuzz();
12029  return v8::Handle<Value>();
12030}
12031
12032
12033static v8::Handle<Value> NotHandledIndexedPropertySetter(
12034    uint32_t index,
12035    Local<Value> value,
12036    const AccessorInfo& info) {
12037  ApiTestFuzzer::Fuzz();
12038  return v8::Handle<Value>();
12039}
12040
12041
12042THREADED_TEST(PixelArrayWithInterceptor) {
12043  v8::HandleScope scope;
12044  LocalContext context;
12045  const int kElementCount = 260;
12046  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12047  i::Handle<i::ExternalPixelArray> pixels =
12048      i::Handle<i::ExternalPixelArray>::cast(
12049          FACTORY->NewExternalArray(kElementCount,
12050                                    v8::kExternalPixelArray,
12051                                    pixel_data));
12052  for (int i = 0; i < kElementCount; i++) {
12053    pixels->set(i, i % 256);
12054  }
12055  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12056  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12057                                   NotHandledIndexedPropertySetter);
12058  v8::Handle<v8::Object> obj = templ->NewInstance();
12059  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12060  context->Global()->Set(v8_str("pixels"), obj);
12061  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12062  CHECK_EQ(1, result->Int32Value());
12063  result = CompileRun("var sum = 0;"
12064                      "for (var i = 0; i < 8; i++) {"
12065                      "  sum += pixels[i] = pixels[i] = -i;"
12066                      "}"
12067                      "sum;");
12068  CHECK_EQ(-28, result->Int32Value());
12069  result = CompileRun("pixels.hasOwnProperty('1')");
12070  CHECK(result->BooleanValue());
12071  free(pixel_data);
12072}
12073
12074
12075static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12076  switch (array_type) {
12077    case v8::kExternalByteArray:
12078    case v8::kExternalUnsignedByteArray:
12079    case v8::kExternalPixelArray:
12080      return 1;
12081      break;
12082    case v8::kExternalShortArray:
12083    case v8::kExternalUnsignedShortArray:
12084      return 2;
12085      break;
12086    case v8::kExternalIntArray:
12087    case v8::kExternalUnsignedIntArray:
12088    case v8::kExternalFloatArray:
12089      return 4;
12090      break;
12091    case v8::kExternalDoubleArray:
12092      return 8;
12093      break;
12094    default:
12095      UNREACHABLE();
12096      return -1;
12097  }
12098  UNREACHABLE();
12099  return -1;
12100}
12101
12102
12103template <class ExternalArrayClass, class ElementType>
12104static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12105                                    int64_t low,
12106                                    int64_t high) {
12107  v8::HandleScope scope;
12108  LocalContext context;
12109  const int kElementCount = 40;
12110  int element_size = ExternalArrayElementSize(array_type);
12111  ElementType* array_data =
12112      static_cast<ElementType*>(malloc(kElementCount * element_size));
12113  i::Handle<ExternalArrayClass> array =
12114      i::Handle<ExternalArrayClass>::cast(
12115          FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12116  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
12117  for (int i = 0; i < kElementCount; i++) {
12118    array->set(i, static_cast<ElementType>(i));
12119  }
12120  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
12121  for (int i = 0; i < kElementCount; i++) {
12122    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
12123    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12124  }
12125
12126  v8::Handle<v8::Object> obj = v8::Object::New();
12127  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12128  // Set the elements to be the external array.
12129  obj->SetIndexedPropertiesToExternalArrayData(array_data,
12130                                               array_type,
12131                                               kElementCount);
12132  CHECK_EQ(
12133      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
12134  obj->Set(v8_str("field"), v8::Int32::New(1503));
12135  context->Global()->Set(v8_str("ext_array"), obj);
12136  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12137  CHECK_EQ(1503, result->Int32Value());
12138  result = CompileRun("ext_array[1]");
12139  CHECK_EQ(1, result->Int32Value());
12140
12141  // Check pass through of assigned smis
12142  result = CompileRun("var sum = 0;"
12143                      "for (var i = 0; i < 8; i++) {"
12144                      "  sum += ext_array[i] = ext_array[i] = -i;"
12145                      "}"
12146                      "sum;");
12147  CHECK_EQ(-28, result->Int32Value());
12148
12149  // Check assigned smis
12150  result = CompileRun("for (var i = 0; i < 8; i++) {"
12151                      "  ext_array[i] = i;"
12152                      "}"
12153                      "var sum = 0;"
12154                      "for (var i = 0; i < 8; i++) {"
12155                      "  sum += ext_array[i];"
12156                      "}"
12157                      "sum;");
12158  CHECK_EQ(28, result->Int32Value());
12159
12160  // Check assigned smis in reverse order
12161  result = CompileRun("for (var i = 8; --i >= 0; ) {"
12162                      "  ext_array[i] = i;"
12163                      "}"
12164                      "var sum = 0;"
12165                      "for (var i = 0; i < 8; i++) {"
12166                      "  sum += ext_array[i];"
12167                      "}"
12168                      "sum;");
12169  CHECK_EQ(28, result->Int32Value());
12170
12171  // Check pass through of assigned HeapNumbers
12172  result = CompileRun("var sum = 0;"
12173                      "for (var i = 0; i < 16; i+=2) {"
12174                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12175                      "}"
12176                      "sum;");
12177  CHECK_EQ(-28, result->Int32Value());
12178
12179  // Check assigned HeapNumbers
12180  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12181                      "  ext_array[i] = (i * 0.5);"
12182                      "}"
12183                      "var sum = 0;"
12184                      "for (var i = 0; i < 16; i+=2) {"
12185                      "  sum += ext_array[i];"
12186                      "}"
12187                      "sum;");
12188  CHECK_EQ(28, result->Int32Value());
12189
12190  // Check assigned HeapNumbers in reverse order
12191  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12192                      "  ext_array[i] = (i * 0.5);"
12193                      "}"
12194                      "var sum = 0;"
12195                      "for (var i = 0; i < 16; i+=2) {"
12196                      "  sum += ext_array[i];"
12197                      "}"
12198                      "sum;");
12199  CHECK_EQ(28, result->Int32Value());
12200
12201  i::ScopedVector<char> test_buf(1024);
12202
12203  // Check legal boundary conditions.
12204  // The repeated loads and stores ensure the ICs are exercised.
12205  const char* boundary_program =
12206      "var res = 0;"
12207      "for (var i = 0; i < 16; i++) {"
12208      "  ext_array[i] = %lld;"
12209      "  if (i > 8) {"
12210      "    res = ext_array[i];"
12211      "  }"
12212      "}"
12213      "res;";
12214  i::OS::SNPrintF(test_buf,
12215                  boundary_program,
12216                  low);
12217  result = CompileRun(test_buf.start());
12218  CHECK_EQ(low, result->IntegerValue());
12219
12220  i::OS::SNPrintF(test_buf,
12221                  boundary_program,
12222                  high);
12223  result = CompileRun(test_buf.start());
12224  CHECK_EQ(high, result->IntegerValue());
12225
12226  // Check misprediction of type in IC.
12227  result = CompileRun("var tmp_array = ext_array;"
12228                      "var sum = 0;"
12229                      "for (var i = 0; i < 8; i++) {"
12230                      "  tmp_array[i] = i;"
12231                      "  sum += tmp_array[i];"
12232                      "  if (i == 4) {"
12233                      "    tmp_array = {};"
12234                      "  }"
12235                      "}"
12236                      "sum;");
12237  HEAP->CollectAllGarbage(false);  // Force GC to trigger verification.
12238  CHECK_EQ(28, result->Int32Value());
12239
12240  // Make sure out-of-range loads do not throw.
12241  i::OS::SNPrintF(test_buf,
12242                  "var caught_exception = false;"
12243                  "try {"
12244                  "  ext_array[%d];"
12245                  "} catch (e) {"
12246                  "  caught_exception = true;"
12247                  "}"
12248                  "caught_exception;",
12249                  kElementCount);
12250  result = CompileRun(test_buf.start());
12251  CHECK_EQ(false, result->BooleanValue());
12252
12253  // Make sure out-of-range stores do not throw.
12254  i::OS::SNPrintF(test_buf,
12255                  "var caught_exception = false;"
12256                  "try {"
12257                  "  ext_array[%d] = 1;"
12258                  "} catch (e) {"
12259                  "  caught_exception = true;"
12260                  "}"
12261                  "caught_exception;",
12262                  kElementCount);
12263  result = CompileRun(test_buf.start());
12264  CHECK_EQ(false, result->BooleanValue());
12265
12266  // Check other boundary conditions, values and operations.
12267  result = CompileRun("for (var i = 0; i < 8; i++) {"
12268                      "  ext_array[7] = undefined;"
12269                      "}"
12270                      "ext_array[7];");
12271  CHECK_EQ(0, result->Int32Value());
12272  CHECK_EQ(
12273      0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
12274
12275  result = CompileRun("for (var i = 0; i < 8; i++) {"
12276                      "  ext_array[6] = '2.3';"
12277                      "}"
12278                      "ext_array[6];");
12279  CHECK_EQ(2, result->Int32Value());
12280  CHECK_EQ(
12281      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
12282
12283  if (array_type != v8::kExternalFloatArray &&
12284      array_type != v8::kExternalDoubleArray) {
12285    // Though the specification doesn't state it, be explicit about
12286    // converting NaNs and +/-Infinity to zero.
12287    result = CompileRun("for (var i = 0; i < 8; i++) {"
12288                        "  ext_array[i] = 5;"
12289                        "}"
12290                        "for (var i = 0; i < 8; i++) {"
12291                        "  ext_array[i] = NaN;"
12292                        "}"
12293                        "ext_array[5];");
12294    CHECK_EQ(0, result->Int32Value());
12295    CHECK_EQ(0,
12296             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12297
12298    result = CompileRun("for (var i = 0; i < 8; i++) {"
12299                        "  ext_array[i] = 5;"
12300                        "}"
12301                        "for (var i = 0; i < 8; i++) {"
12302                        "  ext_array[i] = Infinity;"
12303                        "}"
12304                        "ext_array[5];");
12305    int expected_value =
12306        (array_type == v8::kExternalPixelArray) ? 255 : 0;
12307    CHECK_EQ(expected_value, result->Int32Value());
12308    CHECK_EQ(expected_value,
12309             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12310
12311    result = CompileRun("for (var i = 0; i < 8; i++) {"
12312                        "  ext_array[i] = 5;"
12313                        "}"
12314                        "for (var i = 0; i < 8; i++) {"
12315                        "  ext_array[i] = -Infinity;"
12316                        "}"
12317                        "ext_array[5];");
12318    CHECK_EQ(0, result->Int32Value());
12319    CHECK_EQ(0,
12320             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12321
12322    // Check truncation behavior of integral arrays.
12323    const char* unsigned_data =
12324        "var source_data = [0.6, 10.6];"
12325        "var expected_results = [0, 10];";
12326    const char* signed_data =
12327        "var source_data = [0.6, 10.6, -0.6, -10.6];"
12328        "var expected_results = [0, 10, 0, -10];";
12329    const char* pixel_data =
12330        "var source_data = [0.6, 10.6];"
12331        "var expected_results = [1, 11];";
12332    bool is_unsigned =
12333        (array_type == v8::kExternalUnsignedByteArray ||
12334         array_type == v8::kExternalUnsignedShortArray ||
12335         array_type == v8::kExternalUnsignedIntArray);
12336    bool is_pixel_data = array_type == v8::kExternalPixelArray;
12337
12338    i::OS::SNPrintF(test_buf,
12339                    "%s"
12340                    "var all_passed = true;"
12341                    "for (var i = 0; i < source_data.length; i++) {"
12342                    "  for (var j = 0; j < 8; j++) {"
12343                    "    ext_array[j] = source_data[i];"
12344                    "  }"
12345                    "  all_passed = all_passed &&"
12346                    "               (ext_array[5] == expected_results[i]);"
12347                    "}"
12348                    "all_passed;",
12349                    (is_unsigned ?
12350                         unsigned_data :
12351                         (is_pixel_data ? pixel_data : signed_data)));
12352    result = CompileRun(test_buf.start());
12353    CHECK_EQ(true, result->BooleanValue());
12354  }
12355
12356  for (int i = 0; i < kElementCount; i++) {
12357    array->set(i, static_cast<ElementType>(i));
12358  }
12359  // Test complex assignments
12360  result = CompileRun("function ee_op_test_complex_func(sum) {"
12361                      " for (var i = 0; i < 40; ++i) {"
12362                      "   sum += (ext_array[i] += 1);"
12363                      "   sum += (ext_array[i] -= 1);"
12364                      " } "
12365                      " return sum;"
12366                      "}"
12367                      "sum=0;"
12368                      "for (var i=0;i<10000;++i) {"
12369                      "  sum=ee_op_test_complex_func(sum);"
12370                      "}"
12371                      "sum;");
12372  CHECK_EQ(16000000, result->Int32Value());
12373
12374  // Test count operations
12375  result = CompileRun("function ee_op_test_count_func(sum) {"
12376                      " for (var i = 0; i < 40; ++i) {"
12377                      "   sum += (++ext_array[i]);"
12378                      "   sum += (--ext_array[i]);"
12379                      " } "
12380                      " return sum;"
12381                      "}"
12382                      "sum=0;"
12383                      "for (var i=0;i<10000;++i) {"
12384                      "  sum=ee_op_test_count_func(sum);"
12385                      "}"
12386                      "sum;");
12387  CHECK_EQ(16000000, result->Int32Value());
12388
12389  result = CompileRun("ext_array[3] = 33;"
12390                      "delete ext_array[3];"
12391                      "ext_array[3];");
12392  CHECK_EQ(33, result->Int32Value());
12393
12394  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12395                      "ext_array[2] = 12; ext_array[3] = 13;"
12396                      "ext_array.__defineGetter__('2',"
12397                      "function() { return 120; });"
12398                      "ext_array[2];");
12399  CHECK_EQ(12, result->Int32Value());
12400
12401  result = CompileRun("var js_array = new Array(40);"
12402                      "js_array[0] = 77;"
12403                      "js_array;");
12404  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12405
12406  result = CompileRun("ext_array[1] = 23;"
12407                      "ext_array.__proto__ = [];"
12408                      "js_array.__proto__ = ext_array;"
12409                      "js_array.concat(ext_array);");
12410  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12411  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12412
12413  result = CompileRun("ext_array[1] = 23;");
12414  CHECK_EQ(23, result->Int32Value());
12415
12416  // Test more complex manipulations which cause eax to contain values
12417  // that won't be completely overwritten by loads from the arrays.
12418  // This catches bugs in the instructions used for the KeyedLoadIC
12419  // for byte and word types.
12420  {
12421    const int kXSize = 300;
12422    const int kYSize = 300;
12423    const int kLargeElementCount = kXSize * kYSize * 4;
12424    ElementType* large_array_data =
12425        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12426    i::Handle<ExternalArrayClass> large_array =
12427        i::Handle<ExternalArrayClass>::cast(
12428            FACTORY->NewExternalArray(kLargeElementCount,
12429                                         array_type,
12430                                         array_data));
12431    v8::Handle<v8::Object> large_obj = v8::Object::New();
12432    // Set the elements to be the external array.
12433    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12434                                                       array_type,
12435                                                       kLargeElementCount);
12436    context->Global()->Set(v8_str("large_array"), large_obj);
12437    // Initialize contents of a few rows.
12438    for (int x = 0; x < 300; x++) {
12439      int row = 0;
12440      int offset = row * 300 * 4;
12441      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12442      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12443      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12444      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12445      row = 150;
12446      offset = row * 300 * 4;
12447      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12448      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12449      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12450      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12451      row = 298;
12452      offset = row * 300 * 4;
12453      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12454      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12455      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12456      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12457    }
12458    // The goal of the code below is to make "offset" large enough
12459    // that the computation of the index (which goes into eax) has
12460    // high bits set which will not be overwritten by a byte or short
12461    // load.
12462    result = CompileRun("var failed = false;"
12463                        "var offset = 0;"
12464                        "for (var i = 0; i < 300; i++) {"
12465                        "  if (large_array[4 * i] != 127 ||"
12466                        "      large_array[4 * i + 1] != 0 ||"
12467                        "      large_array[4 * i + 2] != 0 ||"
12468                        "      large_array[4 * i + 3] != 127) {"
12469                        "    failed = true;"
12470                        "  }"
12471                        "}"
12472                        "offset = 150 * 300 * 4;"
12473                        "for (var i = 0; i < 300; i++) {"
12474                        "  if (large_array[offset + 4 * i] != 127 ||"
12475                        "      large_array[offset + 4 * i + 1] != 0 ||"
12476                        "      large_array[offset + 4 * i + 2] != 0 ||"
12477                        "      large_array[offset + 4 * i + 3] != 127) {"
12478                        "    failed = true;"
12479                        "  }"
12480                        "}"
12481                        "offset = 298 * 300 * 4;"
12482                        "for (var i = 0; i < 300; i++) {"
12483                        "  if (large_array[offset + 4 * i] != 127 ||"
12484                        "      large_array[offset + 4 * i + 1] != 0 ||"
12485                        "      large_array[offset + 4 * i + 2] != 0 ||"
12486                        "      large_array[offset + 4 * i + 3] != 127) {"
12487                        "    failed = true;"
12488                        "  }"
12489                        "}"
12490                        "!failed;");
12491    CHECK_EQ(true, result->BooleanValue());
12492    free(large_array_data);
12493  }
12494
12495  // The "" property descriptor is overloaded to store information about
12496  // the external array. Ensure that setting and accessing the "" property
12497  // works (it should overwrite the information cached about the external
12498  // array in the DescriptorArray) in various situations.
12499  result = CompileRun("ext_array[''] = 23; ext_array['']");
12500  CHECK_EQ(23, result->Int32Value());
12501
12502  // Property "" set after the external array is associated with the object.
12503  {
12504    v8::Handle<v8::Object> obj2 = v8::Object::New();
12505    obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12506    obj2->Set(v8_str(""), v8::Int32::New(1503));
12507    // Set the elements to be the external array.
12508    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12509                                                  array_type,
12510                                                  kElementCount);
12511    context->Global()->Set(v8_str("ext_array"), obj2);
12512    result = CompileRun("ext_array['']");
12513    CHECK_EQ(1503, result->Int32Value());
12514  }
12515
12516  // Property "" set after the external array is associated with the object.
12517  {
12518    v8::Handle<v8::Object> obj2 = v8::Object::New();
12519    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12520    // Set the elements to be the external array.
12521    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12522                                                  array_type,
12523                                                  kElementCount);
12524    obj2->Set(v8_str(""), v8::Int32::New(1503));
12525    context->Global()->Set(v8_str("ext_array"), obj2);
12526    result = CompileRun("ext_array['']");
12527    CHECK_EQ(1503, result->Int32Value());
12528  }
12529
12530  // Should reuse the map from previous test.
12531  {
12532    v8::Handle<v8::Object> obj2 = v8::Object::New();
12533    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12534    // Set the elements to be the external array. Should re-use the map
12535    // from previous test.
12536    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12537                                                  array_type,
12538                                                  kElementCount);
12539    context->Global()->Set(v8_str("ext_array"), obj2);
12540    result = CompileRun("ext_array['']");
12541  }
12542
12543  // Property "" is a constant function that shouldn't not be interfered with
12544  // when an external array is set.
12545  {
12546    v8::Handle<v8::Object> obj2 = v8::Object::New();
12547    // Start
12548    obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12549
12550    // Add a constant function to an object.
12551    context->Global()->Set(v8_str("ext_array"), obj2);
12552    result = CompileRun("ext_array[''] = function() {return 1503;};"
12553                        "ext_array['']();");
12554
12555    // Add an external array transition to the same map that
12556    // has the constant transition.
12557    v8::Handle<v8::Object> obj3 = v8::Object::New();
12558    obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12559    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12560                                                  array_type,
12561                                                  kElementCount);
12562    context->Global()->Set(v8_str("ext_array"), obj3);
12563  }
12564
12565  // If a external array transition is in the map, it should get clobbered
12566  // by a constant function.
12567  {
12568    // Add an external array transition.
12569    v8::Handle<v8::Object> obj3 = v8::Object::New();
12570    obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12571    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12572                                                  array_type,
12573                                                  kElementCount);
12574
12575    // Add a constant function to the same map that just got an external array
12576    // transition.
12577    v8::Handle<v8::Object> obj2 = v8::Object::New();
12578    obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12579    context->Global()->Set(v8_str("ext_array"), obj2);
12580    result = CompileRun("ext_array[''] = function() {return 1503;};"
12581                        "ext_array['']();");
12582  }
12583
12584  free(array_data);
12585}
12586
12587
12588THREADED_TEST(ExternalByteArray) {
12589  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
12590      v8::kExternalByteArray,
12591      -128,
12592      127);
12593}
12594
12595
12596THREADED_TEST(ExternalUnsignedByteArray) {
12597  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
12598      v8::kExternalUnsignedByteArray,
12599      0,
12600      255);
12601}
12602
12603
12604THREADED_TEST(ExternalPixelArray) {
12605  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12606      v8::kExternalPixelArray,
12607      0,
12608      255);
12609}
12610
12611
12612THREADED_TEST(ExternalShortArray) {
12613  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
12614      v8::kExternalShortArray,
12615      -32768,
12616      32767);
12617}
12618
12619
12620THREADED_TEST(ExternalUnsignedShortArray) {
12621  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
12622      v8::kExternalUnsignedShortArray,
12623      0,
12624      65535);
12625}
12626
12627
12628THREADED_TEST(ExternalIntArray) {
12629  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
12630      v8::kExternalIntArray,
12631      INT_MIN,   // -2147483648
12632      INT_MAX);  //  2147483647
12633}
12634
12635
12636THREADED_TEST(ExternalUnsignedIntArray) {
12637  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
12638      v8::kExternalUnsignedIntArray,
12639      0,
12640      UINT_MAX);  // 4294967295
12641}
12642
12643
12644THREADED_TEST(ExternalFloatArray) {
12645  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
12646      v8::kExternalFloatArray,
12647      -500,
12648      500);
12649}
12650
12651
12652THREADED_TEST(ExternalDoubleArray) {
12653  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12654      v8::kExternalDoubleArray,
12655      -500,
12656      500);
12657}
12658
12659
12660THREADED_TEST(ExternalArrays) {
12661  TestExternalByteArray();
12662  TestExternalUnsignedByteArray();
12663  TestExternalShortArray();
12664  TestExternalUnsignedShortArray();
12665  TestExternalIntArray();
12666  TestExternalUnsignedIntArray();
12667  TestExternalFloatArray();
12668}
12669
12670
12671void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12672  v8::HandleScope scope;
12673  LocalContext context;
12674  for (int size = 0; size < 100; size += 10) {
12675    int element_size = ExternalArrayElementSize(array_type);
12676    void* external_data = malloc(size * element_size);
12677    v8::Handle<v8::Object> obj = v8::Object::New();
12678    obj->SetIndexedPropertiesToExternalArrayData(
12679        external_data, array_type, size);
12680    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12681    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12682    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12683    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12684    free(external_data);
12685  }
12686}
12687
12688
12689THREADED_TEST(ExternalArrayInfo) {
12690  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12691  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12692  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12693  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12694  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12695  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12696  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
12697  ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
12698  ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
12699}
12700
12701
12702THREADED_TEST(ScriptContextDependence) {
12703  v8::HandleScope scope;
12704  LocalContext c1;
12705  const char *source = "foo";
12706  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12707  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12708  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12709  CHECK_EQ(dep->Run()->Int32Value(), 100);
12710  CHECK_EQ(indep->Run()->Int32Value(), 100);
12711  LocalContext c2;
12712  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12713  CHECK_EQ(dep->Run()->Int32Value(), 100);
12714  CHECK_EQ(indep->Run()->Int32Value(), 101);
12715}
12716
12717
12718THREADED_TEST(StackTrace) {
12719  v8::HandleScope scope;
12720  LocalContext context;
12721  v8::TryCatch try_catch;
12722  const char *source = "function foo() { FAIL.FAIL; }; foo();";
12723  v8::Handle<v8::String> src = v8::String::New(source);
12724  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12725  v8::Script::New(src, origin)->Run();
12726  CHECK(try_catch.HasCaught());
12727  v8::String::Utf8Value stack(try_catch.StackTrace());
12728  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12729}
12730
12731
12732// Checks that a StackFrame has certain expected values.
12733void checkStackFrame(const char* expected_script_name,
12734    const char* expected_func_name, int expected_line_number,
12735    int expected_column, bool is_eval, bool is_constructor,
12736    v8::Handle<v8::StackFrame> frame) {
12737  v8::HandleScope scope;
12738  v8::String::Utf8Value func_name(frame->GetFunctionName());
12739  v8::String::Utf8Value script_name(frame->GetScriptName());
12740  if (*script_name == NULL) {
12741    // The situation where there is no associated script, like for evals.
12742    CHECK(expected_script_name == NULL);
12743  } else {
12744    CHECK(strstr(*script_name, expected_script_name) != NULL);
12745  }
12746  CHECK(strstr(*func_name, expected_func_name) != NULL);
12747  CHECK_EQ(expected_line_number, frame->GetLineNumber());
12748  CHECK_EQ(expected_column, frame->GetColumn());
12749  CHECK_EQ(is_eval, frame->IsEval());
12750  CHECK_EQ(is_constructor, frame->IsConstructor());
12751}
12752
12753
12754v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12755  v8::HandleScope scope;
12756  const char* origin = "capture-stack-trace-test";
12757  const int kOverviewTest = 1;
12758  const int kDetailedTest = 2;
12759
12760  ASSERT(args.Length() == 1);
12761
12762  int testGroup = args[0]->Int32Value();
12763  if (testGroup == kOverviewTest) {
12764    v8::Handle<v8::StackTrace> stackTrace =
12765        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12766    CHECK_EQ(4, stackTrace->GetFrameCount());
12767    checkStackFrame(origin, "bar", 2, 10, false, false,
12768                    stackTrace->GetFrame(0));
12769    checkStackFrame(origin, "foo", 6, 3, false, false,
12770                    stackTrace->GetFrame(1));
12771    // This is the source string inside the eval which has the call to foo.
12772    checkStackFrame(NULL, "", 1, 5, false, false,
12773                    stackTrace->GetFrame(2));
12774    // The last frame is an anonymous function which has the initial eval call.
12775    checkStackFrame(origin, "", 8, 7, false, false,
12776                    stackTrace->GetFrame(3));
12777
12778    CHECK(stackTrace->AsArray()->IsArray());
12779  } else if (testGroup == kDetailedTest) {
12780    v8::Handle<v8::StackTrace> stackTrace =
12781        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12782    CHECK_EQ(4, stackTrace->GetFrameCount());
12783    checkStackFrame(origin, "bat", 4, 22, false, false,
12784                    stackTrace->GetFrame(0));
12785    checkStackFrame(origin, "baz", 8, 3, false, true,
12786                    stackTrace->GetFrame(1));
12787#ifdef ENABLE_DEBUGGER_SUPPORT
12788    bool is_eval = true;
12789#else  // ENABLE_DEBUGGER_SUPPORT
12790    bool is_eval = false;
12791#endif  // ENABLE_DEBUGGER_SUPPORT
12792
12793    // This is the source string inside the eval which has the call to baz.
12794    checkStackFrame(NULL, "", 1, 5, is_eval, false,
12795                    stackTrace->GetFrame(2));
12796    // The last frame is an anonymous function which has the initial eval call.
12797    checkStackFrame(origin, "", 10, 1, false, false,
12798                    stackTrace->GetFrame(3));
12799
12800    CHECK(stackTrace->AsArray()->IsArray());
12801  }
12802  return v8::Undefined();
12803}
12804
12805
12806// Tests the C++ StackTrace API.
12807// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12808// THREADED_TEST(CaptureStackTrace) {
12809TEST(CaptureStackTrace) {
12810  v8::HandleScope scope;
12811  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12812  Local<ObjectTemplate> templ = ObjectTemplate::New();
12813  templ->Set(v8_str("AnalyzeStackInNativeCode"),
12814             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12815  LocalContext context(0, templ);
12816
12817  // Test getting OVERVIEW information. Should ignore information that is not
12818  // script name, function name, line number, and column offset.
12819  const char *overview_source =
12820    "function bar() {\n"
12821    "  var y; AnalyzeStackInNativeCode(1);\n"
12822    "}\n"
12823    "function foo() {\n"
12824    "\n"
12825    "  bar();\n"
12826    "}\n"
12827    "var x;eval('new foo();');";
12828  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12829  v8::Handle<Value> overview_result =
12830      v8::Script::New(overview_src, origin)->Run();
12831  ASSERT(!overview_result.IsEmpty());
12832  ASSERT(overview_result->IsObject());
12833
12834  // Test getting DETAILED information.
12835  const char *detailed_source =
12836    "function bat() {AnalyzeStackInNativeCode(2);\n"
12837    "}\n"
12838    "\n"
12839    "function baz() {\n"
12840    "  bat();\n"
12841    "}\n"
12842    "eval('new baz();');";
12843  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12844  // Make the script using a non-zero line and column offset.
12845  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12846  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12847  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12848  v8::Handle<v8::Script> detailed_script(
12849      v8::Script::New(detailed_src, &detailed_origin));
12850  v8::Handle<Value> detailed_result = detailed_script->Run();
12851  ASSERT(!detailed_result.IsEmpty());
12852  ASSERT(detailed_result->IsObject());
12853}
12854
12855
12856static void StackTraceForUncaughtExceptionListener(
12857    v8::Handle<v8::Message> message,
12858    v8::Handle<Value>) {
12859  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12860  CHECK_EQ(2, stack_trace->GetFrameCount());
12861  checkStackFrame("origin", "foo", 2, 3, false, false,
12862                  stack_trace->GetFrame(0));
12863  checkStackFrame("origin", "bar", 5, 3, false, false,
12864                  stack_trace->GetFrame(1));
12865}
12866
12867TEST(CaptureStackTraceForUncaughtException) {
12868  report_count = 0;
12869  v8::HandleScope scope;
12870  LocalContext env;
12871  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12872  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12873
12874  Script::Compile(v8_str("function foo() {\n"
12875                         "  throw 1;\n"
12876                         "};\n"
12877                         "function bar() {\n"
12878                         "  foo();\n"
12879                         "};"),
12880                  v8_str("origin"))->Run();
12881  v8::Local<v8::Object> global = env->Global();
12882  Local<Value> trouble = global->Get(v8_str("bar"));
12883  CHECK(trouble->IsFunction());
12884  Function::Cast(*trouble)->Call(global, 0, NULL);
12885  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12886  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12887}
12888
12889
12890TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12891  v8::HandleScope scope;
12892  LocalContext env;
12893  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12894                                                    1024,
12895                                                    v8::StackTrace::kDetailed);
12896
12897  CompileRun(
12898      "var setters = ['column', 'lineNumber', 'scriptName',\n"
12899      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12900      "    'isConstructor'];\n"
12901      "for (var i = 0; i < setters.length; i++) {\n"
12902      "  var prop = setters[i];\n"
12903      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12904      "}\n");
12905  CompileRun("throw 'exception';");
12906  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12907}
12908
12909
12910v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12911  v8::HandleScope scope;
12912  v8::Handle<v8::StackTrace> stackTrace =
12913      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12914  CHECK_EQ(5, stackTrace->GetFrameCount());
12915  v8::Handle<v8::String> url = v8_str("eval_url");
12916  for (int i = 0; i < 3; i++) {
12917    v8::Handle<v8::String> name =
12918        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12919    CHECK(!name.IsEmpty());
12920    CHECK_EQ(url, name);
12921  }
12922  return v8::Undefined();
12923}
12924
12925
12926TEST(SourceURLInStackTrace) {
12927  v8::HandleScope scope;
12928  Local<ObjectTemplate> templ = ObjectTemplate::New();
12929  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12930             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12931  LocalContext context(0, templ);
12932
12933  const char *source =
12934    "function outer() {\n"
12935    "function bar() {\n"
12936    "  AnalyzeStackOfEvalWithSourceURL();\n"
12937    "}\n"
12938    "function foo() {\n"
12939    "\n"
12940    "  bar();\n"
12941    "}\n"
12942    "foo();\n"
12943    "}\n"
12944    "eval('(' + outer +')()//@ sourceURL=eval_url');";
12945  CHECK(CompileRun(source)->IsUndefined());
12946}
12947
12948
12949// Test that idle notification can be handled and eventually returns true.
12950THREADED_TEST(IdleNotification) {
12951  bool rv = false;
12952  for (int i = 0; i < 100; i++) {
12953    rv = v8::V8::IdleNotification();
12954    if (rv)
12955      break;
12956  }
12957  CHECK(rv == true);
12958}
12959
12960
12961static uint32_t* stack_limit;
12962
12963static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
12964  stack_limit = reinterpret_cast<uint32_t*>(
12965      i::Isolate::Current()->stack_guard()->real_climit());
12966  return v8::Undefined();
12967}
12968
12969
12970// Uses the address of a local variable to determine the stack top now.
12971// Given a size, returns an address that is that far from the current
12972// top of stack.
12973static uint32_t* ComputeStackLimit(uint32_t size) {
12974  uint32_t* answer = &size - (size / sizeof(size));
12975  // If the size is very large and the stack is very near the bottom of
12976  // memory then the calculation above may wrap around and give an address
12977  // that is above the (downwards-growing) stack.  In that case we return
12978  // a very low address.
12979  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12980  return answer;
12981}
12982
12983
12984TEST(SetResourceConstraints) {
12985  static const int K = 1024;
12986  uint32_t* set_limit = ComputeStackLimit(128 * K);
12987
12988  // Set stack limit.
12989  v8::ResourceConstraints constraints;
12990  constraints.set_stack_limit(set_limit);
12991  CHECK(v8::SetResourceConstraints(&constraints));
12992
12993  // Execute a script.
12994  v8::HandleScope scope;
12995  LocalContext env;
12996  Local<v8::FunctionTemplate> fun_templ =
12997      v8::FunctionTemplate::New(GetStackLimitCallback);
12998  Local<Function> fun = fun_templ->GetFunction();
12999  env->Global()->Set(v8_str("get_stack_limit"), fun);
13000  CompileRun("get_stack_limit();");
13001
13002  CHECK(stack_limit == set_limit);
13003}
13004
13005
13006TEST(SetResourceConstraintsInThread) {
13007  uint32_t* set_limit;
13008  {
13009    v8::Locker locker;
13010    static const int K = 1024;
13011    set_limit = ComputeStackLimit(128 * K);
13012
13013    // Set stack limit.
13014    v8::ResourceConstraints constraints;
13015    constraints.set_stack_limit(set_limit);
13016    CHECK(v8::SetResourceConstraints(&constraints));
13017
13018    // Execute a script.
13019    v8::HandleScope scope;
13020    LocalContext env;
13021    Local<v8::FunctionTemplate> fun_templ =
13022        v8::FunctionTemplate::New(GetStackLimitCallback);
13023    Local<Function> fun = fun_templ->GetFunction();
13024    env->Global()->Set(v8_str("get_stack_limit"), fun);
13025    CompileRun("get_stack_limit();");
13026
13027    CHECK(stack_limit == set_limit);
13028  }
13029  {
13030    v8::Locker locker;
13031    CHECK(stack_limit == set_limit);
13032  }
13033}
13034
13035
13036THREADED_TEST(GetHeapStatistics) {
13037  v8::HandleScope scope;
13038  LocalContext c1;
13039  v8::HeapStatistics heap_statistics;
13040  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13041  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
13042  v8::V8::GetHeapStatistics(&heap_statistics);
13043  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13044  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13045}
13046
13047
13048static double DoubleFromBits(uint64_t value) {
13049  double target;
13050  memcpy(&target, &value, sizeof(target));
13051  return target;
13052}
13053
13054
13055static uint64_t DoubleToBits(double value) {
13056  uint64_t target;
13057  memcpy(&target, &value, sizeof(target));
13058  return target;
13059}
13060
13061
13062static double DoubleToDateTime(double input) {
13063  double date_limit = 864e13;
13064  if (IsNaN(input) || input < -date_limit || input > date_limit) {
13065    return i::OS::nan_value();
13066  }
13067  return (input < 0) ? -(floor(-input)) : floor(input);
13068}
13069
13070// We don't have a consistent way to write 64-bit constants syntactically, so we
13071// split them into two 32-bit constants and combine them programmatically.
13072static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13073  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13074}
13075
13076
13077THREADED_TEST(QuietSignalingNaNs) {
13078  v8::HandleScope scope;
13079  LocalContext context;
13080  v8::TryCatch try_catch;
13081
13082  // Special double values.
13083  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13084  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13085  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13086  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13087  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13088  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13089  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13090
13091  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13092  // on either side of the epoch.
13093  double date_limit = 864e13;
13094
13095  double test_values[] = {
13096      snan,
13097      qnan,
13098      infinity,
13099      max_normal,
13100      date_limit + 1,
13101      date_limit,
13102      min_normal,
13103      max_denormal,
13104      min_denormal,
13105      0,
13106      -0,
13107      -min_denormal,
13108      -max_denormal,
13109      -min_normal,
13110      -date_limit,
13111      -date_limit - 1,
13112      -max_normal,
13113      -infinity,
13114      -qnan,
13115      -snan
13116  };
13117  int num_test_values = 20;
13118
13119  for (int i = 0; i < num_test_values; i++) {
13120    double test_value = test_values[i];
13121
13122    // Check that Number::New preserves non-NaNs and quiets SNaNs.
13123    v8::Handle<v8::Value> number = v8::Number::New(test_value);
13124    double stored_number = number->NumberValue();
13125    if (!IsNaN(test_value)) {
13126      CHECK_EQ(test_value, stored_number);
13127    } else {
13128      uint64_t stored_bits = DoubleToBits(stored_number);
13129      // Check if quiet nan (bits 51..62 all set).
13130      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13131    }
13132
13133    // Check that Date::New preserves non-NaNs in the date range and
13134    // quiets SNaNs.
13135    v8::Handle<v8::Value> date = v8::Date::New(test_value);
13136    double expected_stored_date = DoubleToDateTime(test_value);
13137    double stored_date = date->NumberValue();
13138    if (!IsNaN(expected_stored_date)) {
13139      CHECK_EQ(expected_stored_date, stored_date);
13140    } else {
13141      uint64_t stored_bits = DoubleToBits(stored_date);
13142      // Check if quiet nan (bits 51..62 all set).
13143      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13144    }
13145  }
13146}
13147
13148
13149static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13150  v8::HandleScope scope;
13151  v8::TryCatch tc;
13152  v8::Handle<v8::String> str = args[0]->ToString();
13153  if (tc.HasCaught())
13154    return tc.ReThrow();
13155  return v8::Undefined();
13156}
13157
13158
13159// Test that an exception can be propagated down through a spaghetti
13160// stack using ReThrow.
13161THREADED_TEST(SpaghettiStackReThrow) {
13162  v8::HandleScope scope;
13163  LocalContext context;
13164  context->Global()->Set(
13165      v8::String::New("s"),
13166      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13167  v8::TryCatch try_catch;
13168  CompileRun(
13169      "var i = 0;"
13170      "var o = {"
13171      "  toString: function () {"
13172      "    if (i == 10) {"
13173      "      throw 'Hey!';"
13174      "    } else {"
13175      "      i++;"
13176      "      return s(o);"
13177      "    }"
13178      "  }"
13179      "};"
13180      "s(o);");
13181  CHECK(try_catch.HasCaught());
13182  v8::String::Utf8Value value(try_catch.Exception());
13183  CHECK_EQ(0, strcmp(*value, "Hey!"));
13184}
13185
13186
13187TEST(Regress528) {
13188  v8::V8::Initialize();
13189
13190  v8::HandleScope scope;
13191  v8::Persistent<Context> context;
13192  v8::Persistent<Context> other_context;
13193  int gc_count;
13194
13195  // Create a context used to keep the code from aging in the compilation
13196  // cache.
13197  other_context = Context::New();
13198
13199  // Context-dependent context data creates reference from the compilation
13200  // cache to the global object.
13201  const char* source_simple = "1";
13202  context = Context::New();
13203  {
13204    v8::HandleScope scope;
13205
13206    context->Enter();
13207    Local<v8::String> obj = v8::String::New("");
13208    context->SetData(obj);
13209    CompileRun(source_simple);
13210    context->Exit();
13211  }
13212  context.Dispose();
13213  for (gc_count = 1; gc_count < 10; gc_count++) {
13214    other_context->Enter();
13215    CompileRun(source_simple);
13216    other_context->Exit();
13217    HEAP->CollectAllGarbage(false);
13218    if (GetGlobalObjectsCount() == 1) break;
13219  }
13220  CHECK_GE(2, gc_count);
13221  CHECK_EQ(1, GetGlobalObjectsCount());
13222
13223  // Eval in a function creates reference from the compilation cache to the
13224  // global object.
13225  const char* source_eval = "function f(){eval('1')}; f()";
13226  context = Context::New();
13227  {
13228    v8::HandleScope scope;
13229
13230    context->Enter();
13231    CompileRun(source_eval);
13232    context->Exit();
13233  }
13234  context.Dispose();
13235  for (gc_count = 1; gc_count < 10; gc_count++) {
13236    other_context->Enter();
13237    CompileRun(source_eval);
13238    other_context->Exit();
13239    HEAP->CollectAllGarbage(false);
13240    if (GetGlobalObjectsCount() == 1) break;
13241  }
13242  CHECK_GE(2, gc_count);
13243  CHECK_EQ(1, GetGlobalObjectsCount());
13244
13245  // Looking up the line number for an exception creates reference from the
13246  // compilation cache to the global object.
13247  const char* source_exception = "function f(){throw 1;} f()";
13248  context = Context::New();
13249  {
13250    v8::HandleScope scope;
13251
13252    context->Enter();
13253    v8::TryCatch try_catch;
13254    CompileRun(source_exception);
13255    CHECK(try_catch.HasCaught());
13256    v8::Handle<v8::Message> message = try_catch.Message();
13257    CHECK(!message.IsEmpty());
13258    CHECK_EQ(1, message->GetLineNumber());
13259    context->Exit();
13260  }
13261  context.Dispose();
13262  for (gc_count = 1; gc_count < 10; gc_count++) {
13263    other_context->Enter();
13264    CompileRun(source_exception);
13265    other_context->Exit();
13266    HEAP->CollectAllGarbage(false);
13267    if (GetGlobalObjectsCount() == 1) break;
13268  }
13269  CHECK_GE(2, gc_count);
13270  CHECK_EQ(1, GetGlobalObjectsCount());
13271
13272  other_context.Dispose();
13273}
13274
13275
13276THREADED_TEST(ScriptOrigin) {
13277  v8::HandleScope scope;
13278  LocalContext env;
13279  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13280  v8::Handle<v8::String> script = v8::String::New(
13281      "function f() {}\n\nfunction g() {}");
13282  v8::Script::Compile(script, &origin)->Run();
13283  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13284      env->Global()->Get(v8::String::New("f")));
13285  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13286      env->Global()->Get(v8::String::New("g")));
13287
13288  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13289  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13290  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13291
13292  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13293  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13294  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13295}
13296
13297
13298THREADED_TEST(ScriptLineNumber) {
13299  v8::HandleScope scope;
13300  LocalContext env;
13301  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13302  v8::Handle<v8::String> script = v8::String::New(
13303      "function f() {}\n\nfunction g() {}");
13304  v8::Script::Compile(script, &origin)->Run();
13305  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13306      env->Global()->Get(v8::String::New("f")));
13307  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13308      env->Global()->Get(v8::String::New("g")));
13309  CHECK_EQ(0, f->GetScriptLineNumber());
13310  CHECK_EQ(2, g->GetScriptLineNumber());
13311}
13312
13313
13314static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13315                                              const AccessorInfo& info) {
13316  return v8_num(42);
13317}
13318
13319
13320static void SetterWhichSetsYOnThisTo23(Local<String> name,
13321                                       Local<Value> value,
13322                                       const AccessorInfo& info) {
13323  info.This()->Set(v8_str("y"), v8_num(23));
13324}
13325
13326
13327TEST(SetterOnConstructorPrototype) {
13328  v8::HandleScope scope;
13329  Local<ObjectTemplate> templ = ObjectTemplate::New();
13330  templ->SetAccessor(v8_str("x"),
13331                     GetterWhichReturns42,
13332                     SetterWhichSetsYOnThisTo23);
13333  LocalContext context;
13334  context->Global()->Set(v8_str("P"), templ->NewInstance());
13335  CompileRun("function C1() {"
13336             "  this.x = 23;"
13337             "};"
13338             "C1.prototype = P;"
13339             "function C2() {"
13340             "  this.x = 23"
13341             "};"
13342             "C2.prototype = { };"
13343             "C2.prototype.__proto__ = P;");
13344
13345  v8::Local<v8::Script> script;
13346  script = v8::Script::Compile(v8_str("new C1();"));
13347  for (int i = 0; i < 10; i++) {
13348    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13349    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13350    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13351  }
13352
13353  script = v8::Script::Compile(v8_str("new C2();"));
13354  for (int i = 0; i < 10; i++) {
13355    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13356    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13357    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13358  }
13359}
13360
13361
13362static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13363    Local<String> name, const AccessorInfo& info) {
13364  return v8_num(42);
13365}
13366
13367
13368static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13369    Local<String> name, Local<Value> value, const AccessorInfo& info) {
13370  if (name->Equals(v8_str("x"))) {
13371    info.This()->Set(v8_str("y"), v8_num(23));
13372  }
13373  return v8::Handle<Value>();
13374}
13375
13376
13377THREADED_TEST(InterceptorOnConstructorPrototype) {
13378  v8::HandleScope scope;
13379  Local<ObjectTemplate> templ = ObjectTemplate::New();
13380  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13381                                 NamedPropertySetterWhichSetsYOnThisTo23);
13382  LocalContext context;
13383  context->Global()->Set(v8_str("P"), templ->NewInstance());
13384  CompileRun("function C1() {"
13385             "  this.x = 23;"
13386             "};"
13387             "C1.prototype = P;"
13388             "function C2() {"
13389             "  this.x = 23"
13390             "};"
13391             "C2.prototype = { };"
13392             "C2.prototype.__proto__ = P;");
13393
13394  v8::Local<v8::Script> script;
13395  script = v8::Script::Compile(v8_str("new C1();"));
13396  for (int i = 0; i < 10; i++) {
13397    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13398    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13399    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13400  }
13401
13402  script = v8::Script::Compile(v8_str("new C2();"));
13403  for (int i = 0; i < 10; i++) {
13404    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13405    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13406    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13407  }
13408}
13409
13410
13411TEST(Bug618) {
13412  const char* source = "function C1() {"
13413                       "  this.x = 23;"
13414                       "};"
13415                       "C1.prototype = P;";
13416
13417  v8::HandleScope scope;
13418  LocalContext context;
13419  v8::Local<v8::Script> script;
13420
13421  // Use a simple object as prototype.
13422  v8::Local<v8::Object> prototype = v8::Object::New();
13423  prototype->Set(v8_str("y"), v8_num(42));
13424  context->Global()->Set(v8_str("P"), prototype);
13425
13426  // This compile will add the code to the compilation cache.
13427  CompileRun(source);
13428
13429  script = v8::Script::Compile(v8_str("new C1();"));
13430  // Allow enough iterations for the inobject slack tracking logic
13431  // to finalize instance size and install the fast construct stub.
13432  for (int i = 0; i < 256; i++) {
13433    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13434    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13435    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13436  }
13437
13438  // Use an API object with accessors as prototype.
13439  Local<ObjectTemplate> templ = ObjectTemplate::New();
13440  templ->SetAccessor(v8_str("x"),
13441                     GetterWhichReturns42,
13442                     SetterWhichSetsYOnThisTo23);
13443  context->Global()->Set(v8_str("P"), templ->NewInstance());
13444
13445  // This compile will get the code from the compilation cache.
13446  CompileRun(source);
13447
13448  script = v8::Script::Compile(v8_str("new C1();"));
13449  for (int i = 0; i < 10; i++) {
13450    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13451    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13452    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13453  }
13454}
13455
13456int prologue_call_count = 0;
13457int epilogue_call_count = 0;
13458int prologue_call_count_second = 0;
13459int epilogue_call_count_second = 0;
13460
13461void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13462  ++prologue_call_count;
13463}
13464
13465void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13466  ++epilogue_call_count;
13467}
13468
13469void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13470  ++prologue_call_count_second;
13471}
13472
13473void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13474  ++epilogue_call_count_second;
13475}
13476
13477TEST(GCCallbacks) {
13478  LocalContext context;
13479
13480  v8::V8::AddGCPrologueCallback(PrologueCallback);
13481  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13482  CHECK_EQ(0, prologue_call_count);
13483  CHECK_EQ(0, epilogue_call_count);
13484  HEAP->CollectAllGarbage(false);
13485  CHECK_EQ(1, prologue_call_count);
13486  CHECK_EQ(1, epilogue_call_count);
13487  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13488  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
13489  HEAP->CollectAllGarbage(false);
13490  CHECK_EQ(2, prologue_call_count);
13491  CHECK_EQ(2, epilogue_call_count);
13492  CHECK_EQ(1, prologue_call_count_second);
13493  CHECK_EQ(1, epilogue_call_count_second);
13494  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13495  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
13496  HEAP->CollectAllGarbage(false);
13497  CHECK_EQ(2, prologue_call_count);
13498  CHECK_EQ(2, epilogue_call_count);
13499  CHECK_EQ(2, prologue_call_count_second);
13500  CHECK_EQ(2, epilogue_call_count_second);
13501  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13502  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
13503  HEAP->CollectAllGarbage(false);
13504  CHECK_EQ(2, prologue_call_count);
13505  CHECK_EQ(2, epilogue_call_count);
13506  CHECK_EQ(2, prologue_call_count_second);
13507  CHECK_EQ(2, epilogue_call_count_second);
13508}
13509
13510
13511THREADED_TEST(AddToJSFunctionResultCache) {
13512  i::FLAG_allow_natives_syntax = true;
13513  v8::HandleScope scope;
13514
13515  LocalContext context;
13516
13517  const char* code =
13518      "(function() {"
13519      "  var key0 = 'a';"
13520      "  var key1 = 'b';"
13521      "  var r0 = %_GetFromCache(0, key0);"
13522      "  var r1 = %_GetFromCache(0, key1);"
13523      "  var r0_ = %_GetFromCache(0, key0);"
13524      "  if (r0 !== r0_)"
13525      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13526      "  var r1_ = %_GetFromCache(0, key1);"
13527      "  if (r1 !== r1_)"
13528      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13529      "  return 'PASSED';"
13530      "})()";
13531  HEAP->ClearJSFunctionResultCaches();
13532  ExpectString(code, "PASSED");
13533}
13534
13535
13536static const int k0CacheSize = 16;
13537
13538THREADED_TEST(FillJSFunctionResultCache) {
13539  i::FLAG_allow_natives_syntax = true;
13540  v8::HandleScope scope;
13541
13542  LocalContext context;
13543
13544  const char* code =
13545      "(function() {"
13546      "  var k = 'a';"
13547      "  var r = %_GetFromCache(0, k);"
13548      "  for (var i = 0; i < 16; i++) {"
13549      "    %_GetFromCache(0, 'a' + i);"
13550      "  };"
13551      "  if (r === %_GetFromCache(0, k))"
13552      "    return 'FAILED: k0CacheSize is too small';"
13553      "  return 'PASSED';"
13554      "})()";
13555  HEAP->ClearJSFunctionResultCaches();
13556  ExpectString(code, "PASSED");
13557}
13558
13559
13560THREADED_TEST(RoundRobinGetFromCache) {
13561  i::FLAG_allow_natives_syntax = true;
13562  v8::HandleScope scope;
13563
13564  LocalContext context;
13565
13566  const char* code =
13567      "(function() {"
13568      "  var keys = [];"
13569      "  for (var i = 0; i < 16; i++) keys.push(i);"
13570      "  var values = [];"
13571      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13572      "  for (var i = 0; i < 16; i++) {"
13573      "    var v = %_GetFromCache(0, keys[i]);"
13574      "    if (v !== values[i])"
13575      "      return 'Wrong value for ' + "
13576      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
13577      "  };"
13578      "  return 'PASSED';"
13579      "})()";
13580  HEAP->ClearJSFunctionResultCaches();
13581  ExpectString(code, "PASSED");
13582}
13583
13584
13585THREADED_TEST(ReverseGetFromCache) {
13586  i::FLAG_allow_natives_syntax = true;
13587  v8::HandleScope scope;
13588
13589  LocalContext context;
13590
13591  const char* code =
13592      "(function() {"
13593      "  var keys = [];"
13594      "  for (var i = 0; i < 16; i++) keys.push(i);"
13595      "  var values = [];"
13596      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13597      "  for (var i = 15; i >= 16; i--) {"
13598      "    var v = %_GetFromCache(0, keys[i]);"
13599      "    if (v !== values[i])"
13600      "      return 'Wrong value for ' + "
13601      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
13602      "  };"
13603      "  return 'PASSED';"
13604      "})()";
13605  HEAP->ClearJSFunctionResultCaches();
13606  ExpectString(code, "PASSED");
13607}
13608
13609
13610THREADED_TEST(TestEviction) {
13611  i::FLAG_allow_natives_syntax = true;
13612  v8::HandleScope scope;
13613
13614  LocalContext context;
13615
13616  const char* code =
13617      "(function() {"
13618      "  for (var i = 0; i < 2*16; i++) {"
13619      "    %_GetFromCache(0, 'a' + i);"
13620      "  };"
13621      "  return 'PASSED';"
13622      "})()";
13623  HEAP->ClearJSFunctionResultCaches();
13624  ExpectString(code, "PASSED");
13625}
13626
13627
13628THREADED_TEST(TwoByteStringInAsciiCons) {
13629  // See Chromium issue 47824.
13630  v8::HandleScope scope;
13631
13632  LocalContext context;
13633  const char* init_code =
13634      "var str1 = 'abelspendabel';"
13635      "var str2 = str1 + str1 + str1;"
13636      "str2;";
13637  Local<Value> result = CompileRun(init_code);
13638
13639  CHECK(result->IsString());
13640  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13641  int length = string->length();
13642  CHECK(string->IsAsciiRepresentation());
13643
13644  FlattenString(string);
13645  i::Handle<i::String> flat_string = FlattenGetString(string);
13646
13647  CHECK(string->IsAsciiRepresentation());
13648  CHECK(flat_string->IsAsciiRepresentation());
13649
13650  // Create external resource.
13651  uint16_t* uc16_buffer = new uint16_t[length + 1];
13652
13653  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13654  uc16_buffer[length] = 0;
13655
13656  TestResource resource(uc16_buffer);
13657
13658  flat_string->MakeExternal(&resource);
13659
13660  CHECK(flat_string->IsTwoByteRepresentation());
13661
13662  // At this point, we should have a Cons string which is flat and ASCII,
13663  // with a first half that is a two-byte string (although it only contains
13664  // ASCII characters). This is a valid sequence of steps, and it can happen
13665  // in real pages.
13666
13667  CHECK(string->IsAsciiRepresentation());
13668  i::ConsString* cons = i::ConsString::cast(*string);
13669  CHECK_EQ(0, cons->second()->length());
13670  CHECK(cons->first()->IsTwoByteRepresentation());
13671
13672  // Check that some string operations work.
13673
13674  // Atom RegExp.
13675  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13676  CHECK_EQ(6, reresult->Int32Value());
13677
13678  // Nonatom RegExp.
13679  reresult = CompileRun("str2.match(/abe./g).length;");
13680  CHECK_EQ(6, reresult->Int32Value());
13681
13682  reresult = CompileRun("str2.search(/bel/g);");
13683  CHECK_EQ(1, reresult->Int32Value());
13684
13685  reresult = CompileRun("str2.search(/be./g);");
13686  CHECK_EQ(1, reresult->Int32Value());
13687
13688  ExpectTrue("/bel/g.test(str2);");
13689
13690  ExpectTrue("/be./g.test(str2);");
13691
13692  reresult = CompileRun("/bel/g.exec(str2);");
13693  CHECK(!reresult->IsNull());
13694
13695  reresult = CompileRun("/be./g.exec(str2);");
13696  CHECK(!reresult->IsNull());
13697
13698  ExpectString("str2.substring(2, 10);", "elspenda");
13699
13700  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13701
13702  ExpectString("str2.charAt(2);", "e");
13703
13704  reresult = CompileRun("str2.charCodeAt(2);");
13705  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13706}
13707
13708
13709// Failed access check callback that performs a GC on each invocation.
13710void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13711                                 v8::AccessType type,
13712                                 Local<v8::Value> data) {
13713  HEAP->CollectAllGarbage(true);
13714}
13715
13716
13717TEST(GCInFailedAccessCheckCallback) {
13718  // Install a failed access check callback that performs a GC on each
13719  // invocation. Then force the callback to be called from va
13720
13721  v8::V8::Initialize();
13722  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13723
13724  v8::HandleScope scope;
13725
13726  // Create an ObjectTemplate for global objects and install access
13727  // check callbacks that will block access.
13728  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13729  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13730                                           IndexedGetAccessBlocker,
13731                                           v8::Handle<v8::Value>(),
13732                                           false);
13733
13734  // Create a context and set an x property on it's global object.
13735  LocalContext context0(NULL, global_template);
13736  context0->Global()->Set(v8_str("x"), v8_num(42));
13737  v8::Handle<v8::Object> global0 = context0->Global();
13738
13739  // Create a context with a different security token so that the
13740  // failed access check callback will be called on each access.
13741  LocalContext context1(NULL, global_template);
13742  context1->Global()->Set(v8_str("other"), global0);
13743
13744  // Get property with failed access check.
13745  ExpectUndefined("other.x");
13746
13747  // Get element with failed access check.
13748  ExpectUndefined("other[0]");
13749
13750  // Set property with failed access check.
13751  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13752  CHECK(result->IsObject());
13753
13754  // Set element with failed access check.
13755  result = CompileRun("other[0] = new Object()");
13756  CHECK(result->IsObject());
13757
13758  // Get property attribute with failed access check.
13759  ExpectFalse("\'x\' in other");
13760
13761  // Get property attribute for element with failed access check.
13762  ExpectFalse("0 in other");
13763
13764  // Delete property.
13765  ExpectFalse("delete other.x");
13766
13767  // Delete element.
13768  CHECK_EQ(false, global0->Delete(0));
13769
13770  // DefineAccessor.
13771  CHECK_EQ(false,
13772           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13773
13774  // Define JavaScript accessor.
13775  ExpectUndefined("Object.prototype.__defineGetter__.call("
13776                  "    other, \'x\', function() { return 42; })");
13777
13778  // LookupAccessor.
13779  ExpectUndefined("Object.prototype.__lookupGetter__.call("
13780                  "    other, \'x\')");
13781
13782  // HasLocalElement.
13783  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13784
13785  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13786  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13787  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13788
13789  // Reset the failed access check callback so it does not influence
13790  // the other tests.
13791  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13792}
13793
13794TEST(DefaultIsolateGetCurrent) {
13795  CHECK(v8::Isolate::GetCurrent() != NULL);
13796  v8::Isolate* isolate = v8::Isolate::GetCurrent();
13797  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13798  printf("*** %s\n", "DefaultIsolateGetCurrent success");
13799}
13800
13801TEST(IsolateNewDispose) {
13802  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13803  v8::Isolate* isolate = v8::Isolate::New();
13804  CHECK(isolate != NULL);
13805  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13806  CHECK(current_isolate != isolate);
13807  CHECK(current_isolate == v8::Isolate::GetCurrent());
13808
13809  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13810  last_location = last_message = NULL;
13811  isolate->Dispose();
13812  CHECK_EQ(last_location, NULL);
13813  CHECK_EQ(last_message, NULL);
13814}
13815
13816TEST(IsolateEnterExitDefault) {
13817  v8::HandleScope scope;
13818  LocalContext context;
13819  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13820  CHECK(current_isolate != NULL);  // Default isolate.
13821  ExpectString("'hello'", "hello");
13822  current_isolate->Enter();
13823  ExpectString("'still working'", "still working");
13824  current_isolate->Exit();
13825  ExpectString("'still working 2'", "still working 2");
13826  current_isolate->Exit();
13827  // Default isolate is always, well, 'default current'.
13828  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13829  // Still working since default isolate is auto-entering any thread
13830  // that has no isolate and attempts to execute V8 APIs.
13831  ExpectString("'still working 3'", "still working 3");
13832}
13833
13834TEST(DisposeDefaultIsolate) {
13835  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13836
13837  // Run some V8 code to trigger default isolate to become 'current'.
13838  v8::HandleScope scope;
13839  LocalContext context;
13840  ExpectString("'run some V8'", "run some V8");
13841
13842  v8::Isolate* isolate = v8::Isolate::GetCurrent();
13843  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13844  last_location = last_message = NULL;
13845  isolate->Dispose();
13846  // It is not possible to dispose default isolate via Isolate API.
13847  CHECK_NE(last_location, NULL);
13848  CHECK_NE(last_message, NULL);
13849}
13850
13851TEST(RunDefaultAndAnotherIsolate) {
13852  v8::HandleScope scope;
13853  LocalContext context;
13854
13855  // Enter new isolate.
13856  v8::Isolate* isolate = v8::Isolate::New();
13857  CHECK(isolate);
13858  isolate->Enter();
13859  { // Need this block because subsequent Exit() will deallocate Heap,
13860    // so we need all scope objects to be deconstructed when it happens.
13861    v8::HandleScope scope_new;
13862    LocalContext context_new;
13863
13864    // Run something in new isolate.
13865    CompileRun("var foo = 153;");
13866    ExpectTrue("function f() { return foo == 153; }; f()");
13867  }
13868  isolate->Exit();
13869
13870  // This runs automatically in default isolate.
13871  // Variables in another isolate should be not available.
13872  ExpectTrue("function f() {"
13873             "  try {"
13874             "    foo;"
13875             "    return false;"
13876             "  } catch(e) {"
13877             "    return true;"
13878             "  }"
13879             "};"
13880             "var bar = 371;"
13881             "f()");
13882
13883  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13884  last_location = last_message = NULL;
13885  isolate->Dispose();
13886  CHECK_EQ(last_location, NULL);
13887  CHECK_EQ(last_message, NULL);
13888
13889  // Check that default isolate still runs.
13890  ExpectTrue("function f() { return bar == 371; }; f()");
13891}
13892
13893TEST(DisposeIsolateWhenInUse) {
13894  v8::Isolate* isolate = v8::Isolate::New();
13895  CHECK(isolate);
13896  isolate->Enter();
13897  v8::HandleScope scope;
13898  LocalContext context;
13899  // Run something in this isolate.
13900  ExpectTrue("true");
13901  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13902  last_location = last_message = NULL;
13903  // Still entered, should fail.
13904  isolate->Dispose();
13905  CHECK_NE(last_location, NULL);
13906  CHECK_NE(last_message, NULL);
13907}
13908
13909TEST(RunTwoIsolatesOnSingleThread) {
13910  // Run isolate 1.
13911  v8::Isolate* isolate1 = v8::Isolate::New();
13912  isolate1->Enter();
13913  v8::Persistent<v8::Context> context1 = v8::Context::New();
13914
13915  {
13916    v8::Context::Scope cscope(context1);
13917    v8::HandleScope scope;
13918    // Run something in new isolate.
13919    CompileRun("var foo = 'isolate 1';");
13920    ExpectString("function f() { return foo; }; f()", "isolate 1");
13921  }
13922
13923  // Run isolate 2.
13924  v8::Isolate* isolate2 = v8::Isolate::New();
13925  v8::Persistent<v8::Context> context2;
13926
13927  {
13928    v8::Isolate::Scope iscope(isolate2);
13929    context2 = v8::Context::New();
13930    v8::Context::Scope cscope(context2);
13931    v8::HandleScope scope;
13932
13933    // Run something in new isolate.
13934    CompileRun("var foo = 'isolate 2';");
13935    ExpectString("function f() { return foo; }; f()", "isolate 2");
13936  }
13937
13938  {
13939    v8::Context::Scope cscope(context1);
13940    v8::HandleScope scope;
13941    // Now again in isolate 1
13942    ExpectString("function f() { return foo; }; f()", "isolate 1");
13943  }
13944
13945  isolate1->Exit();
13946
13947  // Run some stuff in default isolate.
13948  v8::Persistent<v8::Context> context_default = v8::Context::New();
13949
13950  {
13951    v8::Context::Scope cscope(context_default);
13952    v8::HandleScope scope;
13953    // Variables in other isolates should be not available, verify there
13954    // is an exception.
13955    ExpectTrue("function f() {"
13956               "  try {"
13957               "    foo;"
13958               "    return false;"
13959               "  } catch(e) {"
13960               "    return true;"
13961               "  }"
13962               "};"
13963               "var isDefaultIsolate = true;"
13964               "f()");
13965  }
13966
13967  isolate1->Enter();
13968
13969  {
13970    v8::Isolate::Scope iscope(isolate2);
13971    v8::Context::Scope cscope(context2);
13972    v8::HandleScope scope;
13973    ExpectString("function f() { return foo; }; f()", "isolate 2");
13974  }
13975
13976  {
13977    v8::Context::Scope cscope(context1);
13978    v8::HandleScope scope;
13979    ExpectString("function f() { return foo; }; f()", "isolate 1");
13980  }
13981
13982  {
13983    v8::Isolate::Scope iscope(isolate2);
13984    context2.Dispose();
13985  }
13986
13987  context1.Dispose();
13988  isolate1->Exit();
13989
13990  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13991  last_location = last_message = NULL;
13992
13993  isolate1->Dispose();
13994  CHECK_EQ(last_location, NULL);
13995  CHECK_EQ(last_message, NULL);
13996
13997  isolate2->Dispose();
13998  CHECK_EQ(last_location, NULL);
13999  CHECK_EQ(last_message, NULL);
14000
14001  // Check that default isolate still runs.
14002  {
14003    v8::Context::Scope cscope(context_default);
14004    v8::HandleScope scope;
14005    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14006  }
14007}
14008
14009static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14010  v8::Isolate::Scope isolate_scope(isolate);
14011  v8::HandleScope scope;
14012  LocalContext context;
14013  i::ScopedVector<char> code(1024);
14014  i::OS::SNPrintF(code, "function fib(n) {"
14015                        "  if (n <= 2) return 1;"
14016                        "  return fib(n-1) + fib(n-2);"
14017                        "}"
14018                        "fib(%d)", limit);
14019  Local<Value> value = CompileRun(code.start());
14020  CHECK(value->IsNumber());
14021  return static_cast<int>(value->NumberValue());
14022}
14023
14024class IsolateThread : public v8::internal::Thread {
14025 public:
14026  IsolateThread(v8::Isolate* isolate, int fib_limit)
14027      : Thread("IsolateThread"),
14028        isolate_(isolate),
14029        fib_limit_(fib_limit),
14030        result_(0) { }
14031
14032  void Run() {
14033    result_ = CalcFibonacci(isolate_, fib_limit_);
14034  }
14035
14036  int result() { return result_; }
14037
14038 private:
14039  v8::Isolate* isolate_;
14040  int fib_limit_;
14041  int result_;
14042};
14043
14044TEST(MultipleIsolatesOnIndividualThreads) {
14045  v8::Isolate* isolate1 = v8::Isolate::New();
14046  v8::Isolate* isolate2 = v8::Isolate::New();
14047
14048  IsolateThread thread1(isolate1, 21);
14049  IsolateThread thread2(isolate2, 12);
14050
14051  // Compute some fibonacci numbers on 3 threads in 3 isolates.
14052  thread1.Start();
14053  thread2.Start();
14054
14055  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14056  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14057
14058  thread1.Join();
14059  thread2.Join();
14060
14061  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14062  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14063  CHECK_EQ(result1, 10946);
14064  CHECK_EQ(result2, 144);
14065  CHECK_EQ(result1, thread1.result());
14066  CHECK_EQ(result2, thread2.result());
14067
14068  isolate1->Dispose();
14069  isolate2->Dispose();
14070}
14071
14072TEST(IsolateDifferentContexts) {
14073  v8::Isolate* isolate = v8::Isolate::New();
14074  Persistent<v8::Context> context;
14075  {
14076    v8::Isolate::Scope isolate_scope(isolate);
14077    v8::HandleScope handle_scope;
14078    context = v8::Context::New();
14079    v8::Context::Scope context_scope(context);
14080    Local<Value> v = CompileRun("2");
14081    CHECK(v->IsNumber());
14082    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14083  }
14084  {
14085    v8::Isolate::Scope isolate_scope(isolate);
14086    v8::HandleScope handle_scope;
14087    context = v8::Context::New();
14088    v8::Context::Scope context_scope(context);
14089    Local<Value> v = CompileRun("22");
14090    CHECK(v->IsNumber());
14091    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14092  }
14093}
14094
14095class InitDefaultIsolateThread : public v8::internal::Thread {
14096 public:
14097  enum TestCase {
14098    IgnoreOOM,
14099    SetResourceConstraints,
14100    SetFatalHandler,
14101    SetCounterFunction,
14102    SetCreateHistogramFunction,
14103    SetAddHistogramSampleFunction
14104  };
14105
14106  explicit InitDefaultIsolateThread(TestCase testCase)
14107      : Thread("InitDefaultIsolateThread"),
14108        testCase_(testCase),
14109        result_(false) { }
14110
14111  void Run() {
14112    switch (testCase_) {
14113    case IgnoreOOM:
14114      v8::V8::IgnoreOutOfMemoryException();
14115      break;
14116
14117    case SetResourceConstraints: {
14118      static const int K = 1024;
14119      v8::ResourceConstraints constraints;
14120      constraints.set_max_young_space_size(256 * K);
14121      constraints.set_max_old_space_size(4 * K * K);
14122      v8::SetResourceConstraints(&constraints);
14123      break;
14124    }
14125
14126    case SetFatalHandler:
14127      v8::V8::SetFatalErrorHandler(NULL);
14128      break;
14129
14130    case SetCounterFunction:
14131      v8::V8::SetCounterFunction(NULL);
14132      break;
14133
14134    case SetCreateHistogramFunction:
14135      v8::V8::SetCreateHistogramFunction(NULL);
14136      break;
14137
14138    case SetAddHistogramSampleFunction:
14139      v8::V8::SetAddHistogramSampleFunction(NULL);
14140      break;
14141    }
14142    result_ = true;
14143  }
14144
14145  bool result() { return result_; }
14146
14147 private:
14148  TestCase testCase_;
14149  bool result_;
14150};
14151
14152
14153static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14154  InitDefaultIsolateThread thread(testCase);
14155  thread.Start();
14156  thread.Join();
14157  CHECK_EQ(thread.result(), true);
14158}
14159
14160TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14161  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14162}
14163
14164TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14165  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14166}
14167
14168TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14169  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14170}
14171
14172TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14173  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14174}
14175
14176TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14177  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14178}
14179
14180TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14181  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14182}
14183
14184
14185TEST(StringCheckMultipleContexts) {
14186  const char* code =
14187      "(function() { return \"a\".charAt(0); })()";
14188
14189  {
14190    // Run the code twice in the first context to initialize the call IC.
14191    v8::HandleScope scope;
14192    LocalContext context1;
14193    ExpectString(code, "a");
14194    ExpectString(code, "a");
14195  }
14196
14197  {
14198    // Change the String.prototype in the second context and check
14199    // that the right function gets called.
14200    v8::HandleScope scope;
14201    LocalContext context2;
14202    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14203    ExpectString(code, "not a");
14204  }
14205}
14206
14207
14208TEST(NumberCheckMultipleContexts) {
14209  const char* code =
14210      "(function() { return (42).toString(); })()";
14211
14212  {
14213    // Run the code twice in the first context to initialize the call IC.
14214    v8::HandleScope scope;
14215    LocalContext context1;
14216    ExpectString(code, "42");
14217    ExpectString(code, "42");
14218  }
14219
14220  {
14221    // Change the Number.prototype in the second context and check
14222    // that the right function gets called.
14223    v8::HandleScope scope;
14224    LocalContext context2;
14225    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14226    ExpectString(code, "not 42");
14227  }
14228}
14229
14230
14231TEST(BooleanCheckMultipleContexts) {
14232  const char* code =
14233      "(function() { return true.toString(); })()";
14234
14235  {
14236    // Run the code twice in the first context to initialize the call IC.
14237    v8::HandleScope scope;
14238    LocalContext context1;
14239    ExpectString(code, "true");
14240    ExpectString(code, "true");
14241  }
14242
14243  {
14244    // Change the Boolean.prototype in the second context and check
14245    // that the right function gets called.
14246    v8::HandleScope scope;
14247    LocalContext context2;
14248    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14249    ExpectString(code, "");
14250  }
14251}
14252
14253
14254TEST(DontDeleteCellLoadIC) {
14255  const char* function_code =
14256      "function readCell() { while (true) { return cell; } }";
14257
14258  {
14259    // Run the code twice in the first context to initialize the load
14260    // IC for a don't delete cell.
14261    v8::HandleScope scope;
14262    LocalContext context1;
14263    CompileRun("var cell = \"first\";");
14264    ExpectBoolean("delete cell", false);
14265    CompileRun(function_code);
14266    ExpectString("readCell()", "first");
14267    ExpectString("readCell()", "first");
14268  }
14269
14270  {
14271    // Use a deletable cell in the second context.
14272    v8::HandleScope scope;
14273    LocalContext context2;
14274    CompileRun("cell = \"second\";");
14275    CompileRun(function_code);
14276    ExpectString("readCell()", "second");
14277    ExpectBoolean("delete cell", true);
14278    ExpectString("(function() {"
14279                 "  try {"
14280                 "    return readCell();"
14281                 "  } catch(e) {"
14282                 "    return e.toString();"
14283                 "  }"
14284                 "})()",
14285                 "ReferenceError: cell is not defined");
14286    CompileRun("cell = \"new_second\";");
14287    HEAP->CollectAllGarbage(true);
14288    ExpectString("readCell()", "new_second");
14289    ExpectString("readCell()", "new_second");
14290  }
14291}
14292
14293
14294TEST(DontDeleteCellLoadICForceDelete) {
14295  const char* function_code =
14296      "function readCell() { while (true) { return cell; } }";
14297
14298  // Run the code twice to initialize the load IC for a don't delete
14299  // cell.
14300  v8::HandleScope scope;
14301  LocalContext context;
14302  CompileRun("var cell = \"value\";");
14303  ExpectBoolean("delete cell", false);
14304  CompileRun(function_code);
14305  ExpectString("readCell()", "value");
14306  ExpectString("readCell()", "value");
14307
14308  // Delete the cell using the API and check the inlined code works
14309  // correctly.
14310  CHECK(context->Global()->ForceDelete(v8_str("cell")));
14311  ExpectString("(function() {"
14312               "  try {"
14313               "    return readCell();"
14314               "  } catch(e) {"
14315               "    return e.toString();"
14316               "  }"
14317               "})()",
14318               "ReferenceError: cell is not defined");
14319}
14320
14321
14322TEST(DontDeleteCellLoadICAPI) {
14323  const char* function_code =
14324      "function readCell() { while (true) { return cell; } }";
14325
14326  // Run the code twice to initialize the load IC for a don't delete
14327  // cell created using the API.
14328  v8::HandleScope scope;
14329  LocalContext context;
14330  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14331  ExpectBoolean("delete cell", false);
14332  CompileRun(function_code);
14333  ExpectString("readCell()", "value");
14334  ExpectString("readCell()", "value");
14335
14336  // Delete the cell using the API and check the inlined code works
14337  // correctly.
14338  CHECK(context->Global()->ForceDelete(v8_str("cell")));
14339  ExpectString("(function() {"
14340               "  try {"
14341               "    return readCell();"
14342               "  } catch(e) {"
14343               "    return e.toString();"
14344               "  }"
14345               "})()",
14346               "ReferenceError: cell is not defined");
14347}
14348
14349
14350TEST(RegExp) {
14351  v8::HandleScope scope;
14352  LocalContext context;
14353
14354  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14355  CHECK(re->IsRegExp());
14356  CHECK(re->GetSource()->Equals(v8_str("foo")));
14357  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14358
14359  re = v8::RegExp::New(v8_str("bar"),
14360                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14361                                                      v8::RegExp::kGlobal));
14362  CHECK(re->IsRegExp());
14363  CHECK(re->GetSource()->Equals(v8_str("bar")));
14364  CHECK_EQ(static_cast<int>(re->GetFlags()),
14365           v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14366
14367  re = v8::RegExp::New(v8_str("baz"),
14368                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14369                                                      v8::RegExp::kMultiline));
14370  CHECK(re->IsRegExp());
14371  CHECK(re->GetSource()->Equals(v8_str("baz")));
14372  CHECK_EQ(static_cast<int>(re->GetFlags()),
14373           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14374
14375  re = CompileRun("/quux/").As<v8::RegExp>();
14376  CHECK(re->IsRegExp());
14377  CHECK(re->GetSource()->Equals(v8_str("quux")));
14378  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14379
14380  re = CompileRun("/quux/gm").As<v8::RegExp>();
14381  CHECK(re->IsRegExp());
14382  CHECK(re->GetSource()->Equals(v8_str("quux")));
14383  CHECK_EQ(static_cast<int>(re->GetFlags()),
14384           v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14385
14386  // Override the RegExp constructor and check the API constructor
14387  // still works.
14388  CompileRun("RegExp = function() {}");
14389
14390  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14391  CHECK(re->IsRegExp());
14392  CHECK(re->GetSource()->Equals(v8_str("foobar")));
14393  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14394
14395  re = v8::RegExp::New(v8_str("foobarbaz"),
14396                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14397                                                      v8::RegExp::kMultiline));
14398  CHECK(re->IsRegExp());
14399  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14400  CHECK_EQ(static_cast<int>(re->GetFlags()),
14401           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14402
14403  context->Global()->Set(v8_str("re"), re);
14404  ExpectTrue("re.test('FoobarbaZ')");
14405
14406  // RegExps are objects on which you can set properties.
14407  re->Set(v8_str("property"), v8::Integer::New(32));
14408  v8::Handle<v8::Value> value = CompileRun("re.property");
14409  ASSERT_EQ(32, value->Int32Value());
14410
14411  v8::TryCatch try_catch;
14412  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14413  CHECK(re.IsEmpty());
14414  CHECK(try_catch.HasCaught());
14415  context->Global()->Set(v8_str("ex"), try_catch.Exception());
14416  ExpectTrue("ex instanceof SyntaxError");
14417}
14418
14419
14420THREADED_TEST(Equals) {
14421  v8::HandleScope handleScope;
14422  LocalContext localContext;
14423
14424  v8::Handle<v8::Object> globalProxy = localContext->Global();
14425  v8::Handle<Value> global = globalProxy->GetPrototype();
14426
14427  CHECK(global->StrictEquals(global));
14428  CHECK(!global->StrictEquals(globalProxy));
14429  CHECK(!globalProxy->StrictEquals(global));
14430  CHECK(globalProxy->StrictEquals(globalProxy));
14431
14432  CHECK(global->Equals(global));
14433  CHECK(!global->Equals(globalProxy));
14434  CHECK(!globalProxy->Equals(global));
14435  CHECK(globalProxy->Equals(globalProxy));
14436}
14437
14438
14439static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14440                                    const v8::AccessorInfo& info ) {
14441  return v8_str("42!");
14442}
14443
14444
14445static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14446  v8::Handle<v8::Array> result = v8::Array::New();
14447  result->Set(0, v8_str("universalAnswer"));
14448  return result;
14449}
14450
14451
14452TEST(NamedEnumeratorAndForIn) {
14453  v8::HandleScope handle_scope;
14454  LocalContext context;
14455  v8::Context::Scope context_scope(context.local());
14456
14457  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14458  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14459  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14460  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14461        "var result = []; for (var k in o) result.push(k); result"));
14462  CHECK_EQ(1, result->Length());
14463  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14464}
14465
14466
14467TEST(DefinePropertyPostDetach) {
14468  v8::HandleScope scope;
14469  LocalContext context;
14470  v8::Handle<v8::Object> proxy = context->Global();
14471  v8::Handle<v8::Function> define_property =
14472      CompileRun("(function() {"
14473                 "  Object.defineProperty("
14474                 "    this,"
14475                 "    1,"
14476                 "    { configurable: true, enumerable: true, value: 3 });"
14477                 "})").As<Function>();
14478  context->DetachGlobal();
14479  define_property->Call(proxy, 0, NULL);
14480}
14481
14482
14483static void InstallContextId(v8::Handle<Context> context, int id) {
14484  Context::Scope scope(context);
14485  CompileRun("Object.prototype").As<Object>()->
14486      Set(v8_str("context_id"), v8::Integer::New(id));
14487}
14488
14489
14490static void CheckContextId(v8::Handle<Object> object, int expected) {
14491  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14492}
14493
14494
14495THREADED_TEST(CreationContext) {
14496  HandleScope handle_scope;
14497  Persistent<Context> context1 = Context::New();
14498  InstallContextId(context1, 1);
14499  Persistent<Context> context2 = Context::New();
14500  InstallContextId(context2, 2);
14501  Persistent<Context> context3 = Context::New();
14502  InstallContextId(context3, 3);
14503
14504  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14505
14506  Local<Object> object1;
14507  Local<Function> func1;
14508  {
14509    Context::Scope scope(context1);
14510    object1 = Object::New();
14511    func1 = tmpl->GetFunction();
14512  }
14513
14514  Local<Object> object2;
14515  Local<Function> func2;
14516  {
14517    Context::Scope scope(context2);
14518    object2 = Object::New();
14519    func2 = tmpl->GetFunction();
14520  }
14521
14522  Local<Object> instance1;
14523  Local<Object> instance2;
14524
14525  {
14526    Context::Scope scope(context3);
14527    instance1 = func1->NewInstance();
14528    instance2 = func2->NewInstance();
14529  }
14530
14531  CHECK(object1->CreationContext() == context1);
14532  CheckContextId(object1, 1);
14533  CHECK(func1->CreationContext() == context1);
14534  CheckContextId(func1, 1);
14535  CHECK(instance1->CreationContext() == context1);
14536  CheckContextId(instance1, 1);
14537  CHECK(object2->CreationContext() == context2);
14538  CheckContextId(object2, 2);
14539  CHECK(func2->CreationContext() == context2);
14540  CheckContextId(func2, 2);
14541  CHECK(instance2->CreationContext() == context2);
14542  CheckContextId(instance2, 2);
14543
14544  {
14545    Context::Scope scope(context1);
14546    CHECK(object1->CreationContext() == context1);
14547    CheckContextId(object1, 1);
14548    CHECK(func1->CreationContext() == context1);
14549    CheckContextId(func1, 1);
14550    CHECK(instance1->CreationContext() == context1);
14551    CheckContextId(instance1, 1);
14552    CHECK(object2->CreationContext() == context2);
14553    CheckContextId(object2, 2);
14554    CHECK(func2->CreationContext() == context2);
14555    CheckContextId(func2, 2);
14556    CHECK(instance2->CreationContext() == context2);
14557    CheckContextId(instance2, 2);
14558  }
14559
14560  {
14561    Context::Scope scope(context2);
14562    CHECK(object1->CreationContext() == context1);
14563    CheckContextId(object1, 1);
14564    CHECK(func1->CreationContext() == context1);
14565    CheckContextId(func1, 1);
14566    CHECK(instance1->CreationContext() == context1);
14567    CheckContextId(instance1, 1);
14568    CHECK(object2->CreationContext() == context2);
14569    CheckContextId(object2, 2);
14570    CHECK(func2->CreationContext() == context2);
14571    CheckContextId(func2, 2);
14572    CHECK(instance2->CreationContext() == context2);
14573    CheckContextId(instance2, 2);
14574  }
14575
14576  context1.Dispose();
14577  context2.Dispose();
14578  context3.Dispose();
14579}
14580
14581
14582Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14583                                                  const AccessorInfo& info) {
14584  if (index == 42) return v8_str("yes");
14585  return Handle<v8::Integer>();
14586}
14587
14588
14589Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14590                                                const AccessorInfo& info) {
14591  if (property->Equals(v8_str("foo"))) return v8_str("yes");
14592  return Handle<Value>();
14593}
14594
14595
14596Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14597    uint32_t index, const AccessorInfo& info) {
14598  if (index == 42) return v8_num(1).As<v8::Integer>();
14599  return Handle<v8::Integer>();
14600}
14601
14602
14603Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14604    Local<String> property, const AccessorInfo& info) {
14605  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14606  return Handle<v8::Integer>();
14607}
14608
14609
14610Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14611    Local<String> property, const AccessorInfo& info) {
14612  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14613  return Handle<v8::Integer>();
14614}
14615
14616
14617Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14618                                           const AccessorInfo& info) {
14619  return v8_str("yes");
14620}
14621
14622
14623TEST(HasOwnProperty) {
14624  v8::HandleScope scope;
14625  LocalContext env;
14626  { // Check normal properties and defined getters.
14627    Handle<Value> value = CompileRun(
14628        "function Foo() {"
14629        "    this.foo = 11;"
14630        "    this.__defineGetter__('baz', function() { return 1; });"
14631        "};"
14632        "function Bar() { "
14633        "    this.bar = 13;"
14634        "    this.__defineGetter__('bla', function() { return 2; });"
14635        "};"
14636        "Bar.prototype = new Foo();"
14637        "new Bar();");
14638    CHECK(value->IsObject());
14639    Handle<Object> object = value->ToObject();
14640    CHECK(object->Has(v8_str("foo")));
14641    CHECK(!object->HasOwnProperty(v8_str("foo")));
14642    CHECK(object->HasOwnProperty(v8_str("bar")));
14643    CHECK(object->Has(v8_str("baz")));
14644    CHECK(!object->HasOwnProperty(v8_str("baz")));
14645    CHECK(object->HasOwnProperty(v8_str("bla")));
14646  }
14647  { // Check named getter interceptors.
14648    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14649    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14650    Handle<Object> instance = templ->NewInstance();
14651    CHECK(!instance->HasOwnProperty(v8_str("42")));
14652    CHECK(instance->HasOwnProperty(v8_str("foo")));
14653    CHECK(!instance->HasOwnProperty(v8_str("bar")));
14654  }
14655  { // Check indexed getter interceptors.
14656    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14657    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14658    Handle<Object> instance = templ->NewInstance();
14659    CHECK(instance->HasOwnProperty(v8_str("42")));
14660    CHECK(!instance->HasOwnProperty(v8_str("43")));
14661    CHECK(!instance->HasOwnProperty(v8_str("foo")));
14662  }
14663  { // Check named query interceptors.
14664    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14665    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14666    Handle<Object> instance = templ->NewInstance();
14667    CHECK(instance->HasOwnProperty(v8_str("foo")));
14668    CHECK(!instance->HasOwnProperty(v8_str("bar")));
14669  }
14670  { // Check indexed query interceptors.
14671    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14672    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14673    Handle<Object> instance = templ->NewInstance();
14674    CHECK(instance->HasOwnProperty(v8_str("42")));
14675    CHECK(!instance->HasOwnProperty(v8_str("41")));
14676  }
14677  { // Check callbacks.
14678    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14679    templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14680    Handle<Object> instance = templ->NewInstance();
14681    CHECK(instance->HasOwnProperty(v8_str("foo")));
14682    CHECK(!instance->HasOwnProperty(v8_str("bar")));
14683  }
14684  { // Check that query wins on disagreement.
14685    Handle<ObjectTemplate> templ = ObjectTemplate::New();
14686    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14687                                   0,
14688                                   HasOwnPropertyNamedPropertyQuery2);
14689    Handle<Object> instance = templ->NewInstance();
14690    CHECK(!instance->HasOwnProperty(v8_str("foo")));
14691    CHECK(instance->HasOwnProperty(v8_str("bar")));
14692  }
14693}
14694
14695
14696void CheckCodeGenerationAllowed() {
14697  Handle<Value> result = CompileRun("eval('42')");
14698  CHECK_EQ(42, result->Int32Value());
14699  result = CompileRun("(function(e) { return e('42'); })(eval)");
14700  CHECK_EQ(42, result->Int32Value());
14701  result = CompileRun("var f = new Function('return 42'); f()");
14702  CHECK_EQ(42, result->Int32Value());
14703}
14704
14705
14706void CheckCodeGenerationDisallowed() {
14707  TryCatch try_catch;
14708
14709  Handle<Value> result = CompileRun("eval('42')");
14710  CHECK(result.IsEmpty());
14711  CHECK(try_catch.HasCaught());
14712  try_catch.Reset();
14713
14714  result = CompileRun("(function(e) { return e('42'); })(eval)");
14715  CHECK(result.IsEmpty());
14716  CHECK(try_catch.HasCaught());
14717  try_catch.Reset();
14718
14719  result = CompileRun("var f = new Function('return 42'); f()");
14720  CHECK(result.IsEmpty());
14721  CHECK(try_catch.HasCaught());
14722}
14723
14724
14725bool CodeGenerationAllowed(Local<Context> context) {
14726  ApiTestFuzzer::Fuzz();
14727  return true;
14728}
14729
14730
14731bool CodeGenerationDisallowed(Local<Context> context) {
14732  ApiTestFuzzer::Fuzz();
14733  return false;
14734}
14735
14736
14737THREADED_TEST(AllowCodeGenFromStrings) {
14738  v8::HandleScope scope;
14739  LocalContext context;
14740
14741  // eval and the Function constructor allowed by default.
14742  CheckCodeGenerationAllowed();
14743
14744  // Disallow eval and the Function constructor.
14745  context->AllowCodeGenerationFromStrings(false);
14746  CheckCodeGenerationDisallowed();
14747
14748  // Allow again.
14749  context->AllowCodeGenerationFromStrings(true);
14750  CheckCodeGenerationAllowed();
14751
14752  // Disallow but setting a global callback that will allow the calls.
14753  context->AllowCodeGenerationFromStrings(false);
14754  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14755  CheckCodeGenerationAllowed();
14756
14757  // Set a callback that disallows the code generation.
14758  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14759  CheckCodeGenerationDisallowed();
14760}
14761
14762
14763static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14764  return v8::Undefined();
14765}
14766
14767
14768THREADED_TEST(CallAPIFunctionOnNonObject) {
14769  v8::HandleScope scope;
14770  LocalContext context;
14771  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14772  Handle<Function> function = templ->GetFunction();
14773  context->Global()->Set(v8_str("f"), function);
14774  TryCatch try_catch;
14775  CompileRun("f.call(2)");
14776}
14777
14778
14779// Regression test for issue 1470.
14780THREADED_TEST(ReadOnlyIndexedProperties) {
14781  v8::HandleScope scope;
14782  Local<ObjectTemplate> templ = ObjectTemplate::New();
14783
14784  LocalContext context;
14785  Local<v8::Object> obj = templ->NewInstance();
14786  context->Global()->Set(v8_str("obj"), obj);
14787  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14788  obj->Set(v8_str("1"), v8_str("foobar"));
14789  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14790  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14791  obj->Set(v8_num(2), v8_str("foobar"));
14792  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14793
14794  // Test non-smi case.
14795  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14796  obj->Set(v8_str("2000000000"), v8_str("foobar"));
14797  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14798}
14799
14800
14801THREADED_TEST(Regress1516) {
14802  v8::HandleScope scope;
14803
14804  LocalContext context;
14805  { v8::HandleScope temp_scope;
14806    CompileRun("({'a': 0})");
14807  }
14808
14809  int elements;
14810  { i::MapCache* map_cache =
14811        i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14812    elements = map_cache->NumberOfElements();
14813    CHECK_LE(1, elements);
14814  }
14815
14816  i::Isolate::Current()->heap()->CollectAllGarbage(true);
14817  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14818    if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14819      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14820      CHECK_GT(elements, map_cache->NumberOfElements());
14821    }
14822  }
14823}
14824
14825
14826static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
14827                                                Local<Value> name,
14828                                                v8::AccessType type,
14829                                                Local<Value> data) {
14830  // Only block read access to __proto__.
14831  if (type == v8::ACCESS_GET &&
14832      name->IsString() &&
14833      name->ToString()->Length() == 9 &&
14834      name->ToString()->Utf8Length() == 9) {
14835    char buffer[10];
14836    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
14837    return strncmp(buffer, "__proto__", 9) != 0;
14838  }
14839
14840  return true;
14841}
14842
14843
14844THREADED_TEST(Regress93759) {
14845  HandleScope scope;
14846
14847  // Template for object with security check.
14848  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
14849  // We don't do indexing, so any callback can be used for that.
14850  no_proto_template->SetAccessCheckCallbacks(
14851      BlockProtoNamedSecurityTestCallback,
14852      IndexedSecurityTestCallback);
14853
14854  // Templates for objects with hidden prototypes and possibly security check.
14855  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
14856  hidden_proto_template->SetHiddenPrototype(true);
14857
14858  Local<FunctionTemplate> protected_hidden_proto_template =
14859      v8::FunctionTemplate::New();
14860  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
14861      BlockProtoNamedSecurityTestCallback,
14862      IndexedSecurityTestCallback);
14863  protected_hidden_proto_template->SetHiddenPrototype(true);
14864
14865  // Context for "foreign" objects used in test.
14866  Persistent<Context> context = v8::Context::New();
14867  context->Enter();
14868
14869  // Plain object, no security check.
14870  Local<Object> simple_object = Object::New();
14871
14872  // Object with explicit security check.
14873  Local<Object> protected_object =
14874      no_proto_template->NewInstance();
14875
14876  // JSGlobalProxy object, always have security check.
14877  Local<Object> proxy_object =
14878      context->Global();
14879
14880  // Global object, the  prototype of proxy_object. No security checks.
14881  Local<Object> global_object =
14882      proxy_object->GetPrototype()->ToObject();
14883
14884  // Hidden prototype without security check.
14885  Local<Object> hidden_prototype =
14886      hidden_proto_template->GetFunction()->NewInstance();
14887  Local<Object> object_with_hidden =
14888    Object::New();
14889  object_with_hidden->SetPrototype(hidden_prototype);
14890
14891  // Hidden prototype with security check on the hidden prototype.
14892  Local<Object> protected_hidden_prototype =
14893      protected_hidden_proto_template->GetFunction()->NewInstance();
14894  Local<Object> object_with_protected_hidden =
14895    Object::New();
14896  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
14897
14898  context->Exit();
14899
14900  // Template for object for second context. Values to test are put on it as
14901  // properties.
14902  Local<ObjectTemplate> global_template = ObjectTemplate::New();
14903  global_template->Set(v8_str("simple"), simple_object);
14904  global_template->Set(v8_str("protected"), protected_object);
14905  global_template->Set(v8_str("global"), global_object);
14906  global_template->Set(v8_str("proxy"), proxy_object);
14907  global_template->Set(v8_str("hidden"), object_with_hidden);
14908  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
14909
14910  LocalContext context2(NULL, global_template);
14911
14912  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
14913  CHECK(result1->Equals(simple_object->GetPrototype()));
14914
14915  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
14916  CHECK(result2->Equals(Undefined()));
14917
14918  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
14919  CHECK(result3->Equals(global_object->GetPrototype()));
14920
14921  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
14922  CHECK(result4->Equals(Undefined()));
14923
14924  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
14925  CHECK(result5->Equals(
14926      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
14927
14928  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
14929  CHECK(result6->Equals(Undefined()));
14930
14931  context.Dispose();
14932}
14933