test-api.cc revision f7060e27768c550ace7ec48ad8c093466db52dfa
1// Copyright 2007-2009 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 "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
38#include "utils.h"
39#include "cctest.h"
40
41static const bool kLogThreading = true;
42
43static bool IsNaN(double x) {
44#ifdef WIN32
45  return _isnan(x);
46#else
47  return isnan(x);
48#endif
49}
50
51using ::v8::ObjectTemplate;
52using ::v8::Value;
53using ::v8::Context;
54using ::v8::Local;
55using ::v8::String;
56using ::v8::Script;
57using ::v8::Function;
58using ::v8::AccessorInfo;
59using ::v8::Extension;
60
61namespace i = ::v8::internal;
62
63
64static void ExpectString(const char* code, const char* expected) {
65  Local<Value> result = CompileRun(code);
66  CHECK(result->IsString());
67  String::AsciiValue ascii(result);
68  CHECK_EQ(expected, *ascii);
69}
70
71
72static void ExpectBoolean(const char* code, bool expected) {
73  Local<Value> result = CompileRun(code);
74  CHECK(result->IsBoolean());
75  CHECK_EQ(expected, result->BooleanValue());
76}
77
78
79static void ExpectTrue(const char* code) {
80  ExpectBoolean(code, true);
81}
82
83
84static void ExpectObject(const char* code, Local<Value> expected) {
85  Local<Value> result = CompileRun(code);
86  CHECK(result->Equals(expected));
87}
88
89
90static int signature_callback_count;
91static v8::Handle<Value> IncrementingSignatureCallback(
92    const v8::Arguments& args) {
93  ApiTestFuzzer::Fuzz();
94  signature_callback_count++;
95  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
96  for (int i = 0; i < args.Length(); i++)
97    result->Set(v8::Integer::New(i), args[i]);
98  return result;
99}
100
101
102static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
103  ApiTestFuzzer::Fuzz();
104  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
105  for (int i = 0; i < args.Length(); i++) {
106    result->Set(v8::Integer::New(i), args[i]);
107  }
108  return result;
109}
110
111
112THREADED_TEST(Handles) {
113  v8::HandleScope scope;
114  Local<Context> local_env;
115  {
116    LocalContext env;
117    local_env = env.local();
118  }
119
120  // Local context should still be live.
121  CHECK(!local_env.IsEmpty());
122  local_env->Enter();
123
124  v8::Handle<v8::Primitive> undef = v8::Undefined();
125  CHECK(!undef.IsEmpty());
126  CHECK(undef->IsUndefined());
127
128  const char* c_source = "1 + 2 + 3";
129  Local<String> source = String::New(c_source);
130  Local<Script> script = Script::Compile(source);
131  CHECK_EQ(6, script->Run()->Int32Value());
132
133  local_env->Exit();
134}
135
136
137THREADED_TEST(ReceiverSignature) {
138  v8::HandleScope scope;
139  LocalContext env;
140  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
141  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
142  fun->PrototypeTemplate()->Set(
143      v8_str("m"),
144      v8::FunctionTemplate::New(IncrementingSignatureCallback,
145                                v8::Handle<Value>(),
146                                sig));
147  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
148  signature_callback_count = 0;
149  CompileRun(
150      "var o = new Fun();"
151      "o.m();");
152  CHECK_EQ(1, signature_callback_count);
153  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
154  sub_fun->Inherit(fun);
155  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
156  CompileRun(
157      "var o = new SubFun();"
158      "o.m();");
159  CHECK_EQ(2, signature_callback_count);
160
161  v8::TryCatch try_catch;
162  CompileRun(
163      "var o = { };"
164      "o.m = Fun.prototype.m;"
165      "o.m();");
166  CHECK_EQ(2, signature_callback_count);
167  CHECK(try_catch.HasCaught());
168  try_catch.Reset();
169  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
170  sub_fun->Inherit(fun);
171  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
172  CompileRun(
173      "var o = new UnrelFun();"
174      "o.m = Fun.prototype.m;"
175      "o.m();");
176  CHECK_EQ(2, signature_callback_count);
177  CHECK(try_catch.HasCaught());
178}
179
180
181
182
183THREADED_TEST(ArgumentSignature) {
184  v8::HandleScope scope;
185  LocalContext env;
186  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
187  cons->SetClassName(v8_str("Cons"));
188  v8::Handle<v8::Signature> sig =
189      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
190  v8::Handle<v8::FunctionTemplate> fun =
191      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
192  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
193  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
194
195  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
196  CHECK(value1->IsTrue());
197
198  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
199  CHECK(value2->IsTrue());
200
201  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
202  CHECK(value3->IsTrue());
203
204  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
205  cons1->SetClassName(v8_str("Cons1"));
206  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
207  cons2->SetClassName(v8_str("Cons2"));
208  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
209  cons3->SetClassName(v8_str("Cons3"));
210
211  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
212  v8::Handle<v8::Signature> wsig =
213      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
214  v8::Handle<v8::FunctionTemplate> fun2 =
215      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
216
217  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
218  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
219  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
220  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
221  v8::Handle<Value> value4 = CompileRun(
222      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
223      "'[object Cons1],[object Cons2],[object Cons3]'");
224  CHECK(value4->IsTrue());
225
226  v8::Handle<Value> value5 = CompileRun(
227      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
228  CHECK(value5->IsTrue());
229
230  v8::Handle<Value> value6 = CompileRun(
231      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
232  CHECK(value6->IsTrue());
233
234  v8::Handle<Value> value7 = CompileRun(
235      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
236      "'[object Cons1],[object Cons2],[object Cons3],d';");
237  CHECK(value7->IsTrue());
238
239  v8::Handle<Value> value8 = CompileRun(
240      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
241  CHECK(value8->IsTrue());
242}
243
244
245THREADED_TEST(HulIgennem) {
246  v8::HandleScope scope;
247  LocalContext env;
248  v8::Handle<v8::Primitive> undef = v8::Undefined();
249  Local<String> undef_str = undef->ToString();
250  char* value = i::NewArray<char>(undef_str->Length() + 1);
251  undef_str->WriteAscii(value);
252  CHECK_EQ(0, strcmp(value, "undefined"));
253  i::DeleteArray(value);
254}
255
256
257THREADED_TEST(Access) {
258  v8::HandleScope scope;
259  LocalContext env;
260  Local<v8::Object> obj = v8::Object::New();
261  Local<Value> foo_before = obj->Get(v8_str("foo"));
262  CHECK(foo_before->IsUndefined());
263  Local<String> bar_str = v8_str("bar");
264  obj->Set(v8_str("foo"), bar_str);
265  Local<Value> foo_after = obj->Get(v8_str("foo"));
266  CHECK(!foo_after->IsUndefined());
267  CHECK(foo_after->IsString());
268  CHECK_EQ(bar_str, foo_after);
269}
270
271
272THREADED_TEST(AccessElement) {
273  v8::HandleScope scope;
274  LocalContext env;
275  Local<v8::Object> obj = v8::Object::New();
276  Local<Value> before = obj->Get(1);
277  CHECK(before->IsUndefined());
278  Local<String> bar_str = v8_str("bar");
279  obj->Set(1, bar_str);
280  Local<Value> after = obj->Get(1);
281  CHECK(!after->IsUndefined());
282  CHECK(after->IsString());
283  CHECK_EQ(bar_str, after);
284
285  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
286  CHECK_EQ(v8_str("a"), value->Get(0));
287  CHECK_EQ(v8_str("b"), value->Get(1));
288}
289
290
291THREADED_TEST(Script) {
292  v8::HandleScope scope;
293  LocalContext env;
294  const char* c_source = "1 + 2 + 3";
295  Local<String> source = String::New(c_source);
296  Local<Script> script = Script::Compile(source);
297  CHECK_EQ(6, script->Run()->Int32Value());
298}
299
300
301static uint16_t* AsciiToTwoByteString(const char* source) {
302  int array_length = i::StrLength(source) + 1;
303  uint16_t* converted = i::NewArray<uint16_t>(array_length);
304  for (int i = 0; i < array_length; i++) converted[i] = source[i];
305  return converted;
306}
307
308
309class TestResource: public String::ExternalStringResource {
310 public:
311  static int dispose_count;
312
313  explicit TestResource(uint16_t* data)
314      : data_(data), length_(0) {
315    while (data[length_]) ++length_;
316  }
317
318  ~TestResource() {
319    i::DeleteArray(data_);
320    ++dispose_count;
321  }
322
323  const uint16_t* data() const {
324    return data_;
325  }
326
327  size_t length() const {
328    return length_;
329  }
330 private:
331  uint16_t* data_;
332  size_t length_;
333};
334
335
336int TestResource::dispose_count = 0;
337
338
339class TestAsciiResource: public String::ExternalAsciiStringResource {
340 public:
341  static int dispose_count;
342
343  explicit TestAsciiResource(const char* data)
344      : data_(data),
345        length_(strlen(data)) { }
346
347  ~TestAsciiResource() {
348    i::DeleteArray(data_);
349    ++dispose_count;
350  }
351
352  const char* data() const {
353    return data_;
354  }
355
356  size_t length() const {
357    return length_;
358  }
359 private:
360  const char* data_;
361  size_t length_;
362};
363
364
365int TestAsciiResource::dispose_count = 0;
366
367
368THREADED_TEST(ScriptUsingStringResource) {
369  TestResource::dispose_count = 0;
370  const char* c_source = "1 + 2 * 3";
371  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
372  {
373    v8::HandleScope scope;
374    LocalContext env;
375    TestResource* resource = new TestResource(two_byte_source);
376    Local<String> source = String::NewExternal(resource);
377    Local<Script> script = Script::Compile(source);
378    Local<Value> value = script->Run();
379    CHECK(value->IsNumber());
380    CHECK_EQ(7, value->Int32Value());
381    CHECK(source->IsExternal());
382    CHECK_EQ(resource,
383             static_cast<TestResource*>(source->GetExternalStringResource()));
384    v8::internal::Heap::CollectAllGarbage(false);
385    CHECK_EQ(0, TestResource::dispose_count);
386  }
387  v8::internal::CompilationCache::Clear();
388  v8::internal::Heap::CollectAllGarbage(false);
389  CHECK_EQ(1, TestResource::dispose_count);
390}
391
392
393THREADED_TEST(ScriptUsingAsciiStringResource) {
394  TestAsciiResource::dispose_count = 0;
395  const char* c_source = "1 + 2 * 3";
396  {
397    v8::HandleScope scope;
398    LocalContext env;
399    Local<String> source =
400        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
401    Local<Script> script = Script::Compile(source);
402    Local<Value> value = script->Run();
403    CHECK(value->IsNumber());
404    CHECK_EQ(7, value->Int32Value());
405    v8::internal::Heap::CollectAllGarbage(false);
406    CHECK_EQ(0, TestAsciiResource::dispose_count);
407  }
408  v8::internal::CompilationCache::Clear();
409  v8::internal::Heap::CollectAllGarbage(false);
410  CHECK_EQ(1, TestAsciiResource::dispose_count);
411}
412
413
414THREADED_TEST(ScriptMakingExternalString) {
415  TestResource::dispose_count = 0;
416  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
417  {
418    v8::HandleScope scope;
419    LocalContext env;
420    Local<String> source = String::New(two_byte_source);
421    // Trigger GCs so that the newly allocated string moves to old gen.
422    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
423    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
424    bool success = source->MakeExternal(new TestResource(two_byte_source));
425    CHECK(success);
426    Local<Script> script = Script::Compile(source);
427    Local<Value> value = script->Run();
428    CHECK(value->IsNumber());
429    CHECK_EQ(7, value->Int32Value());
430    v8::internal::Heap::CollectAllGarbage(false);
431    CHECK_EQ(0, TestResource::dispose_count);
432  }
433  v8::internal::CompilationCache::Clear();
434  v8::internal::Heap::CollectAllGarbage(false);
435  CHECK_EQ(1, TestResource::dispose_count);
436}
437
438
439THREADED_TEST(ScriptMakingExternalAsciiString) {
440  TestAsciiResource::dispose_count = 0;
441  const char* c_source = "1 + 2 * 3";
442  {
443    v8::HandleScope scope;
444    LocalContext env;
445    Local<String> source = v8_str(c_source);
446    // Trigger GCs so that the newly allocated string moves to old gen.
447    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
448    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
449    bool success = source->MakeExternal(
450        new TestAsciiResource(i::StrDup(c_source)));
451    CHECK(success);
452    Local<Script> script = Script::Compile(source);
453    Local<Value> value = script->Run();
454    CHECK(value->IsNumber());
455    CHECK_EQ(7, value->Int32Value());
456    v8::internal::Heap::CollectAllGarbage(false);
457    CHECK_EQ(0, TestAsciiResource::dispose_count);
458  }
459  v8::internal::CompilationCache::Clear();
460  v8::internal::Heap::CollectAllGarbage(false);
461  CHECK_EQ(1, TestAsciiResource::dispose_count);
462}
463
464
465TEST(MakingExternalStringConditions) {
466  v8::HandleScope scope;
467  LocalContext env;
468
469  // Free some space in the new space so that we can check freshness.
470  i::Heap::CollectGarbage(0, i::NEW_SPACE);
471  i::Heap::CollectGarbage(0, i::NEW_SPACE);
472
473  Local<String> small_string = String::New(AsciiToTwoByteString("small"));
474  // We should refuse to externalize newly created small string.
475  CHECK(!small_string->CanMakeExternal());
476  // Trigger GCs so that the newly allocated string moves to old gen.
477  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
478  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
479  // Old space strings should be accepted.
480  CHECK(small_string->CanMakeExternal());
481
482  small_string = String::New(AsciiToTwoByteString("small 2"));
483  // We should refuse externalizing newly created small string.
484  CHECK(!small_string->CanMakeExternal());
485  for (int i = 0; i < 100; i++) {
486    String::Value value(small_string);
487  }
488  // Frequently used strings should be accepted.
489  CHECK(small_string->CanMakeExternal());
490
491  const int buf_size = 10 * 1024;
492  char* buf = i::NewArray<char>(buf_size);
493  memset(buf, 'a', buf_size);
494  buf[buf_size - 1] = '\0';
495  Local<String> large_string = String::New(AsciiToTwoByteString(buf));
496  i::DeleteArray(buf);
497  // Large strings should be immediately accepted.
498  CHECK(large_string->CanMakeExternal());
499}
500
501
502TEST(MakingExternalAsciiStringConditions) {
503  v8::HandleScope scope;
504  LocalContext env;
505
506  // Free some space in the new space so that we can check freshness.
507  i::Heap::CollectGarbage(0, i::NEW_SPACE);
508  i::Heap::CollectGarbage(0, i::NEW_SPACE);
509
510  Local<String> small_string = String::New("small");
511  // We should refuse to externalize newly created small string.
512  CHECK(!small_string->CanMakeExternal());
513  // Trigger GCs so that the newly allocated string moves to old gen.
514  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
515  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
516  // Old space strings should be accepted.
517  CHECK(small_string->CanMakeExternal());
518
519  small_string = String::New("small 2");
520  // We should refuse externalizing newly created small string.
521  CHECK(!small_string->CanMakeExternal());
522  for (int i = 0; i < 100; i++) {
523    String::Value value(small_string);
524  }
525  // Frequently used strings should be accepted.
526  CHECK(small_string->CanMakeExternal());
527
528  const int buf_size = 10 * 1024;
529  char* buf = i::NewArray<char>(buf_size);
530  memset(buf, 'a', buf_size);
531  buf[buf_size - 1] = '\0';
532  Local<String> large_string = String::New(buf);
533  i::DeleteArray(buf);
534  // Large strings should be immediately accepted.
535  CHECK(large_string->CanMakeExternal());
536}
537
538
539THREADED_TEST(UsingExternalString) {
540  {
541    v8::HandleScope scope;
542    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
543    Local<String> string =
544        String::NewExternal(new TestResource(two_byte_string));
545    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
546    // Trigger GCs so that the newly allocated string moves to old gen.
547    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
548    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
549    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
550    CHECK(isymbol->IsSymbol());
551  }
552  i::Heap::CollectAllGarbage(false);
553  i::Heap::CollectAllGarbage(false);
554}
555
556
557THREADED_TEST(UsingExternalAsciiString) {
558  {
559    v8::HandleScope scope;
560    const char* one_byte_string = "test string";
561    Local<String> string = String::NewExternal(
562        new TestAsciiResource(i::StrDup(one_byte_string)));
563    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
564    // Trigger GCs so that the newly allocated string moves to old gen.
565    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
566    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
567    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
568    CHECK(isymbol->IsSymbol());
569  }
570  i::Heap::CollectAllGarbage(false);
571  i::Heap::CollectAllGarbage(false);
572}
573
574
575THREADED_TEST(ScavengeExternalString) {
576  TestResource::dispose_count = 0;
577  bool in_new_space = false;
578  {
579    v8::HandleScope scope;
580    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
581    Local<String> string =
582        String::NewExternal(new TestResource(two_byte_string));
583    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
584    i::Heap::CollectGarbage(0, i::NEW_SPACE);
585    in_new_space = i::Heap::InNewSpace(*istring);
586    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
587    CHECK_EQ(0, TestResource::dispose_count);
588  }
589  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
590  CHECK_EQ(1, TestResource::dispose_count);
591}
592
593
594THREADED_TEST(ScavengeExternalAsciiString) {
595  TestAsciiResource::dispose_count = 0;
596  bool in_new_space = false;
597  {
598    v8::HandleScope scope;
599    const char* one_byte_string = "test string";
600    Local<String> string = String::NewExternal(
601        new TestAsciiResource(i::StrDup(one_byte_string)));
602    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
603    i::Heap::CollectGarbage(0, i::NEW_SPACE);
604    in_new_space = i::Heap::InNewSpace(*istring);
605    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
606    CHECK_EQ(0, TestAsciiResource::dispose_count);
607  }
608  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
609  CHECK_EQ(1, TestAsciiResource::dispose_count);
610}
611
612
613THREADED_TEST(StringConcat) {
614  {
615    v8::HandleScope scope;
616    LocalContext env;
617    const char* one_byte_string_1 = "function a_times_t";
618    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
619    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
620    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
621    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
622    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
623    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
624    Local<String> left = v8_str(one_byte_string_1);
625    Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
626    Local<String> source = String::Concat(left, right);
627    right = String::NewExternal(
628        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
629    source = String::Concat(source, right);
630    right = String::NewExternal(
631        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
632    source = String::Concat(source, right);
633    right = v8_str(one_byte_string_2);
634    source = String::Concat(source, right);
635    right = String::New(AsciiToTwoByteString(two_byte_string_2));
636    source = String::Concat(source, right);
637    right = String::NewExternal(
638        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
639    source = String::Concat(source, right);
640    Local<Script> script = Script::Compile(source);
641    Local<Value> value = script->Run();
642    CHECK(value->IsNumber());
643    CHECK_EQ(68, value->Int32Value());
644  }
645  v8::internal::CompilationCache::Clear();
646  i::Heap::CollectAllGarbage(false);
647  i::Heap::CollectAllGarbage(false);
648}
649
650
651THREADED_TEST(GlobalProperties) {
652  v8::HandleScope scope;
653  LocalContext env;
654  v8::Handle<v8::Object> global = env->Global();
655  global->Set(v8_str("pi"), v8_num(3.1415926));
656  Local<Value> pi = global->Get(v8_str("pi"));
657  CHECK_EQ(3.1415926, pi->NumberValue());
658}
659
660
661static v8::Handle<Value> handle_call(const v8::Arguments& args) {
662  ApiTestFuzzer::Fuzz();
663  return v8_num(102);
664}
665
666
667static v8::Handle<Value> construct_call(const v8::Arguments& args) {
668  ApiTestFuzzer::Fuzz();
669  args.This()->Set(v8_str("x"), v8_num(1));
670  args.This()->Set(v8_str("y"), v8_num(2));
671  return args.This();
672}
673
674THREADED_TEST(FunctionTemplate) {
675  v8::HandleScope scope;
676  LocalContext env;
677  {
678    Local<v8::FunctionTemplate> fun_templ =
679        v8::FunctionTemplate::New(handle_call);
680    Local<Function> fun = fun_templ->GetFunction();
681    env->Global()->Set(v8_str("obj"), fun);
682    Local<Script> script = v8_compile("obj()");
683    CHECK_EQ(102, script->Run()->Int32Value());
684  }
685  // Use SetCallHandler to initialize a function template, should work like the
686  // previous one.
687  {
688    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
689    fun_templ->SetCallHandler(handle_call);
690    Local<Function> fun = fun_templ->GetFunction();
691    env->Global()->Set(v8_str("obj"), fun);
692    Local<Script> script = v8_compile("obj()");
693    CHECK_EQ(102, script->Run()->Int32Value());
694  }
695  // Test constructor calls.
696  {
697    Local<v8::FunctionTemplate> fun_templ =
698        v8::FunctionTemplate::New(construct_call);
699    fun_templ->SetClassName(v8_str("funky"));
700    Local<Function> fun = fun_templ->GetFunction();
701    env->Global()->Set(v8_str("obj"), fun);
702    Local<Script> script = v8_compile("var s = new obj(); s.x");
703    CHECK_EQ(1, script->Run()->Int32Value());
704
705    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
706    CHECK_EQ(v8_str("[object funky]"), result);
707  }
708}
709
710
711THREADED_TEST(FindInstanceInPrototypeChain) {
712  v8::HandleScope scope;
713  LocalContext env;
714
715  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
716  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
717  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
718  derived->Inherit(base);
719
720  Local<v8::Function> base_function = base->GetFunction();
721  Local<v8::Function> derived_function = derived->GetFunction();
722  Local<v8::Function> other_function = other->GetFunction();
723
724  Local<v8::Object> base_instance = base_function->NewInstance();
725  Local<v8::Object> derived_instance = derived_function->NewInstance();
726  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
727  Local<v8::Object> other_instance = other_function->NewInstance();
728  derived_instance2->Set(v8_str("__proto__"), derived_instance);
729  other_instance->Set(v8_str("__proto__"), derived_instance2);
730
731  // base_instance is only an instance of base.
732  CHECK_EQ(base_instance,
733           base_instance->FindInstanceInPrototypeChain(base));
734  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
735  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
736
737  // derived_instance is an instance of base and derived.
738  CHECK_EQ(derived_instance,
739           derived_instance->FindInstanceInPrototypeChain(base));
740  CHECK_EQ(derived_instance,
741           derived_instance->FindInstanceInPrototypeChain(derived));
742  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
743
744  // other_instance is an instance of other and its immediate
745  // prototype derived_instance2 is an instance of base and derived.
746  // Note, derived_instance is an instance of base and derived too,
747  // but it comes after derived_instance2 in the prototype chain of
748  // other_instance.
749  CHECK_EQ(derived_instance2,
750           other_instance->FindInstanceInPrototypeChain(base));
751  CHECK_EQ(derived_instance2,
752           other_instance->FindInstanceInPrototypeChain(derived));
753  CHECK_EQ(other_instance,
754           other_instance->FindInstanceInPrototypeChain(other));
755}
756
757
758THREADED_TEST(TinyInteger) {
759  v8::HandleScope scope;
760  LocalContext env;
761  int32_t value = 239;
762  Local<v8::Integer> value_obj = v8::Integer::New(value);
763  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
764}
765
766
767THREADED_TEST(BigSmiInteger) {
768  v8::HandleScope scope;
769  LocalContext env;
770  int32_t value = i::Smi::kMaxValue;
771  // We cannot add one to a Smi::kMaxValue without wrapping.
772  if (i::kSmiValueSize < 32) {
773    CHECK(i::Smi::IsValid(value));
774    CHECK(!i::Smi::IsValid(value + 1));
775    Local<v8::Integer> value_obj = v8::Integer::New(value);
776    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
777  }
778}
779
780
781THREADED_TEST(BigInteger) {
782  v8::HandleScope scope;
783  LocalContext env;
784  // We cannot add one to a Smi::kMaxValue without wrapping.
785  if (i::kSmiValueSize < 32) {
786    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
787    // The code will not be run in that case, due to the "if" guard.
788    int32_t value =
789        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
790    CHECK(value > i::Smi::kMaxValue);
791    CHECK(!i::Smi::IsValid(value));
792    Local<v8::Integer> value_obj = v8::Integer::New(value);
793    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
794  }
795}
796
797
798THREADED_TEST(TinyUnsignedInteger) {
799  v8::HandleScope scope;
800  LocalContext env;
801  uint32_t value = 239;
802  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
803  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
804}
805
806
807THREADED_TEST(BigUnsignedSmiInteger) {
808  v8::HandleScope scope;
809  LocalContext env;
810  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
811  CHECK(i::Smi::IsValid(value));
812  CHECK(!i::Smi::IsValid(value + 1));
813  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
814  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
815}
816
817
818THREADED_TEST(BigUnsignedInteger) {
819  v8::HandleScope scope;
820  LocalContext env;
821  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
822  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
823  CHECK(!i::Smi::IsValid(value));
824  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
825  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
826}
827
828
829THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
830  v8::HandleScope scope;
831  LocalContext env;
832  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
833  uint32_t value = INT32_MAX_AS_UINT + 1;
834  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
835  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
836  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
837}
838
839
840THREADED_TEST(Number) {
841  v8::HandleScope scope;
842  LocalContext env;
843  double PI = 3.1415926;
844  Local<v8::Number> pi_obj = v8::Number::New(PI);
845  CHECK_EQ(PI, pi_obj->NumberValue());
846}
847
848
849THREADED_TEST(ToNumber) {
850  v8::HandleScope scope;
851  LocalContext env;
852  Local<String> str = v8_str("3.1415926");
853  CHECK_EQ(3.1415926, str->NumberValue());
854  v8::Handle<v8::Boolean> t = v8::True();
855  CHECK_EQ(1.0, t->NumberValue());
856  v8::Handle<v8::Boolean> f = v8::False();
857  CHECK_EQ(0.0, f->NumberValue());
858}
859
860
861THREADED_TEST(Date) {
862  v8::HandleScope scope;
863  LocalContext env;
864  double PI = 3.1415926;
865  Local<Value> date_obj = v8::Date::New(PI);
866  CHECK_EQ(3.0, date_obj->NumberValue());
867}
868
869
870THREADED_TEST(Boolean) {
871  v8::HandleScope scope;
872  LocalContext env;
873  v8::Handle<v8::Boolean> t = v8::True();
874  CHECK(t->Value());
875  v8::Handle<v8::Boolean> f = v8::False();
876  CHECK(!f->Value());
877  v8::Handle<v8::Primitive> u = v8::Undefined();
878  CHECK(!u->BooleanValue());
879  v8::Handle<v8::Primitive> n = v8::Null();
880  CHECK(!n->BooleanValue());
881  v8::Handle<String> str1 = v8_str("");
882  CHECK(!str1->BooleanValue());
883  v8::Handle<String> str2 = v8_str("x");
884  CHECK(str2->BooleanValue());
885  CHECK(!v8::Number::New(0)->BooleanValue());
886  CHECK(v8::Number::New(-1)->BooleanValue());
887  CHECK(v8::Number::New(1)->BooleanValue());
888  CHECK(v8::Number::New(42)->BooleanValue());
889  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
890}
891
892
893static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
894  ApiTestFuzzer::Fuzz();
895  return v8_num(13.4);
896}
897
898
899static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
900  ApiTestFuzzer::Fuzz();
901  return v8_num(876);
902}
903
904
905THREADED_TEST(GlobalPrototype) {
906  v8::HandleScope scope;
907  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
908  func_templ->PrototypeTemplate()->Set(
909      "dummy",
910      v8::FunctionTemplate::New(DummyCallHandler));
911  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
912  templ->Set("x", v8_num(200));
913  templ->SetAccessor(v8_str("m"), GetM);
914  LocalContext env(0, templ);
915  v8::Handle<v8::Object> obj = env->Global();
916  v8::Handle<Script> script = v8_compile("dummy()");
917  v8::Handle<Value> result = script->Run();
918  CHECK_EQ(13.4, result->NumberValue());
919  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
920  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
921}
922
923
924THREADED_TEST(ObjectTemplate) {
925  v8::HandleScope scope;
926  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
927  templ1->Set("x", v8_num(10));
928  templ1->Set("y", v8_num(13));
929  LocalContext env;
930  Local<v8::Object> instance1 = templ1->NewInstance();
931  env->Global()->Set(v8_str("p"), instance1);
932  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
933  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
934  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
935  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
936  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
937  templ2->Set("a", v8_num(12));
938  templ2->Set("b", templ1);
939  Local<v8::Object> instance2 = templ2->NewInstance();
940  env->Global()->Set(v8_str("q"), instance2);
941  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
942  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
943  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
944  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
945}
946
947
948static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
949  ApiTestFuzzer::Fuzz();
950  return v8_num(17.2);
951}
952
953
954static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
955  ApiTestFuzzer::Fuzz();
956  return v8_num(15.2);
957}
958
959
960THREADED_TEST(DescriptorInheritance) {
961  v8::HandleScope scope;
962  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
963  super->PrototypeTemplate()->Set("flabby",
964                                  v8::FunctionTemplate::New(GetFlabby));
965  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
966
967  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
968
969  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
970  base1->Inherit(super);
971  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
972
973  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
974  base2->Inherit(super);
975  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
976
977  LocalContext env;
978
979  env->Global()->Set(v8_str("s"), super->GetFunction());
980  env->Global()->Set(v8_str("base1"), base1->GetFunction());
981  env->Global()->Set(v8_str("base2"), base2->GetFunction());
982
983  // Checks right __proto__ chain.
984  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
985  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
986
987  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
988
989  // Instance accessor should not be visible on function object or its prototype
990  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
991  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
992  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
993
994  env->Global()->Set(v8_str("obj"),
995                     base1->GetFunction()->NewInstance());
996  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
997  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
998  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
999  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1000  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1001
1002  env->Global()->Set(v8_str("obj2"),
1003                     base2->GetFunction()->NewInstance());
1004  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1005  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1006  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1007  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1008  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1009
1010  // base1 and base2 cannot cross reference to each's prototype
1011  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1012  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1013}
1014
1015
1016int echo_named_call_count;
1017
1018
1019static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1020                                           const AccessorInfo& info) {
1021  ApiTestFuzzer::Fuzz();
1022  CHECK_EQ(v8_str("data"), info.Data());
1023  echo_named_call_count++;
1024  return name;
1025}
1026
1027
1028THREADED_TEST(NamedPropertyHandlerGetter) {
1029  echo_named_call_count = 0;
1030  v8::HandleScope scope;
1031  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1032  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1033                                                     0, 0, 0, 0,
1034                                                     v8_str("data"));
1035  LocalContext env;
1036  env->Global()->Set(v8_str("obj"),
1037                     templ->GetFunction()->NewInstance());
1038  CHECK_EQ(echo_named_call_count, 0);
1039  v8_compile("obj.x")->Run();
1040  CHECK_EQ(echo_named_call_count, 1);
1041  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1042  v8::Handle<Value> str = CompileRun(code);
1043  String::AsciiValue value(str);
1044  CHECK_EQ(*value, "oddlepoddle");
1045  // Check default behavior
1046  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1047  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1048  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1049}
1050
1051
1052int echo_indexed_call_count = 0;
1053
1054
1055static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1056                                             const AccessorInfo& info) {
1057  ApiTestFuzzer::Fuzz();
1058  CHECK_EQ(v8_num(637), info.Data());
1059  echo_indexed_call_count++;
1060  return v8_num(index);
1061}
1062
1063
1064THREADED_TEST(IndexedPropertyHandlerGetter) {
1065  v8::HandleScope scope;
1066  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1067  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1068                                                       0, 0, 0, 0,
1069                                                       v8_num(637));
1070  LocalContext env;
1071  env->Global()->Set(v8_str("obj"),
1072                     templ->GetFunction()->NewInstance());
1073  Local<Script> script = v8_compile("obj[900]");
1074  CHECK_EQ(script->Run()->Int32Value(), 900);
1075}
1076
1077
1078v8::Handle<v8::Object> bottom;
1079
1080static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1081    uint32_t index,
1082    const AccessorInfo& info) {
1083  ApiTestFuzzer::Fuzz();
1084  CHECK(info.This()->Equals(bottom));
1085  return v8::Handle<Value>();
1086}
1087
1088static v8::Handle<Value> CheckThisNamedPropertyHandler(
1089    Local<String> name,
1090    const AccessorInfo& info) {
1091  ApiTestFuzzer::Fuzz();
1092  CHECK(info.This()->Equals(bottom));
1093  return v8::Handle<Value>();
1094}
1095
1096
1097v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1098                                                 Local<Value> value,
1099                                                 const AccessorInfo& info) {
1100  ApiTestFuzzer::Fuzz();
1101  CHECK(info.This()->Equals(bottom));
1102  return v8::Handle<Value>();
1103}
1104
1105
1106v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1107                                               Local<Value> value,
1108                                               const AccessorInfo& info) {
1109  ApiTestFuzzer::Fuzz();
1110  CHECK(info.This()->Equals(bottom));
1111  return v8::Handle<Value>();
1112}
1113
1114v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1115    uint32_t index,
1116    const AccessorInfo& info) {
1117  ApiTestFuzzer::Fuzz();
1118  CHECK(info.This()->Equals(bottom));
1119  return v8::Handle<v8::Boolean>();
1120}
1121
1122
1123v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1124                                                    const AccessorInfo& info) {
1125  ApiTestFuzzer::Fuzz();
1126  CHECK(info.This()->Equals(bottom));
1127  return v8::Handle<v8::Boolean>();
1128}
1129
1130
1131v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1132    uint32_t index,
1133    const AccessorInfo& info) {
1134  ApiTestFuzzer::Fuzz();
1135  CHECK(info.This()->Equals(bottom));
1136  return v8::Handle<v8::Boolean>();
1137}
1138
1139
1140v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1141    Local<String> property,
1142    const AccessorInfo& info) {
1143  ApiTestFuzzer::Fuzz();
1144  CHECK(info.This()->Equals(bottom));
1145  return v8::Handle<v8::Boolean>();
1146}
1147
1148
1149v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1150    const AccessorInfo& info) {
1151  ApiTestFuzzer::Fuzz();
1152  CHECK(info.This()->Equals(bottom));
1153  return v8::Handle<v8::Array>();
1154}
1155
1156
1157v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1158    const AccessorInfo& info) {
1159  ApiTestFuzzer::Fuzz();
1160  CHECK(info.This()->Equals(bottom));
1161  return v8::Handle<v8::Array>();
1162}
1163
1164
1165THREADED_TEST(PropertyHandlerInPrototype) {
1166  v8::HandleScope scope;
1167  LocalContext env;
1168
1169  // Set up a prototype chain with three interceptors.
1170  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1171  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1172      CheckThisIndexedPropertyHandler,
1173      CheckThisIndexedPropertySetter,
1174      CheckThisIndexedPropertyQuery,
1175      CheckThisIndexedPropertyDeleter,
1176      CheckThisIndexedPropertyEnumerator);
1177
1178  templ->InstanceTemplate()->SetNamedPropertyHandler(
1179      CheckThisNamedPropertyHandler,
1180      CheckThisNamedPropertySetter,
1181      CheckThisNamedPropertyQuery,
1182      CheckThisNamedPropertyDeleter,
1183      CheckThisNamedPropertyEnumerator);
1184
1185  bottom = templ->GetFunction()->NewInstance();
1186  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1187  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1188
1189  bottom->Set(v8_str("__proto__"), middle);
1190  middle->Set(v8_str("__proto__"), top);
1191  env->Global()->Set(v8_str("obj"), bottom);
1192
1193  // Indexed and named get.
1194  Script::Compile(v8_str("obj[0]"))->Run();
1195  Script::Compile(v8_str("obj.x"))->Run();
1196
1197  // Indexed and named set.
1198  Script::Compile(v8_str("obj[1] = 42"))->Run();
1199  Script::Compile(v8_str("obj.y = 42"))->Run();
1200
1201  // Indexed and named query.
1202  Script::Compile(v8_str("0 in obj"))->Run();
1203  Script::Compile(v8_str("'x' in obj"))->Run();
1204
1205  // Indexed and named deleter.
1206  Script::Compile(v8_str("delete obj[0]"))->Run();
1207  Script::Compile(v8_str("delete obj.x"))->Run();
1208
1209  // Enumerators.
1210  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1211}
1212
1213
1214static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1215                                               const AccessorInfo& info) {
1216  ApiTestFuzzer::Fuzz();
1217  if (v8_str("pre")->Equals(key)) {
1218    return v8_str("PrePropertyHandler: pre");
1219  }
1220  return v8::Handle<String>();
1221}
1222
1223
1224static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1225                                                     const AccessorInfo&) {
1226  if (v8_str("pre")->Equals(key)) {
1227    return v8::True();
1228  }
1229
1230  return v8::Handle<v8::Boolean>();  // do not intercept the call
1231}
1232
1233
1234THREADED_TEST(PrePropertyHandler) {
1235  v8::HandleScope scope;
1236  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1237  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1238                                                    0,
1239                                                    PrePropertyHandlerHas);
1240  LocalContext env(NULL, desc->InstanceTemplate());
1241  Script::Compile(v8_str(
1242      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1243  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1244  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1245  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1246  CHECK_EQ(v8_str("Object: on"), result_on);
1247  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1248  CHECK(result_post.IsEmpty());
1249}
1250
1251
1252THREADED_TEST(UndefinedIsNotEnumerable) {
1253  v8::HandleScope scope;
1254  LocalContext env;
1255  v8::Handle<Value> result = Script::Compile(v8_str(
1256      "this.propertyIsEnumerable(undefined)"))->Run();
1257  CHECK(result->IsFalse());
1258}
1259
1260
1261v8::Handle<Script> call_recursively_script;
1262static const int kTargetRecursionDepth = 200;  // near maximum
1263
1264
1265static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1266  ApiTestFuzzer::Fuzz();
1267  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1268  if (depth == kTargetRecursionDepth) return v8::Undefined();
1269  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1270  return call_recursively_script->Run();
1271}
1272
1273
1274static v8::Handle<Value> CallFunctionRecursivelyCall(
1275    const v8::Arguments& args) {
1276  ApiTestFuzzer::Fuzz();
1277  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1278  if (depth == kTargetRecursionDepth) {
1279    printf("[depth = %d]\n", depth);
1280    return v8::Undefined();
1281  }
1282  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1283  v8::Handle<Value> function =
1284      args.This()->Get(v8_str("callFunctionRecursively"));
1285  return function.As<Function>()->Call(args.This(), 0, NULL);
1286}
1287
1288
1289THREADED_TEST(DeepCrossLanguageRecursion) {
1290  v8::HandleScope scope;
1291  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1292  global->Set(v8_str("callScriptRecursively"),
1293              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1294  global->Set(v8_str("callFunctionRecursively"),
1295              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1296  LocalContext env(NULL, global);
1297
1298  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1299  call_recursively_script = v8_compile("callScriptRecursively()");
1300  v8::Handle<Value> result = call_recursively_script->Run();
1301  call_recursively_script = v8::Handle<Script>();
1302
1303  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1304  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1305}
1306
1307
1308static v8::Handle<Value>
1309    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1310  ApiTestFuzzer::Fuzz();
1311  return v8::ThrowException(key);
1312}
1313
1314
1315static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1316                                                    Local<Value>,
1317                                                    const AccessorInfo&) {
1318  v8::ThrowException(key);
1319  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1320}
1321
1322
1323THREADED_TEST(CallbackExceptionRegression) {
1324  v8::HandleScope scope;
1325  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1326  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1327                               ThrowingPropertyHandlerSet);
1328  LocalContext env;
1329  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1330  v8::Handle<Value> otto = Script::Compile(v8_str(
1331      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1332  CHECK_EQ(v8_str("otto"), otto);
1333  v8::Handle<Value> netto = Script::Compile(v8_str(
1334      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1335  CHECK_EQ(v8_str("netto"), netto);
1336}
1337
1338
1339THREADED_TEST(FunctionPrototype) {
1340  v8::HandleScope scope;
1341  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1342  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1343  LocalContext env;
1344  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1345  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1346  CHECK_EQ(script->Run()->Int32Value(), 321);
1347}
1348
1349
1350THREADED_TEST(InternalFields) {
1351  v8::HandleScope scope;
1352  LocalContext env;
1353
1354  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1355  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1356  instance_templ->SetInternalFieldCount(1);
1357  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1358  CHECK_EQ(1, obj->InternalFieldCount());
1359  CHECK(obj->GetInternalField(0)->IsUndefined());
1360  obj->SetInternalField(0, v8_num(17));
1361  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1362}
1363
1364
1365THREADED_TEST(GlobalObjectInternalFields) {
1366  v8::HandleScope scope;
1367  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1368  global_template->SetInternalFieldCount(1);
1369  LocalContext env(NULL, global_template);
1370  v8::Handle<v8::Object> global_proxy = env->Global();
1371  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1372  CHECK_EQ(1, global->InternalFieldCount());
1373  CHECK(global->GetInternalField(0)->IsUndefined());
1374  global->SetInternalField(0, v8_num(17));
1375  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1376}
1377
1378
1379THREADED_TEST(InternalFieldsNativePointers) {
1380  v8::HandleScope scope;
1381  LocalContext env;
1382
1383  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1384  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1385  instance_templ->SetInternalFieldCount(1);
1386  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1387  CHECK_EQ(1, obj->InternalFieldCount());
1388  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1389
1390  char* data = new char[100];
1391
1392  void* aligned = data;
1393  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1394  void* unaligned = data + 1;
1395  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1396
1397  // Check reading and writing aligned pointers.
1398  obj->SetPointerInInternalField(0, aligned);
1399  i::Heap::CollectAllGarbage(false);
1400  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1401
1402  // Check reading and writing unaligned pointers.
1403  obj->SetPointerInInternalField(0, unaligned);
1404  i::Heap::CollectAllGarbage(false);
1405  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1406
1407  delete[] data;
1408}
1409
1410
1411THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1412  v8::HandleScope scope;
1413  LocalContext env;
1414
1415  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1416  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1417  instance_templ->SetInternalFieldCount(1);
1418  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1419  CHECK_EQ(1, obj->InternalFieldCount());
1420  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1421
1422  char* data = new char[100];
1423
1424  void* aligned = data;
1425  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1426  void* unaligned = data + 1;
1427  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1428
1429  obj->SetPointerInInternalField(0, aligned);
1430  i::Heap::CollectAllGarbage(false);
1431  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1432
1433  obj->SetPointerInInternalField(0, unaligned);
1434  i::Heap::CollectAllGarbage(false);
1435  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1436
1437  obj->SetInternalField(0, v8::External::Wrap(aligned));
1438  i::Heap::CollectAllGarbage(false);
1439  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1440
1441  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1442  i::Heap::CollectAllGarbage(false);
1443  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1444
1445  delete[] data;
1446}
1447
1448
1449THREADED_TEST(IdentityHash) {
1450  v8::HandleScope scope;
1451  LocalContext env;
1452
1453  // Ensure that the test starts with an fresh heap to test whether the hash
1454  // code is based on the address.
1455  i::Heap::CollectAllGarbage(false);
1456  Local<v8::Object> obj = v8::Object::New();
1457  int hash = obj->GetIdentityHash();
1458  int hash1 = obj->GetIdentityHash();
1459  CHECK_EQ(hash, hash1);
1460  int hash2 = v8::Object::New()->GetIdentityHash();
1461  // Since the identity hash is essentially a random number two consecutive
1462  // objects should not be assigned the same hash code. If the test below fails
1463  // the random number generator should be evaluated.
1464  CHECK_NE(hash, hash2);
1465  i::Heap::CollectAllGarbage(false);
1466  int hash3 = v8::Object::New()->GetIdentityHash();
1467  // Make sure that the identity hash is not based on the initial address of
1468  // the object alone. If the test below fails the random number generator
1469  // should be evaluated.
1470  CHECK_NE(hash, hash3);
1471  int hash4 = obj->GetIdentityHash();
1472  CHECK_EQ(hash, hash4);
1473}
1474
1475
1476THREADED_TEST(HiddenProperties) {
1477  v8::HandleScope scope;
1478  LocalContext env;
1479
1480  v8::Local<v8::Object> obj = v8::Object::New();
1481  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1482  v8::Local<v8::String> empty = v8_str("");
1483  v8::Local<v8::String> prop_name = v8_str("prop_name");
1484
1485  i::Heap::CollectAllGarbage(false);
1486
1487  // Make sure delete of a non-existent hidden value works
1488  CHECK(obj->DeleteHiddenValue(key));
1489
1490  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1491  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1492  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1493  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1494
1495  i::Heap::CollectAllGarbage(false);
1496
1497  // Make sure we do not find the hidden property.
1498  CHECK(!obj->Has(empty));
1499  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1500  CHECK(obj->Get(empty)->IsUndefined());
1501  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1502  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1503  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1504  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1505
1506  i::Heap::CollectAllGarbage(false);
1507
1508  // Add another property and delete it afterwards to force the object in
1509  // slow case.
1510  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1511  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1512  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1513  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1514  CHECK(obj->Delete(prop_name));
1515  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1516
1517  i::Heap::CollectAllGarbage(false);
1518
1519  CHECK(obj->DeleteHiddenValue(key));
1520  CHECK(obj->GetHiddenValue(key).IsEmpty());
1521}
1522
1523
1524static bool interceptor_for_hidden_properties_called;
1525static v8::Handle<Value> InterceptorForHiddenProperties(
1526    Local<String> name, const AccessorInfo& info) {
1527  interceptor_for_hidden_properties_called = true;
1528  return v8::Handle<Value>();
1529}
1530
1531
1532THREADED_TEST(HiddenPropertiesWithInterceptors) {
1533  v8::HandleScope scope;
1534  LocalContext context;
1535
1536  interceptor_for_hidden_properties_called = false;
1537
1538  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1539
1540  // Associate an interceptor with an object and start setting hidden values.
1541  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1542  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1543  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1544  Local<v8::Function> function = fun_templ->GetFunction();
1545  Local<v8::Object> obj = function->NewInstance();
1546  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1547  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1548  CHECK(!interceptor_for_hidden_properties_called);
1549}
1550
1551
1552THREADED_TEST(External) {
1553  v8::HandleScope scope;
1554  int x = 3;
1555  Local<v8::External> ext = v8::External::New(&x);
1556  LocalContext env;
1557  env->Global()->Set(v8_str("ext"), ext);
1558  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1559  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1560  int* ptr = static_cast<int*>(reext->Value());
1561  CHECK_EQ(x, 3);
1562  *ptr = 10;
1563  CHECK_EQ(x, 10);
1564
1565  // Make sure unaligned pointers are wrapped properly.
1566  char* data = i::StrDup("0123456789");
1567  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1568  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1569  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1570  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1571
1572  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1573  CHECK_EQ('0', *char_ptr);
1574  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1575  CHECK_EQ('1', *char_ptr);
1576  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1577  CHECK_EQ('2', *char_ptr);
1578  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1579  CHECK_EQ('3', *char_ptr);
1580  i::DeleteArray(data);
1581}
1582
1583
1584THREADED_TEST(GlobalHandle) {
1585  v8::Persistent<String> global;
1586  {
1587    v8::HandleScope scope;
1588    Local<String> str = v8_str("str");
1589    global = v8::Persistent<String>::New(str);
1590  }
1591  CHECK_EQ(global->Length(), 3);
1592  global.Dispose();
1593}
1594
1595
1596THREADED_TEST(ScriptException) {
1597  v8::HandleScope scope;
1598  LocalContext env;
1599  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1600  v8::TryCatch try_catch;
1601  Local<Value> result = script->Run();
1602  CHECK(result.IsEmpty());
1603  CHECK(try_catch.HasCaught());
1604  String::AsciiValue exception_value(try_catch.Exception());
1605  CHECK_EQ(*exception_value, "panama!");
1606}
1607
1608
1609bool message_received;
1610
1611
1612static void check_message(v8::Handle<v8::Message> message,
1613                          v8::Handle<Value> data) {
1614  CHECK_EQ(5.76, data->NumberValue());
1615  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1616  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1617  message_received = true;
1618}
1619
1620
1621THREADED_TEST(MessageHandlerData) {
1622  message_received = false;
1623  v8::HandleScope scope;
1624  CHECK(!message_received);
1625  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1626  LocalContext context;
1627  v8::ScriptOrigin origin =
1628      v8::ScriptOrigin(v8_str("6.75"));
1629  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1630                                                  &origin);
1631  script->SetData(v8_str("7.56"));
1632  script->Run();
1633  CHECK(message_received);
1634  // clear out the message listener
1635  v8::V8::RemoveMessageListeners(check_message);
1636}
1637
1638
1639THREADED_TEST(GetSetProperty) {
1640  v8::HandleScope scope;
1641  LocalContext context;
1642  context->Global()->Set(v8_str("foo"), v8_num(14));
1643  context->Global()->Set(v8_str("12"), v8_num(92));
1644  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1645  context->Global()->Set(v8_num(13), v8_num(56));
1646  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1647  CHECK_EQ(14, foo->Int32Value());
1648  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1649  CHECK_EQ(92, twelve->Int32Value());
1650  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1651  CHECK_EQ(32, sixteen->Int32Value());
1652  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1653  CHECK_EQ(56, thirteen->Int32Value());
1654  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1655  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1656  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1657  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1658  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1659  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1660  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1661  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1662  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1663}
1664
1665
1666THREADED_TEST(PropertyAttributes) {
1667  v8::HandleScope scope;
1668  LocalContext context;
1669  // read-only
1670  Local<String> prop = v8_str("read_only");
1671  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1672  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1673  Script::Compile(v8_str("read_only = 9"))->Run();
1674  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1675  context->Global()->Set(prop, v8_num(10));
1676  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1677  // dont-delete
1678  prop = v8_str("dont_delete");
1679  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1680  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1681  Script::Compile(v8_str("delete dont_delete"))->Run();
1682  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1683}
1684
1685
1686THREADED_TEST(Array) {
1687  v8::HandleScope scope;
1688  LocalContext context;
1689  Local<v8::Array> array = v8::Array::New();
1690  CHECK_EQ(0, array->Length());
1691  CHECK(array->Get(0)->IsUndefined());
1692  CHECK(!array->Has(0));
1693  CHECK(array->Get(100)->IsUndefined());
1694  CHECK(!array->Has(100));
1695  array->Set(2, v8_num(7));
1696  CHECK_EQ(3, array->Length());
1697  CHECK(!array->Has(0));
1698  CHECK(!array->Has(1));
1699  CHECK(array->Has(2));
1700  CHECK_EQ(7, array->Get(2)->Int32Value());
1701  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1702  Local<v8::Array> arr = obj.As<v8::Array>();
1703  CHECK_EQ(3, arr->Length());
1704  CHECK_EQ(1, arr->Get(0)->Int32Value());
1705  CHECK_EQ(2, arr->Get(1)->Int32Value());
1706  CHECK_EQ(3, arr->Get(2)->Int32Value());
1707}
1708
1709
1710v8::Handle<Value> HandleF(const v8::Arguments& args) {
1711  v8::HandleScope scope;
1712  ApiTestFuzzer::Fuzz();
1713  Local<v8::Array> result = v8::Array::New(args.Length());
1714  for (int i = 0; i < args.Length(); i++)
1715    result->Set(i, args[i]);
1716  return scope.Close(result);
1717}
1718
1719
1720THREADED_TEST(Vector) {
1721  v8::HandleScope scope;
1722  Local<ObjectTemplate> global = ObjectTemplate::New();
1723  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1724  LocalContext context(0, global);
1725
1726  const char* fun = "f()";
1727  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1728  CHECK_EQ(0, a0->Length());
1729
1730  const char* fun2 = "f(11)";
1731  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1732  CHECK_EQ(1, a1->Length());
1733  CHECK_EQ(11, a1->Get(0)->Int32Value());
1734
1735  const char* fun3 = "f(12, 13)";
1736  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1737  CHECK_EQ(2, a2->Length());
1738  CHECK_EQ(12, a2->Get(0)->Int32Value());
1739  CHECK_EQ(13, a2->Get(1)->Int32Value());
1740
1741  const char* fun4 = "f(14, 15, 16)";
1742  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1743  CHECK_EQ(3, a3->Length());
1744  CHECK_EQ(14, a3->Get(0)->Int32Value());
1745  CHECK_EQ(15, a3->Get(1)->Int32Value());
1746  CHECK_EQ(16, a3->Get(2)->Int32Value());
1747
1748  const char* fun5 = "f(17, 18, 19, 20)";
1749  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1750  CHECK_EQ(4, a4->Length());
1751  CHECK_EQ(17, a4->Get(0)->Int32Value());
1752  CHECK_EQ(18, a4->Get(1)->Int32Value());
1753  CHECK_EQ(19, a4->Get(2)->Int32Value());
1754  CHECK_EQ(20, a4->Get(3)->Int32Value());
1755}
1756
1757
1758THREADED_TEST(FunctionCall) {
1759  v8::HandleScope scope;
1760  LocalContext context;
1761  CompileRun(
1762    "function Foo() {"
1763    "  var result = [];"
1764    "  for (var i = 0; i < arguments.length; i++) {"
1765    "    result.push(arguments[i]);"
1766    "  }"
1767    "  return result;"
1768    "}");
1769  Local<Function> Foo =
1770      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1771
1772  v8::Handle<Value>* args0 = NULL;
1773  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1774  CHECK_EQ(0, a0->Length());
1775
1776  v8::Handle<Value> args1[] = { v8_num(1.1) };
1777  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1778  CHECK_EQ(1, a1->Length());
1779  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1780
1781  v8::Handle<Value> args2[] = { v8_num(2.2),
1782                                v8_num(3.3) };
1783  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1784  CHECK_EQ(2, a2->Length());
1785  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1786  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1787
1788  v8::Handle<Value> args3[] = { v8_num(4.4),
1789                                v8_num(5.5),
1790                                v8_num(6.6) };
1791  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1792  CHECK_EQ(3, a3->Length());
1793  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1794  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1795  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1796
1797  v8::Handle<Value> args4[] = { v8_num(7.7),
1798                                v8_num(8.8),
1799                                v8_num(9.9),
1800                                v8_num(10.11) };
1801  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1802  CHECK_EQ(4, a4->Length());
1803  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1804  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1805  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1806  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1807}
1808
1809
1810static const char* js_code_causing_out_of_memory =
1811    "var a = new Array(); while(true) a.push(a);";
1812
1813
1814// These tests run for a long time and prevent us from running tests
1815// that come after them so they cannot run in parallel.
1816TEST(OutOfMemory) {
1817  // It's not possible to read a snapshot into a heap with different dimensions.
1818  if (v8::internal::Snapshot::IsEnabled()) return;
1819  // Set heap limits.
1820  static const int K = 1024;
1821  v8::ResourceConstraints constraints;
1822  constraints.set_max_young_space_size(256 * K);
1823  constraints.set_max_old_space_size(4 * K * K);
1824  v8::SetResourceConstraints(&constraints);
1825
1826  // Execute a script that causes out of memory.
1827  v8::HandleScope scope;
1828  LocalContext context;
1829  v8::V8::IgnoreOutOfMemoryException();
1830  Local<Script> script =
1831      Script::Compile(String::New(js_code_causing_out_of_memory));
1832  Local<Value> result = script->Run();
1833
1834  // Check for out of memory state.
1835  CHECK(result.IsEmpty());
1836  CHECK(context->HasOutOfMemoryException());
1837}
1838
1839
1840v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1841  ApiTestFuzzer::Fuzz();
1842
1843  v8::HandleScope scope;
1844  LocalContext context;
1845  Local<Script> script =
1846      Script::Compile(String::New(js_code_causing_out_of_memory));
1847  Local<Value> result = script->Run();
1848
1849  // Check for out of memory state.
1850  CHECK(result.IsEmpty());
1851  CHECK(context->HasOutOfMemoryException());
1852
1853  return result;
1854}
1855
1856
1857TEST(OutOfMemoryNested) {
1858  // It's not possible to read a snapshot into a heap with different dimensions.
1859  if (v8::internal::Snapshot::IsEnabled()) return;
1860  // Set heap limits.
1861  static const int K = 1024;
1862  v8::ResourceConstraints constraints;
1863  constraints.set_max_young_space_size(256 * K);
1864  constraints.set_max_old_space_size(4 * K * K);
1865  v8::SetResourceConstraints(&constraints);
1866
1867  v8::HandleScope scope;
1868  Local<ObjectTemplate> templ = ObjectTemplate::New();
1869  templ->Set(v8_str("ProvokeOutOfMemory"),
1870             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1871  LocalContext context(0, templ);
1872  v8::V8::IgnoreOutOfMemoryException();
1873  Local<Value> result = CompileRun(
1874    "var thrown = false;"
1875    "try {"
1876    "  ProvokeOutOfMemory();"
1877    "} catch (e) {"
1878    "  thrown = true;"
1879    "}");
1880  // Check for out of memory state.
1881  CHECK(result.IsEmpty());
1882  CHECK(context->HasOutOfMemoryException());
1883}
1884
1885
1886TEST(HugeConsStringOutOfMemory) {
1887  // It's not possible to read a snapshot into a heap with different dimensions.
1888  if (v8::internal::Snapshot::IsEnabled()) return;
1889  v8::HandleScope scope;
1890  LocalContext context;
1891  // Set heap limits.
1892  static const int K = 1024;
1893  v8::ResourceConstraints constraints;
1894  constraints.set_max_young_space_size(256 * K);
1895  constraints.set_max_old_space_size(2 * K * K);
1896  v8::SetResourceConstraints(&constraints);
1897
1898  // Execute a script that causes out of memory.
1899  v8::V8::IgnoreOutOfMemoryException();
1900
1901  // Build huge string. This should fail with out of memory exception.
1902  Local<Value> result = CompileRun(
1903    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1904    "for (var i = 0; i < 22; i++) { str = str + str; }");
1905
1906  // Check for out of memory state.
1907  CHECK(result.IsEmpty());
1908  CHECK(context->HasOutOfMemoryException());
1909}
1910
1911
1912THREADED_TEST(ConstructCall) {
1913  v8::HandleScope scope;
1914  LocalContext context;
1915  CompileRun(
1916    "function Foo() {"
1917    "  var result = [];"
1918    "  for (var i = 0; i < arguments.length; i++) {"
1919    "    result.push(arguments[i]);"
1920    "  }"
1921    "  return result;"
1922    "}");
1923  Local<Function> Foo =
1924      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1925
1926  v8::Handle<Value>* args0 = NULL;
1927  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1928  CHECK_EQ(0, a0->Length());
1929
1930  v8::Handle<Value> args1[] = { v8_num(1.1) };
1931  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1932  CHECK_EQ(1, a1->Length());
1933  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1934
1935  v8::Handle<Value> args2[] = { v8_num(2.2),
1936                                v8_num(3.3) };
1937  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1938  CHECK_EQ(2, a2->Length());
1939  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1940  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1941
1942  v8::Handle<Value> args3[] = { v8_num(4.4),
1943                                v8_num(5.5),
1944                                v8_num(6.6) };
1945  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1946  CHECK_EQ(3, a3->Length());
1947  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1948  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1949  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1950
1951  v8::Handle<Value> args4[] = { v8_num(7.7),
1952                                v8_num(8.8),
1953                                v8_num(9.9),
1954                                v8_num(10.11) };
1955  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1956  CHECK_EQ(4, a4->Length());
1957  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1958  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1959  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1960  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1961}
1962
1963
1964static void CheckUncle(v8::TryCatch* try_catch) {
1965  CHECK(try_catch->HasCaught());
1966  String::AsciiValue str_value(try_catch->Exception());
1967  CHECK_EQ(*str_value, "uncle?");
1968  try_catch->Reset();
1969}
1970
1971
1972THREADED_TEST(ConversionNumber) {
1973  v8::HandleScope scope;
1974  LocalContext env;
1975  // Very large number.
1976  CompileRun("var obj = Math.pow(2,32) * 1237;");
1977  Local<Value> obj = env->Global()->Get(v8_str("obj"));
1978  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
1979  CHECK_EQ(0, obj->ToInt32()->Value());
1980  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
1981  // Large number.
1982  CompileRun("var obj = -1234567890123;");
1983  obj = env->Global()->Get(v8_str("obj"));
1984  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
1985  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
1986  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
1987  // Small positive integer.
1988  CompileRun("var obj = 42;");
1989  obj = env->Global()->Get(v8_str("obj"));
1990  CHECK_EQ(42.0, obj->ToNumber()->Value());
1991  CHECK_EQ(42, obj->ToInt32()->Value());
1992  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
1993  // Negative integer.
1994  CompileRun("var obj = -37;");
1995  obj = env->Global()->Get(v8_str("obj"));
1996  CHECK_EQ(-37.0, obj->ToNumber()->Value());
1997  CHECK_EQ(-37, obj->ToInt32()->Value());
1998  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
1999  // Positive non-int32 integer.
2000  CompileRun("var obj = 0x81234567;");
2001  obj = env->Global()->Get(v8_str("obj"));
2002  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2003  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2004  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2005  // Fraction.
2006  CompileRun("var obj = 42.3;");
2007  obj = env->Global()->Get(v8_str("obj"));
2008  CHECK_EQ(42.3, obj->ToNumber()->Value());
2009  CHECK_EQ(42, obj->ToInt32()->Value());
2010  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2011  // Large negative fraction.
2012  CompileRun("var obj = -5726623061.75;");
2013  obj = env->Global()->Get(v8_str("obj"));
2014  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2015  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2016  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2017}
2018
2019
2020THREADED_TEST(isNumberType) {
2021  v8::HandleScope scope;
2022  LocalContext env;
2023  // Very large number.
2024  CompileRun("var obj = Math.pow(2,32) * 1237;");
2025  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2026  CHECK(!obj->IsInt32());
2027  CHECK(!obj->IsUint32());
2028  // Large negative number.
2029  CompileRun("var obj = -1234567890123;");
2030  obj = env->Global()->Get(v8_str("obj"));
2031  CHECK(!obj->IsInt32());
2032  CHECK(!obj->IsUint32());
2033  // Small positive integer.
2034  CompileRun("var obj = 42;");
2035  obj = env->Global()->Get(v8_str("obj"));
2036  CHECK(obj->IsInt32());
2037  CHECK(obj->IsUint32());
2038  // Negative integer.
2039  CompileRun("var obj = -37;");
2040  obj = env->Global()->Get(v8_str("obj"));
2041  CHECK(obj->IsInt32());
2042  CHECK(!obj->IsUint32());
2043  // Positive non-int32 integer.
2044  CompileRun("var obj = 0x81234567;");
2045  obj = env->Global()->Get(v8_str("obj"));
2046  CHECK(!obj->IsInt32());
2047  CHECK(obj->IsUint32());
2048  // Fraction.
2049  CompileRun("var obj = 42.3;");
2050  obj = env->Global()->Get(v8_str("obj"));
2051  CHECK(!obj->IsInt32());
2052  CHECK(!obj->IsUint32());
2053  // Large negative fraction.
2054  CompileRun("var obj = -5726623061.75;");
2055  obj = env->Global()->Get(v8_str("obj"));
2056  CHECK(!obj->IsInt32());
2057  CHECK(!obj->IsUint32());
2058}
2059
2060
2061THREADED_TEST(ConversionException) {
2062  v8::HandleScope scope;
2063  LocalContext env;
2064  CompileRun(
2065    "function TestClass() { };"
2066    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2067    "var obj = new TestClass();");
2068  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2069
2070  v8::TryCatch try_catch;
2071
2072  Local<Value> to_string_result = obj->ToString();
2073  CHECK(to_string_result.IsEmpty());
2074  CheckUncle(&try_catch);
2075
2076  Local<Value> to_number_result = obj->ToNumber();
2077  CHECK(to_number_result.IsEmpty());
2078  CheckUncle(&try_catch);
2079
2080  Local<Value> to_integer_result = obj->ToInteger();
2081  CHECK(to_integer_result.IsEmpty());
2082  CheckUncle(&try_catch);
2083
2084  Local<Value> to_uint32_result = obj->ToUint32();
2085  CHECK(to_uint32_result.IsEmpty());
2086  CheckUncle(&try_catch);
2087
2088  Local<Value> to_int32_result = obj->ToInt32();
2089  CHECK(to_int32_result.IsEmpty());
2090  CheckUncle(&try_catch);
2091
2092  Local<Value> to_object_result = v8::Undefined()->ToObject();
2093  CHECK(to_object_result.IsEmpty());
2094  CHECK(try_catch.HasCaught());
2095  try_catch.Reset();
2096
2097  int32_t int32_value = obj->Int32Value();
2098  CHECK_EQ(0, int32_value);
2099  CheckUncle(&try_catch);
2100
2101  uint32_t uint32_value = obj->Uint32Value();
2102  CHECK_EQ(0, uint32_value);
2103  CheckUncle(&try_catch);
2104
2105  double number_value = obj->NumberValue();
2106  CHECK_NE(0, IsNaN(number_value));
2107  CheckUncle(&try_catch);
2108
2109  int64_t integer_value = obj->IntegerValue();
2110  CHECK_EQ(0.0, static_cast<double>(integer_value));
2111  CheckUncle(&try_catch);
2112}
2113
2114
2115v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2116  ApiTestFuzzer::Fuzz();
2117  return v8::ThrowException(v8_str("konto"));
2118}
2119
2120
2121v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2122  if (args.Length() < 1) return v8::Boolean::New(false);
2123  v8::HandleScope scope;
2124  v8::TryCatch try_catch;
2125  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2126  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2127  return v8::Boolean::New(try_catch.HasCaught());
2128}
2129
2130
2131THREADED_TEST(APICatch) {
2132  v8::HandleScope scope;
2133  Local<ObjectTemplate> templ = ObjectTemplate::New();
2134  templ->Set(v8_str("ThrowFromC"),
2135             v8::FunctionTemplate::New(ThrowFromC));
2136  LocalContext context(0, templ);
2137  CompileRun(
2138    "var thrown = false;"
2139    "try {"
2140    "  ThrowFromC();"
2141    "} catch (e) {"
2142    "  thrown = true;"
2143    "}");
2144  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2145  CHECK(thrown->BooleanValue());
2146}
2147
2148
2149THREADED_TEST(APIThrowTryCatch) {
2150  v8::HandleScope scope;
2151  Local<ObjectTemplate> templ = ObjectTemplate::New();
2152  templ->Set(v8_str("ThrowFromC"),
2153             v8::FunctionTemplate::New(ThrowFromC));
2154  LocalContext context(0, templ);
2155  v8::TryCatch try_catch;
2156  CompileRun("ThrowFromC();");
2157  CHECK(try_catch.HasCaught());
2158}
2159
2160
2161// Test that a try-finally block doesn't shadow a try-catch block
2162// when setting up an external handler.
2163//
2164// BUG(271): Some of the exception propagation does not work on the
2165// ARM simulator because the simulator separates the C++ stack and the
2166// JS stack.  This test therefore fails on the simulator.  The test is
2167// not threaded to allow the threading tests to run on the simulator.
2168TEST(TryCatchInTryFinally) {
2169  v8::HandleScope scope;
2170  Local<ObjectTemplate> templ = ObjectTemplate::New();
2171  templ->Set(v8_str("CCatcher"),
2172             v8::FunctionTemplate::New(CCatcher));
2173  LocalContext context(0, templ);
2174  Local<Value> result = CompileRun("try {"
2175                                   "  try {"
2176                                   "    CCatcher('throw 7;');"
2177                                   "  } finally {"
2178                                   "  }"
2179                                   "} catch (e) {"
2180                                   "}");
2181  CHECK(result->IsTrue());
2182}
2183
2184
2185static void receive_message(v8::Handle<v8::Message> message,
2186                            v8::Handle<v8::Value> data) {
2187  message->Get();
2188  message_received = true;
2189}
2190
2191
2192TEST(APIThrowMessage) {
2193  message_received = false;
2194  v8::HandleScope scope;
2195  v8::V8::AddMessageListener(receive_message);
2196  Local<ObjectTemplate> templ = ObjectTemplate::New();
2197  templ->Set(v8_str("ThrowFromC"),
2198             v8::FunctionTemplate::New(ThrowFromC));
2199  LocalContext context(0, templ);
2200  CompileRun("ThrowFromC();");
2201  CHECK(message_received);
2202  v8::V8::RemoveMessageListeners(check_message);
2203}
2204
2205
2206TEST(APIThrowMessageAndVerboseTryCatch) {
2207  message_received = false;
2208  v8::HandleScope scope;
2209  v8::V8::AddMessageListener(receive_message);
2210  Local<ObjectTemplate> templ = ObjectTemplate::New();
2211  templ->Set(v8_str("ThrowFromC"),
2212             v8::FunctionTemplate::New(ThrowFromC));
2213  LocalContext context(0, templ);
2214  v8::TryCatch try_catch;
2215  try_catch.SetVerbose(true);
2216  Local<Value> result = CompileRun("ThrowFromC();");
2217  CHECK(try_catch.HasCaught());
2218  CHECK(result.IsEmpty());
2219  CHECK(message_received);
2220  v8::V8::RemoveMessageListeners(check_message);
2221}
2222
2223
2224THREADED_TEST(ExternalScriptException) {
2225  v8::HandleScope scope;
2226  Local<ObjectTemplate> templ = ObjectTemplate::New();
2227  templ->Set(v8_str("ThrowFromC"),
2228             v8::FunctionTemplate::New(ThrowFromC));
2229  LocalContext context(0, templ);
2230
2231  v8::TryCatch try_catch;
2232  Local<Script> script
2233      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2234  Local<Value> result = script->Run();
2235  CHECK(result.IsEmpty());
2236  CHECK(try_catch.HasCaught());
2237  String::AsciiValue exception_value(try_catch.Exception());
2238  CHECK_EQ("konto", *exception_value);
2239}
2240
2241
2242
2243v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2244  ApiTestFuzzer::Fuzz();
2245  CHECK_EQ(4, args.Length());
2246  int count = args[0]->Int32Value();
2247  int cInterval = args[2]->Int32Value();
2248  if (count == 0) {
2249    return v8::ThrowException(v8_str("FromC"));
2250  } else {
2251    Local<v8::Object> global = Context::GetCurrent()->Global();
2252    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2253    v8::Handle<Value> argv[] = { v8_num(count - 1),
2254                                 args[1],
2255                                 args[2],
2256                                 args[3] };
2257    if (count % cInterval == 0) {
2258      v8::TryCatch try_catch;
2259      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2260      int expected = args[3]->Int32Value();
2261      if (try_catch.HasCaught()) {
2262        CHECK_EQ(expected, count);
2263        CHECK(result.IsEmpty());
2264        CHECK(!i::Top::has_scheduled_exception());
2265      } else {
2266        CHECK_NE(expected, count);
2267      }
2268      return result;
2269    } else {
2270      return fun.As<Function>()->Call(global, 4, argv);
2271    }
2272  }
2273}
2274
2275
2276v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2277  ApiTestFuzzer::Fuzz();
2278  CHECK_EQ(3, args.Length());
2279  bool equality = args[0]->BooleanValue();
2280  int count = args[1]->Int32Value();
2281  int expected = args[2]->Int32Value();
2282  if (equality) {
2283    CHECK_EQ(count, expected);
2284  } else {
2285    CHECK_NE(count, expected);
2286  }
2287  return v8::Undefined();
2288}
2289
2290
2291THREADED_TEST(EvalInTryFinally) {
2292  v8::HandleScope scope;
2293  LocalContext context;
2294  v8::TryCatch try_catch;
2295  CompileRun("(function() {"
2296             "  try {"
2297             "    eval('asldkf (*&^&*^');"
2298             "  } finally {"
2299             "    return;"
2300             "  }"
2301             "})()");
2302  CHECK(!try_catch.HasCaught());
2303}
2304
2305
2306// This test works by making a stack of alternating JavaScript and C
2307// activations.  These activations set up exception handlers with regular
2308// intervals, one interval for C activations and another for JavaScript
2309// activations.  When enough activations have been created an exception is
2310// thrown and we check that the right activation catches the exception and that
2311// no other activations do.  The right activation is always the topmost one with
2312// a handler, regardless of whether it is in JavaScript or C.
2313//
2314// The notation used to describe a test case looks like this:
2315//
2316//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2317//
2318// Each entry is an activation, either JS or C.  The index is the count at that
2319// level.  Stars identify activations with exception handlers, the @ identifies
2320// the exception handler that should catch the exception.
2321//
2322// BUG(271): Some of the exception propagation does not work on the
2323// ARM simulator because the simulator separates the C++ stack and the
2324// JS stack.  This test therefore fails on the simulator.  The test is
2325// not threaded to allow the threading tests to run on the simulator.
2326TEST(ExceptionOrder) {
2327  v8::HandleScope scope;
2328  Local<ObjectTemplate> templ = ObjectTemplate::New();
2329  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2330  templ->Set(v8_str("CThrowCountDown"),
2331             v8::FunctionTemplate::New(CThrowCountDown));
2332  LocalContext context(0, templ);
2333  CompileRun(
2334    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2335    "  if (count == 0) throw 'FromJS';"
2336    "  if (count % jsInterval == 0) {"
2337    "    try {"
2338    "      var value = CThrowCountDown(count - 1,"
2339    "                                  jsInterval,"
2340    "                                  cInterval,"
2341    "                                  expected);"
2342    "      check(false, count, expected);"
2343    "      return value;"
2344    "    } catch (e) {"
2345    "      check(true, count, expected);"
2346    "    }"
2347    "  } else {"
2348    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2349    "  }"
2350    "}");
2351  Local<Function> fun =
2352      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2353
2354  const int argc = 4;
2355  //                             count      jsInterval cInterval  expected
2356
2357  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2358  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2359  fun->Call(fun, argc, a0);
2360
2361  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2362  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2363  fun->Call(fun, argc, a1);
2364
2365  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2366  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2367  fun->Call(fun, argc, a2);
2368
2369  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2370  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2371  fun->Call(fun, argc, a3);
2372
2373  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2374  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2375  fun->Call(fun, argc, a4);
2376
2377  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2378  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2379  fun->Call(fun, argc, a5);
2380}
2381
2382
2383v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2384  ApiTestFuzzer::Fuzz();
2385  CHECK_EQ(1, args.Length());
2386  return v8::ThrowException(args[0]);
2387}
2388
2389
2390THREADED_TEST(ThrowValues) {
2391  v8::HandleScope scope;
2392  Local<ObjectTemplate> templ = ObjectTemplate::New();
2393  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2394  LocalContext context(0, templ);
2395  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2396    "function Run(obj) {"
2397    "  try {"
2398    "    Throw(obj);"
2399    "  } catch (e) {"
2400    "    return e;"
2401    "  }"
2402    "  return 'no exception';"
2403    "}"
2404    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2405  CHECK_EQ(5, result->Length());
2406  CHECK(result->Get(v8::Integer::New(0))->IsString());
2407  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2408  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2409  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2410  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2411  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2412  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2413}
2414
2415
2416THREADED_TEST(CatchZero) {
2417  v8::HandleScope scope;
2418  LocalContext context;
2419  v8::TryCatch try_catch;
2420  CHECK(!try_catch.HasCaught());
2421  Script::Compile(v8_str("throw 10"))->Run();
2422  CHECK(try_catch.HasCaught());
2423  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2424  try_catch.Reset();
2425  CHECK(!try_catch.HasCaught());
2426  Script::Compile(v8_str("throw 0"))->Run();
2427  CHECK(try_catch.HasCaught());
2428  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2429}
2430
2431
2432THREADED_TEST(CatchExceptionFromWith) {
2433  v8::HandleScope scope;
2434  LocalContext context;
2435  v8::TryCatch try_catch;
2436  CHECK(!try_catch.HasCaught());
2437  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2438  CHECK(try_catch.HasCaught());
2439}
2440
2441
2442THREADED_TEST(Equality) {
2443  v8::HandleScope scope;
2444  LocalContext context;
2445  // Check that equality works at all before relying on CHECK_EQ
2446  CHECK(v8_str("a")->Equals(v8_str("a")));
2447  CHECK(!v8_str("a")->Equals(v8_str("b")));
2448
2449  CHECK_EQ(v8_str("a"), v8_str("a"));
2450  CHECK_NE(v8_str("a"), v8_str("b"));
2451  CHECK_EQ(v8_num(1), v8_num(1));
2452  CHECK_EQ(v8_num(1.00), v8_num(1));
2453  CHECK_NE(v8_num(1), v8_num(2));
2454
2455  // Assume String is not symbol.
2456  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2457  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2458  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2459  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2460  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2461  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2462  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2463  CHECK(!not_a_number->StrictEquals(not_a_number));
2464  CHECK(v8::False()->StrictEquals(v8::False()));
2465  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2466
2467  v8::Handle<v8::Object> obj = v8::Object::New();
2468  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2469  CHECK(alias->StrictEquals(obj));
2470  alias.Dispose();
2471}
2472
2473
2474THREADED_TEST(MultiRun) {
2475  v8::HandleScope scope;
2476  LocalContext context;
2477  Local<Script> script = Script::Compile(v8_str("x"));
2478  for (int i = 0; i < 10; i++)
2479    script->Run();
2480}
2481
2482
2483static v8::Handle<Value> GetXValue(Local<String> name,
2484                                   const AccessorInfo& info) {
2485  ApiTestFuzzer::Fuzz();
2486  CHECK_EQ(info.Data(), v8_str("donut"));
2487  CHECK_EQ(name, v8_str("x"));
2488  return name;
2489}
2490
2491
2492THREADED_TEST(SimplePropertyRead) {
2493  v8::HandleScope scope;
2494  Local<ObjectTemplate> templ = ObjectTemplate::New();
2495  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2496  LocalContext context;
2497  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2498  Local<Script> script = Script::Compile(v8_str("obj.x"));
2499  for (int i = 0; i < 10; i++) {
2500    Local<Value> result = script->Run();
2501    CHECK_EQ(result, v8_str("x"));
2502  }
2503}
2504
2505THREADED_TEST(DefinePropertyOnAPIAccessor) {
2506  v8::HandleScope scope;
2507  Local<ObjectTemplate> templ = ObjectTemplate::New();
2508  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2509  LocalContext context;
2510  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2511
2512  // Uses getOwnPropertyDescriptor to check the configurable status
2513  Local<Script> script_desc
2514    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2515                             "obj, 'x');"
2516                             "prop.configurable;"));
2517  Local<Value> result = script_desc->Run();
2518  CHECK_EQ(result->BooleanValue(), true);
2519
2520  // Redefine get - but still configurable
2521  Local<Script> script_define
2522    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2523                             "            configurable: true };"
2524                             "Object.defineProperty(obj, 'x', desc);"
2525                             "obj.x"));
2526  result = script_define->Run();
2527  CHECK_EQ(result, v8_num(42));
2528
2529  // Check that the accessor is still configurable
2530  result = script_desc->Run();
2531  CHECK_EQ(result->BooleanValue(), true);
2532
2533  // Redefine to a non-configurable
2534  script_define
2535    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2536                             "             configurable: false };"
2537                             "Object.defineProperty(obj, 'x', desc);"
2538                             "obj.x"));
2539  result = script_define->Run();
2540  CHECK_EQ(result, v8_num(43));
2541  result = script_desc->Run();
2542  CHECK_EQ(result->BooleanValue(), false);
2543
2544  // Make sure that it is not possible to redefine again
2545  v8::TryCatch try_catch;
2546  result = script_define->Run();
2547  CHECK(try_catch.HasCaught());
2548  String::AsciiValue exception_value(try_catch.Exception());
2549  CHECK_EQ(*exception_value,
2550           "TypeError: Cannot redefine property: defineProperty");
2551}
2552
2553THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2554  v8::HandleScope scope;
2555  Local<ObjectTemplate> templ = ObjectTemplate::New();
2556  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2557  LocalContext context;
2558  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2559
2560  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2561                                    "Object.getOwnPropertyDescriptor( "
2562                                    "obj, 'x');"
2563                                    "prop.configurable;"));
2564  Local<Value> result = script_desc->Run();
2565  CHECK_EQ(result->BooleanValue(), true);
2566
2567  Local<Script> script_define =
2568    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2569                           "            configurable: true };"
2570                           "Object.defineProperty(obj, 'x', desc);"
2571                           "obj.x"));
2572  result = script_define->Run();
2573  CHECK_EQ(result, v8_num(42));
2574
2575
2576  result = script_desc->Run();
2577  CHECK_EQ(result->BooleanValue(), true);
2578
2579
2580  script_define =
2581    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2582                           "            configurable: false };"
2583                           "Object.defineProperty(obj, 'x', desc);"
2584                           "obj.x"));
2585  result = script_define->Run();
2586  CHECK_EQ(result, v8_num(43));
2587  result = script_desc->Run();
2588
2589  CHECK_EQ(result->BooleanValue(), false);
2590
2591  v8::TryCatch try_catch;
2592  result = script_define->Run();
2593  CHECK(try_catch.HasCaught());
2594  String::AsciiValue exception_value(try_catch.Exception());
2595  CHECK_EQ(*exception_value,
2596           "TypeError: Cannot redefine property: defineProperty");
2597}
2598
2599
2600static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2601                                                char const* name) {
2602  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2603}
2604
2605
2606THREADED_TEST(DefineAPIAccessorOnObject) {
2607  v8::HandleScope scope;
2608  Local<ObjectTemplate> templ = ObjectTemplate::New();
2609  LocalContext context;
2610
2611  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2612  CompileRun("var obj2 = {};");
2613
2614  CHECK(CompileRun("obj1.x")->IsUndefined());
2615  CHECK(CompileRun("obj2.x")->IsUndefined());
2616
2617  CHECK(GetGlobalProperty(&context, "obj1")->
2618      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2619
2620  ExpectString("obj1.x", "x");
2621  CHECK(CompileRun("obj2.x")->IsUndefined());
2622
2623  CHECK(GetGlobalProperty(&context, "obj2")->
2624      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2625
2626  ExpectString("obj1.x", "x");
2627  ExpectString("obj2.x", "x");
2628
2629  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2630  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2631
2632  CompileRun("Object.defineProperty(obj1, 'x',"
2633             "{ get: function() { return 'y'; }, configurable: true })");
2634
2635  ExpectString("obj1.x", "y");
2636  ExpectString("obj2.x", "x");
2637
2638  CompileRun("Object.defineProperty(obj2, 'x',"
2639             "{ get: function() { return 'y'; }, configurable: true })");
2640
2641  ExpectString("obj1.x", "y");
2642  ExpectString("obj2.x", "y");
2643
2644  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2645  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2646
2647  CHECK(GetGlobalProperty(&context, "obj1")->
2648      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2649  CHECK(GetGlobalProperty(&context, "obj2")->
2650      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2651
2652  ExpectString("obj1.x", "x");
2653  ExpectString("obj2.x", "x");
2654
2655  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2656  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2657
2658  // Define getters/setters, but now make them not configurable.
2659  CompileRun("Object.defineProperty(obj1, 'x',"
2660             "{ get: function() { return 'z'; }, configurable: false })");
2661  CompileRun("Object.defineProperty(obj2, 'x',"
2662             "{ get: function() { return 'z'; }, configurable: false })");
2663
2664  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2665  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2666
2667  ExpectString("obj1.x", "z");
2668  ExpectString("obj2.x", "z");
2669
2670  CHECK(!GetGlobalProperty(&context, "obj1")->
2671      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2672  CHECK(!GetGlobalProperty(&context, "obj2")->
2673      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2674
2675  ExpectString("obj1.x", "z");
2676  ExpectString("obj2.x", "z");
2677}
2678
2679
2680THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2681  v8::HandleScope scope;
2682  Local<ObjectTemplate> templ = ObjectTemplate::New();
2683  LocalContext context;
2684
2685  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2686  CompileRun("var obj2 = {};");
2687
2688  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2689        v8_str("x"),
2690        GetXValue, NULL,
2691        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2692  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2693        v8_str("x"),
2694        GetXValue, NULL,
2695        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2696
2697  ExpectString("obj1.x", "x");
2698  ExpectString("obj2.x", "x");
2699
2700  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2701  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2702
2703  CHECK(!GetGlobalProperty(&context, "obj1")->
2704      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2705  CHECK(!GetGlobalProperty(&context, "obj2")->
2706      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2707
2708  {
2709    v8::TryCatch try_catch;
2710    CompileRun("Object.defineProperty(obj1, 'x',"
2711        "{get: function() { return 'func'; }})");
2712    CHECK(try_catch.HasCaught());
2713    String::AsciiValue exception_value(try_catch.Exception());
2714    CHECK_EQ(*exception_value,
2715            "TypeError: Cannot redefine property: defineProperty");
2716  }
2717  {
2718    v8::TryCatch try_catch;
2719    CompileRun("Object.defineProperty(obj2, 'x',"
2720        "{get: function() { return 'func'; }})");
2721    CHECK(try_catch.HasCaught());
2722    String::AsciiValue exception_value(try_catch.Exception());
2723    CHECK_EQ(*exception_value,
2724            "TypeError: Cannot redefine property: defineProperty");
2725  }
2726}
2727
2728
2729static v8::Handle<Value> Get239Value(Local<String> name,
2730                                     const AccessorInfo& info) {
2731  ApiTestFuzzer::Fuzz();
2732  CHECK_EQ(info.Data(), v8_str("donut"));
2733  CHECK_EQ(name, v8_str("239"));
2734  return name;
2735}
2736
2737
2738THREADED_TEST(ElementAPIAccessor) {
2739  v8::HandleScope scope;
2740  Local<ObjectTemplate> templ = ObjectTemplate::New();
2741  LocalContext context;
2742
2743  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2744  CompileRun("var obj2 = {};");
2745
2746  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2747        v8_str("239"),
2748        Get239Value, NULL,
2749        v8_str("donut")));
2750  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2751        v8_str("239"),
2752        Get239Value, NULL,
2753        v8_str("donut")));
2754
2755  ExpectString("obj1[239]", "239");
2756  ExpectString("obj2[239]", "239");
2757  ExpectString("obj1['239']", "239");
2758  ExpectString("obj2['239']", "239");
2759}
2760
2761
2762v8::Persistent<Value> xValue;
2763
2764
2765static void SetXValue(Local<String> name,
2766                      Local<Value> value,
2767                      const AccessorInfo& info) {
2768  CHECK_EQ(value, v8_num(4));
2769  CHECK_EQ(info.Data(), v8_str("donut"));
2770  CHECK_EQ(name, v8_str("x"));
2771  CHECK(xValue.IsEmpty());
2772  xValue = v8::Persistent<Value>::New(value);
2773}
2774
2775
2776THREADED_TEST(SimplePropertyWrite) {
2777  v8::HandleScope scope;
2778  Local<ObjectTemplate> templ = ObjectTemplate::New();
2779  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2780  LocalContext context;
2781  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2782  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2783  for (int i = 0; i < 10; i++) {
2784    CHECK(xValue.IsEmpty());
2785    script->Run();
2786    CHECK_EQ(v8_num(4), xValue);
2787    xValue.Dispose();
2788    xValue = v8::Persistent<Value>();
2789  }
2790}
2791
2792
2793static v8::Handle<Value> XPropertyGetter(Local<String> property,
2794                                         const AccessorInfo& info) {
2795  ApiTestFuzzer::Fuzz();
2796  CHECK(info.Data()->IsUndefined());
2797  return property;
2798}
2799
2800
2801THREADED_TEST(NamedInterceptorPropertyRead) {
2802  v8::HandleScope scope;
2803  Local<ObjectTemplate> templ = ObjectTemplate::New();
2804  templ->SetNamedPropertyHandler(XPropertyGetter);
2805  LocalContext context;
2806  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2807  Local<Script> script = Script::Compile(v8_str("obj.x"));
2808  for (int i = 0; i < 10; i++) {
2809    Local<Value> result = script->Run();
2810    CHECK_EQ(result, v8_str("x"));
2811  }
2812}
2813
2814
2815THREADED_TEST(NamedInterceptorDictionaryIC) {
2816  v8::HandleScope scope;
2817  Local<ObjectTemplate> templ = ObjectTemplate::New();
2818  templ->SetNamedPropertyHandler(XPropertyGetter);
2819  LocalContext context;
2820  // Create an object with a named interceptor.
2821  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2822  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2823  for (int i = 0; i < 10; i++) {
2824    Local<Value> result = script->Run();
2825    CHECK_EQ(result, v8_str("x"));
2826  }
2827  // Create a slow case object and a function accessing a property in
2828  // that slow case object (with dictionary probing in generated
2829  // code). Then force object with a named interceptor into slow-case,
2830  // pass it to the function, and check that the interceptor is called
2831  // instead of accessing the local property.
2832  Local<Value> result =
2833      CompileRun("function get_x(o) { return o.x; };"
2834                 "var obj = { x : 42, y : 0 };"
2835                 "delete obj.y;"
2836                 "for (var i = 0; i < 10; i++) get_x(obj);"
2837                 "interceptor_obj.x = 42;"
2838                 "interceptor_obj.y = 10;"
2839                 "delete interceptor_obj.y;"
2840                 "get_x(interceptor_obj)");
2841  CHECK_EQ(result, v8_str("x"));
2842}
2843
2844
2845static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2846                                               const AccessorInfo& info) {
2847  // Set x on the prototype object and do not handle the get request.
2848  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2849  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
2850  return v8::Handle<Value>();
2851}
2852
2853
2854// This is a regression test for http://crbug.com/20104. Map
2855// transitions should not interfere with post interceptor lookup.
2856THREADED_TEST(NamedInterceptorMapTransitionRead) {
2857  v8::HandleScope scope;
2858  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2859  Local<v8::ObjectTemplate> instance_template
2860      = function_template->InstanceTemplate();
2861  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2862  LocalContext context;
2863  context->Global()->Set(v8_str("F"), function_template->GetFunction());
2864  // Create an instance of F and introduce a map transition for x.
2865  CompileRun("var o = new F(); o.x = 23;");
2866  // Create an instance of F and invoke the getter. The result should be 23.
2867  Local<Value> result = CompileRun("o = new F(); o.x");
2868  CHECK_EQ(result->Int32Value(), 23);
2869}
2870
2871
2872static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2873                                               const AccessorInfo& info) {
2874  ApiTestFuzzer::Fuzz();
2875  if (index == 37) {
2876    return v8::Handle<Value>(v8_num(625));
2877  }
2878  return v8::Handle<Value>();
2879}
2880
2881
2882static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2883                                               Local<Value> value,
2884                                               const AccessorInfo& info) {
2885  ApiTestFuzzer::Fuzz();
2886  if (index == 39) {
2887    return value;
2888  }
2889  return v8::Handle<Value>();
2890}
2891
2892
2893THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2894  v8::HandleScope scope;
2895  Local<ObjectTemplate> templ = ObjectTemplate::New();
2896  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2897                                   IndexedPropertySetter);
2898  LocalContext context;
2899  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2900  Local<Script> getter_script = Script::Compile(v8_str(
2901      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2902  Local<Script> setter_script = Script::Compile(v8_str(
2903      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2904      "obj[17] = 23;"
2905      "obj.foo;"));
2906  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2907      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2908      "obj[39] = 47;"
2909      "obj.foo;"));  // This setter should not run, due to the interceptor.
2910  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2911      "obj[37];"));
2912  Local<Value> result = getter_script->Run();
2913  CHECK_EQ(v8_num(5), result);
2914  result = setter_script->Run();
2915  CHECK_EQ(v8_num(23), result);
2916  result = interceptor_setter_script->Run();
2917  CHECK_EQ(v8_num(23), result);
2918  result = interceptor_getter_script->Run();
2919  CHECK_EQ(v8_num(625), result);
2920}
2921
2922
2923static v8::Handle<Value> IdentityIndexedPropertyGetter(
2924    uint32_t index,
2925    const AccessorInfo& info) {
2926  return v8::Integer::New(index);
2927}
2928
2929
2930THREADED_TEST(IndexedInterceptorWithNoSetter) {
2931  v8::HandleScope scope;
2932  Local<ObjectTemplate> templ = ObjectTemplate::New();
2933  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2934
2935  LocalContext context;
2936  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2937
2938  const char* code =
2939      "try {"
2940      "  obj[0] = 239;"
2941      "  for (var i = 0; i < 100; i++) {"
2942      "    var v = obj[0];"
2943      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
2944      "  }"
2945      "  'PASSED'"
2946      "} catch(e) {"
2947      "  e"
2948      "}";
2949  ExpectString(code, "PASSED");
2950}
2951
2952
2953THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
2954  v8::HandleScope scope;
2955  Local<ObjectTemplate> templ = ObjectTemplate::New();
2956  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2957
2958  LocalContext context;
2959  Local<v8::Object> obj = templ->NewInstance();
2960  obj->TurnOnAccessCheck();
2961  context->Global()->Set(v8_str("obj"), obj);
2962
2963  const char* code =
2964      "try {"
2965      "  for (var i = 0; i < 100; i++) {"
2966      "    var v = obj[0];"
2967      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
2968      "  }"
2969      "  'PASSED'"
2970      "} catch(e) {"
2971      "  e"
2972      "}";
2973  ExpectString(code, "PASSED");
2974}
2975
2976
2977THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
2978  i::FLAG_allow_natives_syntax = true;
2979  v8::HandleScope scope;
2980  Local<ObjectTemplate> templ = ObjectTemplate::New();
2981  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2982
2983  LocalContext context;
2984  Local<v8::Object> obj = templ->NewInstance();
2985  context->Global()->Set(v8_str("obj"), obj);
2986
2987  const char* code =
2988      "try {"
2989      "  for (var i = 0; i < 100; i++) {"
2990      "    var expected = i;"
2991      "    if (i == 5) {"
2992      "      %EnableAccessChecks(obj);"
2993      "      expected = undefined;"
2994      "    }"
2995      "    var v = obj[i];"
2996      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2997      "    if (i == 5) %DisableAccessChecks(obj);"
2998      "  }"
2999      "  'PASSED'"
3000      "} catch(e) {"
3001      "  e"
3002      "}";
3003  ExpectString(code, "PASSED");
3004}
3005
3006
3007THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3008  v8::HandleScope scope;
3009  Local<ObjectTemplate> templ = ObjectTemplate::New();
3010  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3011
3012  LocalContext context;
3013  Local<v8::Object> obj = templ->NewInstance();
3014  context->Global()->Set(v8_str("obj"), obj);
3015
3016  const char* code =
3017      "try {"
3018      "  for (var i = 0; i < 100; i++) {"
3019      "    var v = obj[i];"
3020      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3021      "  }"
3022      "  'PASSED'"
3023      "} catch(e) {"
3024      "  e"
3025      "}";
3026  ExpectString(code, "PASSED");
3027}
3028
3029
3030THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3031  v8::HandleScope scope;
3032  Local<ObjectTemplate> templ = ObjectTemplate::New();
3033  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3034
3035  LocalContext context;
3036  Local<v8::Object> obj = templ->NewInstance();
3037  context->Global()->Set(v8_str("obj"), obj);
3038
3039  const char* code =
3040      "try {"
3041      "  for (var i = 0; i < 100; i++) {"
3042      "    var expected = i;"
3043      "    if (i == 50) {"
3044      "       i = 'foobar';"
3045      "       expected = undefined;"
3046      "    }"
3047      "    var v = obj[i];"
3048      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3049      "  }"
3050      "  'PASSED'"
3051      "} catch(e) {"
3052      "  e"
3053      "}";
3054  ExpectString(code, "PASSED");
3055}
3056
3057
3058THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3059  v8::HandleScope scope;
3060  Local<ObjectTemplate> templ = ObjectTemplate::New();
3061  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3062
3063  LocalContext context;
3064  Local<v8::Object> obj = templ->NewInstance();
3065  context->Global()->Set(v8_str("obj"), obj);
3066
3067  const char* code =
3068      "var original = obj;"
3069      "try {"
3070      "  for (var i = 0; i < 100; i++) {"
3071      "    var expected = i;"
3072      "    if (i == 50) {"
3073      "       obj = {50: 'foobar'};"
3074      "       expected = 'foobar';"
3075      "    }"
3076      "    var v = obj[i];"
3077      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3078      "    if (i == 50) obj = original;"
3079      "  }"
3080      "  'PASSED'"
3081      "} catch(e) {"
3082      "  e"
3083      "}";
3084  ExpectString(code, "PASSED");
3085}
3086
3087
3088THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3089  v8::HandleScope scope;
3090  Local<ObjectTemplate> templ = ObjectTemplate::New();
3091  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3092
3093  LocalContext context;
3094  Local<v8::Object> obj = templ->NewInstance();
3095  context->Global()->Set(v8_str("obj"), obj);
3096
3097  const char* code =
3098      "var original = obj;"
3099      "try {"
3100      "  for (var i = 0; i < 100; i++) {"
3101      "    var expected = i;"
3102      "    if (i == 5) {"
3103      "       obj = 239;"
3104      "       expected = undefined;"
3105      "    }"
3106      "    var v = obj[i];"
3107      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3108      "    if (i == 5) obj = original;"
3109      "  }"
3110      "  'PASSED'"
3111      "} catch(e) {"
3112      "  e"
3113      "}";
3114  ExpectString(code, "PASSED");
3115}
3116
3117
3118THREADED_TEST(IndexedInterceptorOnProto) {
3119  v8::HandleScope scope;
3120  Local<ObjectTemplate> templ = ObjectTemplate::New();
3121  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3122
3123  LocalContext context;
3124  Local<v8::Object> obj = templ->NewInstance();
3125  context->Global()->Set(v8_str("obj"), obj);
3126
3127  const char* code =
3128      "var o = {__proto__: obj};"
3129      "try {"
3130      "  for (var i = 0; i < 100; i++) {"
3131      "    var v = o[i];"
3132      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3133      "  }"
3134      "  'PASSED'"
3135      "} catch(e) {"
3136      "  e"
3137      "}";
3138  ExpectString(code, "PASSED");
3139}
3140
3141
3142THREADED_TEST(MultiContexts) {
3143  v8::HandleScope scope;
3144  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3145  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3146
3147  Local<String> password = v8_str("Password");
3148
3149  // Create an environment
3150  LocalContext context0(0, templ);
3151  context0->SetSecurityToken(password);
3152  v8::Handle<v8::Object> global0 = context0->Global();
3153  global0->Set(v8_str("custom"), v8_num(1234));
3154  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3155
3156  // Create an independent environment
3157  LocalContext context1(0, templ);
3158  context1->SetSecurityToken(password);
3159  v8::Handle<v8::Object> global1 = context1->Global();
3160  global1->Set(v8_str("custom"), v8_num(1234));
3161  CHECK_NE(global0, global1);
3162  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3163  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3164
3165  // Now create a new context with the old global
3166  LocalContext context2(0, templ, global1);
3167  context2->SetSecurityToken(password);
3168  v8::Handle<v8::Object> global2 = context2->Global();
3169  CHECK_EQ(global1, global2);
3170  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3171  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3172}
3173
3174
3175THREADED_TEST(FunctionPrototypeAcrossContexts) {
3176  // Make sure that functions created by cloning boilerplates cannot
3177  // communicate through their __proto__ field.
3178
3179  v8::HandleScope scope;
3180
3181  LocalContext env0;
3182  v8::Handle<v8::Object> global0 =
3183      env0->Global();
3184  v8::Handle<v8::Object> object0 =
3185      global0->Get(v8_str("Object")).As<v8::Object>();
3186  v8::Handle<v8::Object> tostring0 =
3187      object0->Get(v8_str("toString")).As<v8::Object>();
3188  v8::Handle<v8::Object> proto0 =
3189      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3190  proto0->Set(v8_str("custom"), v8_num(1234));
3191
3192  LocalContext env1;
3193  v8::Handle<v8::Object> global1 =
3194      env1->Global();
3195  v8::Handle<v8::Object> object1 =
3196      global1->Get(v8_str("Object")).As<v8::Object>();
3197  v8::Handle<v8::Object> tostring1 =
3198      object1->Get(v8_str("toString")).As<v8::Object>();
3199  v8::Handle<v8::Object> proto1 =
3200      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3201  CHECK(!proto1->Has(v8_str("custom")));
3202}
3203
3204
3205THREADED_TEST(Regress892105) {
3206  // Make sure that object and array literals created by cloning
3207  // boilerplates cannot communicate through their __proto__
3208  // field. This is rather difficult to check, but we try to add stuff
3209  // to Object.prototype and Array.prototype and create a new
3210  // environment. This should succeed.
3211
3212  v8::HandleScope scope;
3213
3214  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3215                                "Array.prototype.arr = 4567;"
3216                                "8901");
3217
3218  LocalContext env0;
3219  Local<Script> script0 = Script::Compile(source);
3220  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3221
3222  LocalContext env1;
3223  Local<Script> script1 = Script::Compile(source);
3224  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3225}
3226
3227
3228THREADED_TEST(UndetectableObject) {
3229  v8::HandleScope scope;
3230  LocalContext env;
3231
3232  Local<v8::FunctionTemplate> desc =
3233      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3234  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3235
3236  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3237  env->Global()->Set(v8_str("undetectable"), obj);
3238
3239  ExpectString("undetectable.toString()", "[object Object]");
3240  ExpectString("typeof undetectable", "undefined");
3241  ExpectString("typeof(undetectable)", "undefined");
3242  ExpectBoolean("typeof undetectable == 'undefined'", true);
3243  ExpectBoolean("typeof undetectable == 'object'", false);
3244  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3245  ExpectBoolean("!undetectable", true);
3246
3247  ExpectObject("true&&undetectable", obj);
3248  ExpectBoolean("false&&undetectable", false);
3249  ExpectBoolean("true||undetectable", true);
3250  ExpectObject("false||undetectable", obj);
3251
3252  ExpectObject("undetectable&&true", obj);
3253  ExpectObject("undetectable&&false", obj);
3254  ExpectBoolean("undetectable||true", true);
3255  ExpectBoolean("undetectable||false", false);
3256
3257  ExpectBoolean("undetectable==null", true);
3258  ExpectBoolean("null==undetectable", true);
3259  ExpectBoolean("undetectable==undefined", true);
3260  ExpectBoolean("undefined==undetectable", true);
3261  ExpectBoolean("undetectable==undetectable", true);
3262
3263
3264  ExpectBoolean("undetectable===null", false);
3265  ExpectBoolean("null===undetectable", false);
3266  ExpectBoolean("undetectable===undefined", false);
3267  ExpectBoolean("undefined===undetectable", false);
3268  ExpectBoolean("undetectable===undetectable", true);
3269}
3270
3271
3272THREADED_TEST(UndetectableString) {
3273  v8::HandleScope scope;
3274  LocalContext env;
3275
3276  Local<String> obj = String::NewUndetectable("foo");
3277  env->Global()->Set(v8_str("undetectable"), obj);
3278
3279  ExpectString("undetectable", "foo");
3280  ExpectString("typeof undetectable", "undefined");
3281  ExpectString("typeof(undetectable)", "undefined");
3282  ExpectBoolean("typeof undetectable == 'undefined'", true);
3283  ExpectBoolean("typeof undetectable == 'string'", false);
3284  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3285  ExpectBoolean("!undetectable", true);
3286
3287  ExpectObject("true&&undetectable", obj);
3288  ExpectBoolean("false&&undetectable", false);
3289  ExpectBoolean("true||undetectable", true);
3290  ExpectObject("false||undetectable", obj);
3291
3292  ExpectObject("undetectable&&true", obj);
3293  ExpectObject("undetectable&&false", obj);
3294  ExpectBoolean("undetectable||true", true);
3295  ExpectBoolean("undetectable||false", false);
3296
3297  ExpectBoolean("undetectable==null", true);
3298  ExpectBoolean("null==undetectable", true);
3299  ExpectBoolean("undetectable==undefined", true);
3300  ExpectBoolean("undefined==undetectable", true);
3301  ExpectBoolean("undetectable==undetectable", true);
3302
3303
3304  ExpectBoolean("undetectable===null", false);
3305  ExpectBoolean("null===undetectable", false);
3306  ExpectBoolean("undetectable===undefined", false);
3307  ExpectBoolean("undefined===undetectable", false);
3308  ExpectBoolean("undetectable===undetectable", true);
3309}
3310
3311
3312template <typename T> static void USE(T) { }
3313
3314
3315// This test is not intended to be run, just type checked.
3316static void PersistentHandles() {
3317  USE(PersistentHandles);
3318  Local<String> str = v8_str("foo");
3319  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3320  USE(p_str);
3321  Local<Script> scr = Script::Compile(v8_str(""));
3322  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3323  USE(p_scr);
3324  Local<ObjectTemplate> templ = ObjectTemplate::New();
3325  v8::Persistent<ObjectTemplate> p_templ =
3326    v8::Persistent<ObjectTemplate>::New(templ);
3327  USE(p_templ);
3328}
3329
3330
3331static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3332  ApiTestFuzzer::Fuzz();
3333  return v8::Undefined();
3334}
3335
3336
3337THREADED_TEST(GlobalObjectTemplate) {
3338  v8::HandleScope handle_scope;
3339  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3340  global_template->Set(v8_str("JSNI_Log"),
3341                       v8::FunctionTemplate::New(HandleLogDelegator));
3342  v8::Persistent<Context> context = Context::New(0, global_template);
3343  Context::Scope context_scope(context);
3344  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3345  context.Dispose();
3346}
3347
3348
3349static const char* kSimpleExtensionSource =
3350  "function Foo() {"
3351  "  return 4;"
3352  "}";
3353
3354
3355THREADED_TEST(SimpleExtensions) {
3356  v8::HandleScope handle_scope;
3357  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3358  const char* extension_names[] = { "simpletest" };
3359  v8::ExtensionConfiguration extensions(1, extension_names);
3360  v8::Handle<Context> context = Context::New(&extensions);
3361  Context::Scope lock(context);
3362  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3363  CHECK_EQ(result, v8::Integer::New(4));
3364}
3365
3366
3367static const char* kEvalExtensionSource1 =
3368  "function UseEval1() {"
3369  "  var x = 42;"
3370  "  return eval('x');"
3371  "}";
3372
3373
3374static const char* kEvalExtensionSource2 =
3375  "(function() {"
3376  "  var x = 42;"
3377  "  function e() {"
3378  "    return eval('x');"
3379  "  }"
3380  "  this.UseEval2 = e;"
3381  "})()";
3382
3383
3384THREADED_TEST(UseEvalFromExtension) {
3385  v8::HandleScope handle_scope;
3386  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3387  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3388  const char* extension_names[] = { "evaltest1", "evaltest2" };
3389  v8::ExtensionConfiguration extensions(2, extension_names);
3390  v8::Handle<Context> context = Context::New(&extensions);
3391  Context::Scope lock(context);
3392  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3393  CHECK_EQ(result, v8::Integer::New(42));
3394  result = Script::Compile(v8_str("UseEval2()"))->Run();
3395  CHECK_EQ(result, v8::Integer::New(42));
3396}
3397
3398
3399static const char* kWithExtensionSource1 =
3400  "function UseWith1() {"
3401  "  var x = 42;"
3402  "  with({x:87}) { return x; }"
3403  "}";
3404
3405
3406
3407static const char* kWithExtensionSource2 =
3408  "(function() {"
3409  "  var x = 42;"
3410  "  function e() {"
3411  "    with ({x:87}) { return x; }"
3412  "  }"
3413  "  this.UseWith2 = e;"
3414  "})()";
3415
3416
3417THREADED_TEST(UseWithFromExtension) {
3418  v8::HandleScope handle_scope;
3419  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3420  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3421  const char* extension_names[] = { "withtest1", "withtest2" };
3422  v8::ExtensionConfiguration extensions(2, extension_names);
3423  v8::Handle<Context> context = Context::New(&extensions);
3424  Context::Scope lock(context);
3425  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3426  CHECK_EQ(result, v8::Integer::New(87));
3427  result = Script::Compile(v8_str("UseWith2()"))->Run();
3428  CHECK_EQ(result, v8::Integer::New(87));
3429}
3430
3431
3432THREADED_TEST(AutoExtensions) {
3433  v8::HandleScope handle_scope;
3434  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3435  extension->set_auto_enable(true);
3436  v8::RegisterExtension(extension);
3437  v8::Handle<Context> context = Context::New();
3438  Context::Scope lock(context);
3439  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3440  CHECK_EQ(result, v8::Integer::New(4));
3441}
3442
3443
3444static const char* kSyntaxErrorInExtensionSource =
3445    "[";
3446
3447
3448// Test that a syntax error in an extension does not cause a fatal
3449// error but results in an empty context.
3450THREADED_TEST(SyntaxErrorExtensions) {
3451  v8::HandleScope handle_scope;
3452  v8::RegisterExtension(new Extension("syntaxerror",
3453                                      kSyntaxErrorInExtensionSource));
3454  const char* extension_names[] = { "syntaxerror" };
3455  v8::ExtensionConfiguration extensions(1, extension_names);
3456  v8::Handle<Context> context = Context::New(&extensions);
3457  CHECK(context.IsEmpty());
3458}
3459
3460
3461static const char* kExceptionInExtensionSource =
3462    "throw 42";
3463
3464
3465// Test that an exception when installing an extension does not cause
3466// a fatal error but results in an empty context.
3467THREADED_TEST(ExceptionExtensions) {
3468  v8::HandleScope handle_scope;
3469  v8::RegisterExtension(new Extension("exception",
3470                                      kExceptionInExtensionSource));
3471  const char* extension_names[] = { "exception" };
3472  v8::ExtensionConfiguration extensions(1, extension_names);
3473  v8::Handle<Context> context = Context::New(&extensions);
3474  CHECK(context.IsEmpty());
3475}
3476
3477
3478static void CheckDependencies(const char* name, const char* expected) {
3479  v8::HandleScope handle_scope;
3480  v8::ExtensionConfiguration config(1, &name);
3481  LocalContext context(&config);
3482  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3483}
3484
3485
3486/*
3487 * Configuration:
3488 *
3489 *     /-- B <--\
3490 * A <-          -- D <-- E
3491 *     \-- C <--/
3492 */
3493THREADED_TEST(ExtensionDependency) {
3494  static const char* kEDeps[] = { "D" };
3495  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3496  static const char* kDDeps[] = { "B", "C" };
3497  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3498  static const char* kBCDeps[] = { "A" };
3499  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3500  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3501  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3502  CheckDependencies("A", "undefinedA");
3503  CheckDependencies("B", "undefinedAB");
3504  CheckDependencies("C", "undefinedAC");
3505  CheckDependencies("D", "undefinedABCD");
3506  CheckDependencies("E", "undefinedABCDE");
3507  v8::HandleScope handle_scope;
3508  static const char* exts[2] = { "C", "E" };
3509  v8::ExtensionConfiguration config(2, exts);
3510  LocalContext context(&config);
3511  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3512}
3513
3514
3515static const char* kExtensionTestScript =
3516  "native function A();"
3517  "native function B();"
3518  "native function C();"
3519  "function Foo(i) {"
3520  "  if (i == 0) return A();"
3521  "  if (i == 1) return B();"
3522  "  if (i == 2) return C();"
3523  "}";
3524
3525
3526static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3527  ApiTestFuzzer::Fuzz();
3528  if (args.IsConstructCall()) {
3529    args.This()->Set(v8_str("data"), args.Data());
3530    return v8::Null();
3531  }
3532  return args.Data();
3533}
3534
3535
3536class FunctionExtension : public Extension {
3537 public:
3538  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3539  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3540      v8::Handle<String> name);
3541};
3542
3543
3544static int lookup_count = 0;
3545v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3546      v8::Handle<String> name) {
3547  lookup_count++;
3548  if (name->Equals(v8_str("A"))) {
3549    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3550  } else if (name->Equals(v8_str("B"))) {
3551    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3552  } else if (name->Equals(v8_str("C"))) {
3553    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3554  } else {
3555    return v8::Handle<v8::FunctionTemplate>();
3556  }
3557}
3558
3559
3560THREADED_TEST(FunctionLookup) {
3561  v8::RegisterExtension(new FunctionExtension());
3562  v8::HandleScope handle_scope;
3563  static const char* exts[1] = { "functiontest" };
3564  v8::ExtensionConfiguration config(1, exts);
3565  LocalContext context(&config);
3566  CHECK_EQ(3, lookup_count);
3567  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3568  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3569  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3570}
3571
3572
3573THREADED_TEST(NativeFunctionConstructCall) {
3574  v8::RegisterExtension(new FunctionExtension());
3575  v8::HandleScope handle_scope;
3576  static const char* exts[1] = { "functiontest" };
3577  v8::ExtensionConfiguration config(1, exts);
3578  LocalContext context(&config);
3579  for (int i = 0; i < 10; i++) {
3580    // Run a few times to ensure that allocation of objects doesn't
3581    // change behavior of a constructor function.
3582    CHECK_EQ(v8::Integer::New(8),
3583             Script::Compile(v8_str("(new A()).data"))->Run());
3584    CHECK_EQ(v8::Integer::New(7),
3585             Script::Compile(v8_str("(new B()).data"))->Run());
3586    CHECK_EQ(v8::Integer::New(6),
3587             Script::Compile(v8_str("(new C()).data"))->Run());
3588  }
3589}
3590
3591
3592static const char* last_location;
3593static const char* last_message;
3594void StoringErrorCallback(const char* location, const char* message) {
3595  if (last_location == NULL) {
3596    last_location = location;
3597    last_message = message;
3598  }
3599}
3600
3601
3602// ErrorReporting creates a circular extensions configuration and
3603// tests that the fatal error handler gets called.  This renders V8
3604// unusable and therefore this test cannot be run in parallel.
3605TEST(ErrorReporting) {
3606  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3607  static const char* aDeps[] = { "B" };
3608  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3609  static const char* bDeps[] = { "A" };
3610  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3611  last_location = NULL;
3612  v8::ExtensionConfiguration config(1, bDeps);
3613  v8::Handle<Context> context = Context::New(&config);
3614  CHECK(context.IsEmpty());
3615  CHECK_NE(last_location, NULL);
3616}
3617
3618
3619static const char* js_code_causing_huge_string_flattening =
3620    "var str = 'X';"
3621    "for (var i = 0; i < 30; i++) {"
3622    "  str = str + str;"
3623    "}"
3624    "str.match(/X/);";
3625
3626
3627void OOMCallback(const char* location, const char* message) {
3628  exit(0);
3629}
3630
3631
3632TEST(RegexpOutOfMemory) {
3633  // Execute a script that causes out of memory when flattening a string.
3634  v8::HandleScope scope;
3635  v8::V8::SetFatalErrorHandler(OOMCallback);
3636  LocalContext context;
3637  Local<Script> script =
3638      Script::Compile(String::New(js_code_causing_huge_string_flattening));
3639  last_location = NULL;
3640  Local<Value> result = script->Run();
3641
3642  CHECK(false);  // Should not return.
3643}
3644
3645
3646static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3647                                             v8::Handle<Value> data) {
3648  CHECK_EQ(v8::Undefined(), data);
3649  CHECK(message->GetScriptResourceName()->IsUndefined());
3650  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3651  message->GetLineNumber();
3652  message->GetSourceLine();
3653}
3654
3655
3656THREADED_TEST(ErrorWithMissingScriptInfo) {
3657  v8::HandleScope scope;
3658  LocalContext context;
3659  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3660  Script::Compile(v8_str("throw Error()"))->Run();
3661  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3662}
3663
3664
3665int global_index = 0;
3666
3667class Snorkel {
3668 public:
3669  Snorkel() { index_ = global_index++; }
3670  int index_;
3671};
3672
3673class Whammy {
3674 public:
3675  Whammy() {
3676    cursor_ = 0;
3677  }
3678  ~Whammy() {
3679    script_.Dispose();
3680  }
3681  v8::Handle<Script> getScript() {
3682    if (script_.IsEmpty())
3683      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3684    return Local<Script>(*script_);
3685  }
3686
3687 public:
3688  static const int kObjectCount = 256;
3689  int cursor_;
3690  v8::Persistent<v8::Object> objects_[kObjectCount];
3691  v8::Persistent<Script> script_;
3692};
3693
3694static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3695  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3696  delete snorkel;
3697  obj.ClearWeak();
3698}
3699
3700v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3701                                       const AccessorInfo& info) {
3702  Whammy* whammy =
3703    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3704
3705  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3706
3707  v8::Handle<v8::Object> obj = v8::Object::New();
3708  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3709  if (!prev.IsEmpty()) {
3710    prev->Set(v8_str("next"), obj);
3711    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3712    whammy->objects_[whammy->cursor_].Clear();
3713  }
3714  whammy->objects_[whammy->cursor_] = global;
3715  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3716  return whammy->getScript()->Run();
3717}
3718
3719THREADED_TEST(WeakReference) {
3720  v8::HandleScope handle_scope;
3721  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3722  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3723                                 0, 0, 0, 0,
3724                                 v8::External::New(new Whammy()));
3725  const char* extension_list[] = { "v8/gc" };
3726  v8::ExtensionConfiguration extensions(1, extension_list);
3727  v8::Persistent<Context> context = Context::New(&extensions);
3728  Context::Scope context_scope(context);
3729
3730  v8::Handle<v8::Object> interceptor = templ->NewInstance();
3731  context->Global()->Set(v8_str("whammy"), interceptor);
3732  const char* code =
3733      "var last;"
3734      "for (var i = 0; i < 10000; i++) {"
3735      "  var obj = whammy.length;"
3736      "  if (last) last.next = obj;"
3737      "  last = obj;"
3738      "}"
3739      "gc();"
3740      "4";
3741  v8::Handle<Value> result = CompileRun(code);
3742  CHECK_EQ(4.0, result->NumberValue());
3743
3744  context.Dispose();
3745}
3746
3747
3748static bool in_scavenge = false;
3749static int last = -1;
3750
3751static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3752  CHECK_EQ(-1, last);
3753  last = 0;
3754  obj.Dispose();
3755  obj.Clear();
3756  in_scavenge = true;
3757  i::Heap::PerformScavenge();
3758  in_scavenge = false;
3759  *(reinterpret_cast<bool*>(data)) = true;
3760}
3761
3762static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3763                                        void* data) {
3764  CHECK_EQ(0, last);
3765  last = 1;
3766  *(reinterpret_cast<bool*>(data)) = in_scavenge;
3767  obj.Dispose();
3768  obj.Clear();
3769}
3770
3771THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3772  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3773  // Calling callbacks from scavenges is unsafe as objects held by those
3774  // handlers might have become strongly reachable, but scavenge doesn't
3775  // check that.
3776  v8::Persistent<Context> context = Context::New();
3777  Context::Scope context_scope(context);
3778
3779  v8::Persistent<v8::Object> object_a;
3780  v8::Persistent<v8::Object> object_b;
3781
3782  {
3783    v8::HandleScope handle_scope;
3784    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3785    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3786  }
3787
3788  bool object_a_disposed = false;
3789  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3790  bool released_in_scavenge = false;
3791  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3792
3793  while (!object_a_disposed) {
3794    i::Heap::CollectAllGarbage(false);
3795  }
3796  CHECK(!released_in_scavenge);
3797}
3798
3799
3800v8::Handle<Function> args_fun;
3801
3802
3803static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3804  ApiTestFuzzer::Fuzz();
3805  CHECK_EQ(args_fun, args.Callee());
3806  CHECK_EQ(3, args.Length());
3807  CHECK_EQ(v8::Integer::New(1), args[0]);
3808  CHECK_EQ(v8::Integer::New(2), args[1]);
3809  CHECK_EQ(v8::Integer::New(3), args[2]);
3810  CHECK_EQ(v8::Undefined(), args[3]);
3811  v8::HandleScope scope;
3812  i::Heap::CollectAllGarbage(false);
3813  return v8::Undefined();
3814}
3815
3816
3817THREADED_TEST(Arguments) {
3818  v8::HandleScope scope;
3819  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3820  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3821  LocalContext context(NULL, global);
3822  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
3823  v8_compile("f(1, 2, 3)")->Run();
3824}
3825
3826
3827static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3828                                        const AccessorInfo&) {
3829  return v8::Handle<Value>();
3830}
3831
3832
3833static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3834                                        const AccessorInfo&) {
3835  return v8::Handle<Value>();
3836}
3837
3838
3839static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3840                                        const AccessorInfo&) {
3841  if (!name->Equals(v8_str("foo"))) {
3842    return v8::Handle<v8::Boolean>();  // not intercepted
3843  }
3844
3845  return v8::False();  // intercepted, and don't delete the property
3846}
3847
3848
3849static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3850  if (index != 2) {
3851    return v8::Handle<v8::Boolean>();  // not intercepted
3852  }
3853
3854  return v8::False();  // intercepted, and don't delete the property
3855}
3856
3857
3858THREADED_TEST(Deleter) {
3859  v8::HandleScope scope;
3860  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3861  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3862  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3863  LocalContext context;
3864  context->Global()->Set(v8_str("k"), obj->NewInstance());
3865  CompileRun(
3866    "k.foo = 'foo';"
3867    "k.bar = 'bar';"
3868    "k[2] = 2;"
3869    "k[4] = 4;");
3870  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3871  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3872
3873  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3874  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3875
3876  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3877  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3878
3879  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3880  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3881}
3882
3883
3884static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3885  ApiTestFuzzer::Fuzz();
3886  if (name->Equals(v8_str("foo")) ||
3887      name->Equals(v8_str("bar")) ||
3888      name->Equals(v8_str("baz"))) {
3889    return v8::Undefined();
3890  }
3891  return v8::Handle<Value>();
3892}
3893
3894
3895static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3896  ApiTestFuzzer::Fuzz();
3897  if (index == 0 || index == 1) return v8::Undefined();
3898  return v8::Handle<Value>();
3899}
3900
3901
3902static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3903  ApiTestFuzzer::Fuzz();
3904  v8::Handle<v8::Array> result = v8::Array::New(3);
3905  result->Set(v8::Integer::New(0), v8_str("foo"));
3906  result->Set(v8::Integer::New(1), v8_str("bar"));
3907  result->Set(v8::Integer::New(2), v8_str("baz"));
3908  return result;
3909}
3910
3911
3912static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3913  ApiTestFuzzer::Fuzz();
3914  v8::Handle<v8::Array> result = v8::Array::New(2);
3915  result->Set(v8::Integer::New(0), v8_str("0"));
3916  result->Set(v8::Integer::New(1), v8_str("1"));
3917  return result;
3918}
3919
3920
3921THREADED_TEST(Enumerators) {
3922  v8::HandleScope scope;
3923  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3924  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3925  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3926  LocalContext context;
3927  context->Global()->Set(v8_str("k"), obj->NewInstance());
3928  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3929    "k[10] = 0;"
3930    "k.a = 0;"
3931    "k[5] = 0;"
3932    "k.b = 0;"
3933    "k[4294967295] = 0;"
3934    "k.c = 0;"
3935    "k[4294967296] = 0;"
3936    "k.d = 0;"
3937    "k[140000] = 0;"
3938    "k.e = 0;"
3939    "k[30000000000] = 0;"
3940    "k.f = 0;"
3941    "var result = [];"
3942    "for (var prop in k) {"
3943    "  result.push(prop);"
3944    "}"
3945    "result"));
3946  // Check that we get all the property names returned including the
3947  // ones from the enumerators in the right order: indexed properties
3948  // in numerical order, indexed interceptor properties, named
3949  // properties in insertion order, named interceptor properties.
3950  // This order is not mandated by the spec, so this test is just
3951  // documenting our behavior.
3952  CHECK_EQ(17, result->Length());
3953  // Indexed properties in numerical order.
3954  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3955  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3956  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3957  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3958  // Indexed interceptor properties in the order they are returned
3959  // from the enumerator interceptor.
3960  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3961  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3962  // Named properties in insertion order.
3963  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3964  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3965  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3966  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3967  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3968  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3969  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3970  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3971  // Named interceptor properties.
3972  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3973  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3974  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
3975}
3976
3977
3978int p_getter_count;
3979int p_getter_count2;
3980
3981
3982static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3983  ApiTestFuzzer::Fuzz();
3984  p_getter_count++;
3985  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3986  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3987  if (name->Equals(v8_str("p1"))) {
3988    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3989  } else if (name->Equals(v8_str("p2"))) {
3990    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3991  } else if (name->Equals(v8_str("p3"))) {
3992    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3993  } else if (name->Equals(v8_str("p4"))) {
3994    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3995  }
3996  return v8::Undefined();
3997}
3998
3999
4000static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4001  ApiTestFuzzer::Fuzz();
4002  LocalContext context;
4003  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4004  CompileRun(
4005    "o1.__proto__ = { };"
4006    "var o2 = { __proto__: o1 };"
4007    "var o3 = { __proto__: o2 };"
4008    "var o4 = { __proto__: o3 };"
4009    "for (var i = 0; i < 10; i++) o4.p4;"
4010    "for (var i = 0; i < 10; i++) o3.p3;"
4011    "for (var i = 0; i < 10; i++) o2.p2;"
4012    "for (var i = 0; i < 10; i++) o1.p1;");
4013}
4014
4015
4016static v8::Handle<Value> PGetter2(Local<String> name,
4017                                  const AccessorInfo& info) {
4018  ApiTestFuzzer::Fuzz();
4019  p_getter_count2++;
4020  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4021  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4022  if (name->Equals(v8_str("p1"))) {
4023    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4024  } else if (name->Equals(v8_str("p2"))) {
4025    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4026  } else if (name->Equals(v8_str("p3"))) {
4027    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4028  } else if (name->Equals(v8_str("p4"))) {
4029    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4030  }
4031  return v8::Undefined();
4032}
4033
4034
4035THREADED_TEST(GetterHolders) {
4036  v8::HandleScope scope;
4037  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4038  obj->SetAccessor(v8_str("p1"), PGetter);
4039  obj->SetAccessor(v8_str("p2"), PGetter);
4040  obj->SetAccessor(v8_str("p3"), PGetter);
4041  obj->SetAccessor(v8_str("p4"), PGetter);
4042  p_getter_count = 0;
4043  RunHolderTest(obj);
4044  CHECK_EQ(40, p_getter_count);
4045}
4046
4047
4048THREADED_TEST(PreInterceptorHolders) {
4049  v8::HandleScope scope;
4050  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4051  obj->SetNamedPropertyHandler(PGetter2);
4052  p_getter_count2 = 0;
4053  RunHolderTest(obj);
4054  CHECK_EQ(40, p_getter_count2);
4055}
4056
4057
4058THREADED_TEST(ObjectInstantiation) {
4059  v8::HandleScope scope;
4060  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4061  templ->SetAccessor(v8_str("t"), PGetter2);
4062  LocalContext context;
4063  context->Global()->Set(v8_str("o"), templ->NewInstance());
4064  for (int i = 0; i < 100; i++) {
4065    v8::HandleScope inner_scope;
4066    v8::Handle<v8::Object> obj = templ->NewInstance();
4067    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4068    context->Global()->Set(v8_str("o2"), obj);
4069    v8::Handle<Value> value =
4070        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4071    CHECK_EQ(v8::True(), value);
4072    context->Global()->Set(v8_str("o"), obj);
4073  }
4074}
4075
4076
4077THREADED_TEST(StringWrite) {
4078  v8::HandleScope scope;
4079  v8::Handle<String> str = v8_str("abcde");
4080
4081  char buf[100];
4082  int len;
4083
4084  memset(buf, 0x1, sizeof(buf));
4085  len = str->WriteAscii(buf);
4086  CHECK_EQ(len, 5);
4087  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4088
4089  memset(buf, 0x1, sizeof(buf));
4090  len = str->WriteAscii(buf, 0, 4);
4091  CHECK_EQ(len, 4);
4092  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4093
4094  memset(buf, 0x1, sizeof(buf));
4095  len = str->WriteAscii(buf, 0, 5);
4096  CHECK_EQ(len, 5);
4097  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4098
4099  memset(buf, 0x1, sizeof(buf));
4100  len = str->WriteAscii(buf, 0, 6);
4101  CHECK_EQ(len, 5);
4102  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4103
4104  memset(buf, 0x1, sizeof(buf));
4105  len = str->WriteAscii(buf, 4, -1);
4106  CHECK_EQ(len, 1);
4107  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4108
4109  memset(buf, 0x1, sizeof(buf));
4110  len = str->WriteAscii(buf, 4, 6);
4111  CHECK_EQ(len, 1);
4112  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4113
4114  memset(buf, 0x1, sizeof(buf));
4115  len = str->WriteAscii(buf, 4, 1);
4116  CHECK_EQ(len, 1);
4117  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4118}
4119
4120
4121THREADED_TEST(ToArrayIndex) {
4122  v8::HandleScope scope;
4123  LocalContext context;
4124
4125  v8::Handle<String> str = v8_str("42");
4126  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4127  CHECK(!index.IsEmpty());
4128  CHECK_EQ(42.0, index->Uint32Value());
4129  str = v8_str("42asdf");
4130  index = str->ToArrayIndex();
4131  CHECK(index.IsEmpty());
4132  str = v8_str("-42");
4133  index = str->ToArrayIndex();
4134  CHECK(index.IsEmpty());
4135  str = v8_str("4294967295");
4136  index = str->ToArrayIndex();
4137  CHECK(!index.IsEmpty());
4138  CHECK_EQ(4294967295.0, index->Uint32Value());
4139  v8::Handle<v8::Number> num = v8::Number::New(1);
4140  index = num->ToArrayIndex();
4141  CHECK(!index.IsEmpty());
4142  CHECK_EQ(1.0, index->Uint32Value());
4143  num = v8::Number::New(-1);
4144  index = num->ToArrayIndex();
4145  CHECK(index.IsEmpty());
4146  v8::Handle<v8::Object> obj = v8::Object::New();
4147  index = obj->ToArrayIndex();
4148  CHECK(index.IsEmpty());
4149}
4150
4151
4152THREADED_TEST(ErrorConstruction) {
4153  v8::HandleScope scope;
4154  LocalContext context;
4155
4156  v8::Handle<String> foo = v8_str("foo");
4157  v8::Handle<String> message = v8_str("message");
4158  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4159  CHECK(range_error->IsObject());
4160  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4161  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4162  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4163  CHECK(reference_error->IsObject());
4164  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4165  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4166  CHECK(syntax_error->IsObject());
4167  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4168  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4169  CHECK(type_error->IsObject());
4170  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4171  v8::Handle<Value> error = v8::Exception::Error(foo);
4172  CHECK(error->IsObject());
4173  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4174}
4175
4176
4177static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4178  ApiTestFuzzer::Fuzz();
4179  return v8_num(10);
4180}
4181
4182
4183static void YSetter(Local<String> name,
4184                    Local<Value> value,
4185                    const AccessorInfo& info) {
4186  if (info.This()->Has(name)) {
4187    info.This()->Delete(name);
4188  }
4189  info.This()->Set(name, value);
4190}
4191
4192
4193THREADED_TEST(DeleteAccessor) {
4194  v8::HandleScope scope;
4195  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4196  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4197  LocalContext context;
4198  v8::Handle<v8::Object> holder = obj->NewInstance();
4199  context->Global()->Set(v8_str("holder"), holder);
4200  v8::Handle<Value> result = CompileRun(
4201      "holder.y = 11; holder.y = 12; holder.y");
4202  CHECK_EQ(12, result->Uint32Value());
4203}
4204
4205
4206THREADED_TEST(TypeSwitch) {
4207  v8::HandleScope scope;
4208  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4209  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4210  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4211  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4212  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4213  LocalContext context;
4214  v8::Handle<v8::Object> obj0 = v8::Object::New();
4215  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4216  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4217  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4218  for (int i = 0; i < 10; i++) {
4219    CHECK_EQ(0, type_switch->match(obj0));
4220    CHECK_EQ(1, type_switch->match(obj1));
4221    CHECK_EQ(2, type_switch->match(obj2));
4222    CHECK_EQ(3, type_switch->match(obj3));
4223    CHECK_EQ(3, type_switch->match(obj3));
4224    CHECK_EQ(2, type_switch->match(obj2));
4225    CHECK_EQ(1, type_switch->match(obj1));
4226    CHECK_EQ(0, type_switch->match(obj0));
4227  }
4228}
4229
4230
4231// For use within the TestSecurityHandler() test.
4232static bool g_security_callback_result = false;
4233static bool NamedSecurityTestCallback(Local<v8::Object> global,
4234                                      Local<Value> name,
4235                                      v8::AccessType type,
4236                                      Local<Value> data) {
4237  // Always allow read access.
4238  if (type == v8::ACCESS_GET)
4239    return true;
4240
4241  // Sometimes allow other access.
4242  return g_security_callback_result;
4243}
4244
4245
4246static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4247                                        uint32_t key,
4248                                        v8::AccessType type,
4249                                        Local<Value> data) {
4250  // Always allow read access.
4251  if (type == v8::ACCESS_GET)
4252    return true;
4253
4254  // Sometimes allow other access.
4255  return g_security_callback_result;
4256}
4257
4258
4259static int trouble_nesting = 0;
4260static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4261  ApiTestFuzzer::Fuzz();
4262  trouble_nesting++;
4263
4264  // Call a JS function that throws an uncaught exception.
4265  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4266  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4267    arg_this->Get(v8_str("trouble_callee")) :
4268    arg_this->Get(v8_str("trouble_caller"));
4269  CHECK(trouble_callee->IsFunction());
4270  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4271}
4272
4273
4274static int report_count = 0;
4275static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4276                                             v8::Handle<Value>) {
4277  report_count++;
4278}
4279
4280
4281// Counts uncaught exceptions, but other tests running in parallel
4282// also have uncaught exceptions.
4283TEST(ApiUncaughtException) {
4284  report_count = 0;
4285  v8::HandleScope scope;
4286  LocalContext env;
4287  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4288
4289  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4290  v8::Local<v8::Object> global = env->Global();
4291  global->Set(v8_str("trouble"), fun->GetFunction());
4292
4293  Script::Compile(v8_str("function trouble_callee() {"
4294                         "  var x = null;"
4295                         "  return x.foo;"
4296                         "};"
4297                         "function trouble_caller() {"
4298                         "  trouble();"
4299                         "};"))->Run();
4300  Local<Value> trouble = global->Get(v8_str("trouble"));
4301  CHECK(trouble->IsFunction());
4302  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4303  CHECK(trouble_callee->IsFunction());
4304  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4305  CHECK(trouble_caller->IsFunction());
4306  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4307  CHECK_EQ(1, report_count);
4308  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4309}
4310
4311static const char* script_resource_name = "ExceptionInNativeScript.js";
4312static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4313                                                v8::Handle<Value>) {
4314  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4315  CHECK(!name_val.IsEmpty() && name_val->IsString());
4316  v8::String::AsciiValue name(message->GetScriptResourceName());
4317  CHECK_EQ(script_resource_name, *name);
4318  CHECK_EQ(3, message->GetLineNumber());
4319  v8::String::AsciiValue source_line(message->GetSourceLine());
4320  CHECK_EQ("  new o.foo();", *source_line);
4321}
4322
4323TEST(ExceptionInNativeScript) {
4324  v8::HandleScope scope;
4325  LocalContext env;
4326  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4327
4328  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4329  v8::Local<v8::Object> global = env->Global();
4330  global->Set(v8_str("trouble"), fun->GetFunction());
4331
4332  Script::Compile(v8_str("function trouble() {\n"
4333                         "  var o = {};\n"
4334                         "  new o.foo();\n"
4335                         "};"), v8::String::New(script_resource_name))->Run();
4336  Local<Value> trouble = global->Get(v8_str("trouble"));
4337  CHECK(trouble->IsFunction());
4338  Function::Cast(*trouble)->Call(global, 0, NULL);
4339  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4340}
4341
4342
4343TEST(CompilationErrorUsingTryCatchHandler) {
4344  v8::HandleScope scope;
4345  LocalContext env;
4346  v8::TryCatch try_catch;
4347  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4348  CHECK_NE(NULL, *try_catch.Exception());
4349  CHECK(try_catch.HasCaught());
4350}
4351
4352
4353TEST(TryCatchFinallyUsingTryCatchHandler) {
4354  v8::HandleScope scope;
4355  LocalContext env;
4356  v8::TryCatch try_catch;
4357  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4358  CHECK(!try_catch.HasCaught());
4359  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4360  CHECK(try_catch.HasCaught());
4361  try_catch.Reset();
4362  Script::Compile(v8_str("(function() {"
4363                         "try { throw ''; } finally { return; }"
4364                         "})()"))->Run();
4365  CHECK(!try_catch.HasCaught());
4366  Script::Compile(v8_str("(function()"
4367                         "  { try { throw ''; } finally { throw 0; }"
4368                         "})()"))->Run();
4369  CHECK(try_catch.HasCaught());
4370}
4371
4372
4373// SecurityHandler can't be run twice
4374TEST(SecurityHandler) {
4375  v8::HandleScope scope0;
4376  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4377  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4378                                           IndexedSecurityTestCallback);
4379  // Create an environment
4380  v8::Persistent<Context> context0 =
4381    Context::New(NULL, global_template);
4382  context0->Enter();
4383
4384  v8::Handle<v8::Object> global0 = context0->Global();
4385  v8::Handle<Script> script0 = v8_compile("foo = 111");
4386  script0->Run();
4387  global0->Set(v8_str("0"), v8_num(999));
4388  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4389  CHECK_EQ(111, foo0->Int32Value());
4390  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4391  CHECK_EQ(999, z0->Int32Value());
4392
4393  // Create another environment, should fail security checks.
4394  v8::HandleScope scope1;
4395
4396  v8::Persistent<Context> context1 =
4397    Context::New(NULL, global_template);
4398  context1->Enter();
4399
4400  v8::Handle<v8::Object> global1 = context1->Global();
4401  global1->Set(v8_str("othercontext"), global0);
4402  // This set will fail the security check.
4403  v8::Handle<Script> script1 =
4404    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4405  script1->Run();
4406  // This read will pass the security check.
4407  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4408  CHECK_EQ(111, foo1->Int32Value());
4409  // This read will pass the security check.
4410  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4411  CHECK_EQ(999, z1->Int32Value());
4412
4413  // Create another environment, should pass security checks.
4414  { g_security_callback_result = true;  // allow security handler to pass.
4415    v8::HandleScope scope2;
4416    LocalContext context2;
4417    v8::Handle<v8::Object> global2 = context2->Global();
4418    global2->Set(v8_str("othercontext"), global0);
4419    v8::Handle<Script> script2 =
4420        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4421    script2->Run();
4422    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4423    CHECK_EQ(333, foo2->Int32Value());
4424    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4425    CHECK_EQ(888, z2->Int32Value());
4426  }
4427
4428  context1->Exit();
4429  context1.Dispose();
4430
4431  context0->Exit();
4432  context0.Dispose();
4433}
4434
4435
4436THREADED_TEST(SecurityChecks) {
4437  v8::HandleScope handle_scope;
4438  LocalContext env1;
4439  v8::Persistent<Context> env2 = Context::New();
4440
4441  Local<Value> foo = v8_str("foo");
4442  Local<Value> bar = v8_str("bar");
4443
4444  // Set to the same domain.
4445  env1->SetSecurityToken(foo);
4446
4447  // Create a function in env1.
4448  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4449  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4450  CHECK(spy->IsFunction());
4451
4452  // Create another function accessing global objects.
4453  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4454  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4455  CHECK(spy2->IsFunction());
4456
4457  // Switch to env2 in the same domain and invoke spy on env2.
4458  {
4459    env2->SetSecurityToken(foo);
4460    // Enter env2
4461    Context::Scope scope_env2(env2);
4462    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4463    CHECK(result->IsFunction());
4464  }
4465
4466  {
4467    env2->SetSecurityToken(bar);
4468    Context::Scope scope_env2(env2);
4469
4470    // Call cross_domain_call, it should throw an exception
4471    v8::TryCatch try_catch;
4472    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4473    CHECK(try_catch.HasCaught());
4474  }
4475
4476  env2.Dispose();
4477}
4478
4479
4480// Regression test case for issue 1183439.
4481THREADED_TEST(SecurityChecksForPrototypeChain) {
4482  v8::HandleScope scope;
4483  LocalContext current;
4484  v8::Persistent<Context> other = Context::New();
4485
4486  // Change context to be able to get to the Object function in the
4487  // other context without hitting the security checks.
4488  v8::Local<Value> other_object;
4489  { Context::Scope scope(other);
4490    other_object = other->Global()->Get(v8_str("Object"));
4491    other->Global()->Set(v8_num(42), v8_num(87));
4492  }
4493
4494  current->Global()->Set(v8_str("other"), other->Global());
4495  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4496
4497  // Make sure the security check fails here and we get an undefined
4498  // result instead of getting the Object function. Repeat in a loop
4499  // to make sure to exercise the IC code.
4500  v8::Local<Script> access_other0 = v8_compile("other.Object");
4501  v8::Local<Script> access_other1 = v8_compile("other[42]");
4502  for (int i = 0; i < 5; i++) {
4503    CHECK(!access_other0->Run()->Equals(other_object));
4504    CHECK(access_other0->Run()->IsUndefined());
4505    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4506    CHECK(access_other1->Run()->IsUndefined());
4507  }
4508
4509  // Create an object that has 'other' in its prototype chain and make
4510  // sure we cannot access the Object function indirectly through
4511  // that. Repeat in a loop to make sure to exercise the IC code.
4512  v8_compile("function F() { };"
4513             "F.prototype = other;"
4514             "var f = new F();")->Run();
4515  v8::Local<Script> access_f0 = v8_compile("f.Object");
4516  v8::Local<Script> access_f1 = v8_compile("f[42]");
4517  for (int j = 0; j < 5; j++) {
4518    CHECK(!access_f0->Run()->Equals(other_object));
4519    CHECK(access_f0->Run()->IsUndefined());
4520    CHECK(!access_f1->Run()->Equals(v8_num(87)));
4521    CHECK(access_f1->Run()->IsUndefined());
4522  }
4523
4524  // Now it gets hairy: Set the prototype for the other global object
4525  // to be the current global object. The prototype chain for 'f' now
4526  // goes through 'other' but ends up in the current global object.
4527  { Context::Scope scope(other);
4528    other->Global()->Set(v8_str("__proto__"), current->Global());
4529  }
4530  // Set a named and an index property on the current global
4531  // object. To force the lookup to go through the other global object,
4532  // the properties must not exist in the other global object.
4533  current->Global()->Set(v8_str("foo"), v8_num(100));
4534  current->Global()->Set(v8_num(99), v8_num(101));
4535  // Try to read the properties from f and make sure that the access
4536  // gets stopped by the security checks on the other global object.
4537  Local<Script> access_f2 = v8_compile("f.foo");
4538  Local<Script> access_f3 = v8_compile("f[99]");
4539  for (int k = 0; k < 5; k++) {
4540    CHECK(!access_f2->Run()->Equals(v8_num(100)));
4541    CHECK(access_f2->Run()->IsUndefined());
4542    CHECK(!access_f3->Run()->Equals(v8_num(101)));
4543    CHECK(access_f3->Run()->IsUndefined());
4544  }
4545  other.Dispose();
4546}
4547
4548
4549THREADED_TEST(CrossDomainDelete) {
4550  v8::HandleScope handle_scope;
4551  LocalContext env1;
4552  v8::Persistent<Context> env2 = Context::New();
4553
4554  Local<Value> foo = v8_str("foo");
4555  Local<Value> bar = v8_str("bar");
4556
4557  // Set to the same domain.
4558  env1->SetSecurityToken(foo);
4559  env2->SetSecurityToken(foo);
4560
4561  env1->Global()->Set(v8_str("prop"), v8_num(3));
4562  env2->Global()->Set(v8_str("env1"), env1->Global());
4563
4564  // Change env2 to a different domain and delete env1.prop.
4565  env2->SetSecurityToken(bar);
4566  {
4567    Context::Scope scope_env2(env2);
4568    Local<Value> result =
4569        Script::Compile(v8_str("delete env1.prop"))->Run();
4570    CHECK(result->IsFalse());
4571  }
4572
4573  // Check that env1.prop still exists.
4574  Local<Value> v = env1->Global()->Get(v8_str("prop"));
4575  CHECK(v->IsNumber());
4576  CHECK_EQ(3, v->Int32Value());
4577
4578  env2.Dispose();
4579}
4580
4581
4582THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4583  v8::HandleScope handle_scope;
4584  LocalContext env1;
4585  v8::Persistent<Context> env2 = Context::New();
4586
4587  Local<Value> foo = v8_str("foo");
4588  Local<Value> bar = v8_str("bar");
4589
4590  // Set to the same domain.
4591  env1->SetSecurityToken(foo);
4592  env2->SetSecurityToken(foo);
4593
4594  env1->Global()->Set(v8_str("prop"), v8_num(3));
4595  env2->Global()->Set(v8_str("env1"), env1->Global());
4596
4597  // env1.prop is enumerable in env2.
4598  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4599  {
4600    Context::Scope scope_env2(env2);
4601    Local<Value> result = Script::Compile(test)->Run();
4602    CHECK(result->IsTrue());
4603  }
4604
4605  // Change env2 to a different domain and test again.
4606  env2->SetSecurityToken(bar);
4607  {
4608    Context::Scope scope_env2(env2);
4609    Local<Value> result = Script::Compile(test)->Run();
4610    CHECK(result->IsFalse());
4611  }
4612
4613  env2.Dispose();
4614}
4615
4616
4617THREADED_TEST(CrossDomainForIn) {
4618  v8::HandleScope handle_scope;
4619  LocalContext env1;
4620  v8::Persistent<Context> env2 = Context::New();
4621
4622  Local<Value> foo = v8_str("foo");
4623  Local<Value> bar = v8_str("bar");
4624
4625  // Set to the same domain.
4626  env1->SetSecurityToken(foo);
4627  env2->SetSecurityToken(foo);
4628
4629  env1->Global()->Set(v8_str("prop"), v8_num(3));
4630  env2->Global()->Set(v8_str("env1"), env1->Global());
4631
4632  // Change env2 to a different domain and set env1's global object
4633  // as the __proto__ of an object in env2 and enumerate properties
4634  // in for-in. It shouldn't enumerate properties on env1's global
4635  // object.
4636  env2->SetSecurityToken(bar);
4637  {
4638    Context::Scope scope_env2(env2);
4639    Local<Value> result =
4640        CompileRun("(function(){var obj = {'__proto__':env1};"
4641                   "for (var p in obj)"
4642                   "   if (p == 'prop') return false;"
4643                   "return true;})()");
4644    CHECK(result->IsTrue());
4645  }
4646  env2.Dispose();
4647}
4648
4649
4650TEST(ContextDetachGlobal) {
4651  v8::HandleScope handle_scope;
4652  LocalContext env1;
4653  v8::Persistent<Context> env2 = Context::New();
4654
4655  Local<v8::Object> global1 = env1->Global();
4656
4657  Local<Value> foo = v8_str("foo");
4658
4659  // Set to the same domain.
4660  env1->SetSecurityToken(foo);
4661  env2->SetSecurityToken(foo);
4662
4663  // Enter env2
4664  env2->Enter();
4665
4666  // Create a function in env2 and add a reference to it in env1.
4667  Local<v8::Object> global2 = env2->Global();
4668  global2->Set(v8_str("prop"), v8::Integer::New(1));
4669  CompileRun("function getProp() {return prop;}");
4670
4671  env1->Global()->Set(v8_str("getProp"),
4672                      global2->Get(v8_str("getProp")));
4673
4674  // Detach env2's global, and reuse the global object of env2
4675  env2->Exit();
4676  env2->DetachGlobal();
4677  // env2 has a new global object.
4678  CHECK(!env2->Global()->Equals(global2));
4679
4680  v8::Persistent<Context> env3 =
4681      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4682  env3->SetSecurityToken(v8_str("bar"));
4683  env3->Enter();
4684
4685  Local<v8::Object> global3 = env3->Global();
4686  CHECK_EQ(global2, global3);
4687  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4688  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4689  global3->Set(v8_str("prop"), v8::Integer::New(-1));
4690  global3->Set(v8_str("prop2"), v8::Integer::New(2));
4691  env3->Exit();
4692
4693  // Call getProp in env1, and it should return the value 1
4694  {
4695    Local<Value> get_prop = global1->Get(v8_str("getProp"));
4696    CHECK(get_prop->IsFunction());
4697    v8::TryCatch try_catch;
4698    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4699    CHECK(!try_catch.HasCaught());
4700    CHECK_EQ(1, r->Int32Value());
4701  }
4702
4703  // Check that env3 is not accessible from env1
4704  {
4705    Local<Value> r = global3->Get(v8_str("prop2"));
4706    CHECK(r->IsUndefined());
4707  }
4708
4709  env2.Dispose();
4710  env3.Dispose();
4711}
4712
4713
4714TEST(DetachAndReattachGlobal) {
4715  v8::HandleScope scope;
4716  LocalContext env1;
4717
4718  // Create second environment.
4719  v8::Persistent<Context> env2 = Context::New();
4720
4721  Local<Value> foo = v8_str("foo");
4722
4723  // Set same security token for env1 and env2.
4724  env1->SetSecurityToken(foo);
4725  env2->SetSecurityToken(foo);
4726
4727  // Create a property on the global object in env2.
4728  {
4729    v8::Context::Scope scope(env2);
4730    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4731  }
4732
4733  // Create a reference to env2 global from env1 global.
4734  env1->Global()->Set(v8_str("other"), env2->Global());
4735
4736  // Check that we have access to other.p in env2 from env1.
4737  Local<Value> result = CompileRun("other.p");
4738  CHECK(result->IsInt32());
4739  CHECK_EQ(42, result->Int32Value());
4740
4741  // Hold on to global from env2 and detach global from env2.
4742  Local<v8::Object> global2 = env2->Global();
4743  env2->DetachGlobal();
4744
4745  // Check that the global has been detached. No other.p property can
4746  // be found.
4747  result = CompileRun("other.p");
4748  CHECK(result->IsUndefined());
4749
4750  // Reuse global2 for env3.
4751  v8::Persistent<Context> env3 =
4752      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4753  CHECK_EQ(global2, env3->Global());
4754
4755  // Start by using the same security token for env3 as for env1 and env2.
4756  env3->SetSecurityToken(foo);
4757
4758  // Create a property on the global object in env3.
4759  {
4760    v8::Context::Scope scope(env3);
4761    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4762  }
4763
4764  // Check that other.p is now the property in env3 and that we have access.
4765  result = CompileRun("other.p");
4766  CHECK(result->IsInt32());
4767  CHECK_EQ(24, result->Int32Value());
4768
4769  // Change security token for env3 to something different from env1 and env2.
4770  env3->SetSecurityToken(v8_str("bar"));
4771
4772  // Check that we do not have access to other.p in env1. |other| is now
4773  // the global object for env3 which has a different security token,
4774  // so access should be blocked.
4775  result = CompileRun("other.p");
4776  CHECK(result->IsUndefined());
4777
4778  // Detach the global for env3 and reattach it to env2.
4779  env3->DetachGlobal();
4780  env2->ReattachGlobal(global2);
4781
4782  // Check that we have access to other.p again in env1.  |other| is now
4783  // the global object for env2 which has the same security token as env1.
4784  result = CompileRun("other.p");
4785  CHECK(result->IsInt32());
4786  CHECK_EQ(42, result->Int32Value());
4787
4788  env2.Dispose();
4789  env3.Dispose();
4790}
4791
4792
4793static bool NamedAccessBlocker(Local<v8::Object> global,
4794                               Local<Value> name,
4795                               v8::AccessType type,
4796                               Local<Value> data) {
4797  return Context::GetCurrent()->Global()->Equals(global);
4798}
4799
4800
4801static bool IndexedAccessBlocker(Local<v8::Object> global,
4802                                 uint32_t key,
4803                                 v8::AccessType type,
4804                                 Local<Value> data) {
4805  return Context::GetCurrent()->Global()->Equals(global);
4806}
4807
4808
4809static int g_echo_value = -1;
4810static v8::Handle<Value> EchoGetter(Local<String> name,
4811                                    const AccessorInfo& info) {
4812  return v8_num(g_echo_value);
4813}
4814
4815
4816static void EchoSetter(Local<String> name,
4817                       Local<Value> value,
4818                       const AccessorInfo&) {
4819  if (value->IsNumber())
4820    g_echo_value = value->Int32Value();
4821}
4822
4823
4824static v8::Handle<Value> UnreachableGetter(Local<String> name,
4825                                           const AccessorInfo& info) {
4826  CHECK(false);  // This function should not be called..
4827  return v8::Undefined();
4828}
4829
4830
4831static void UnreachableSetter(Local<String>, Local<Value>,
4832                              const AccessorInfo&) {
4833  CHECK(false);  // This function should nto be called.
4834}
4835
4836
4837THREADED_TEST(AccessControl) {
4838  v8::HandleScope handle_scope;
4839  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4840
4841  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4842                                           IndexedAccessBlocker);
4843
4844  // Add an accessor accessible by cross-domain JS code.
4845  global_template->SetAccessor(
4846      v8_str("accessible_prop"),
4847      EchoGetter, EchoSetter,
4848      v8::Handle<Value>(),
4849      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4850
4851  // Add an accessor that is not accessible by cross-domain JS code.
4852  global_template->SetAccessor(v8_str("blocked_prop"),
4853                               UnreachableGetter, UnreachableSetter,
4854                               v8::Handle<Value>(),
4855                               v8::DEFAULT);
4856
4857  // Create an environment
4858  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4859  context0->Enter();
4860
4861  v8::Handle<v8::Object> global0 = context0->Global();
4862
4863  v8::HandleScope scope1;
4864
4865  v8::Persistent<Context> context1 = Context::New();
4866  context1->Enter();
4867
4868  v8::Handle<v8::Object> global1 = context1->Global();
4869  global1->Set(v8_str("other"), global0);
4870
4871  v8::Handle<Value> value;
4872
4873  // Access blocked property
4874  value = v8_compile("other.blocked_prop = 1")->Run();
4875  value = v8_compile("other.blocked_prop")->Run();
4876  CHECK(value->IsUndefined());
4877
4878  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4879  CHECK(value->IsFalse());
4880
4881  // Access accessible property
4882  value = v8_compile("other.accessible_prop = 3")->Run();
4883  CHECK(value->IsNumber());
4884  CHECK_EQ(3, value->Int32Value());
4885  CHECK_EQ(3, g_echo_value);
4886
4887  value = v8_compile("other.accessible_prop")->Run();
4888  CHECK(value->IsNumber());
4889  CHECK_EQ(3, value->Int32Value());
4890
4891  value =
4892    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4893  CHECK(value->IsTrue());
4894
4895  // Enumeration doesn't enumerate accessors from inaccessible objects in
4896  // the prototype chain even if the accessors are in themselves accessible.
4897  Local<Value> result =
4898      CompileRun("(function(){var obj = {'__proto__':other};"
4899                 "for (var p in obj)"
4900                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4901                 "     return false;"
4902                 "   }"
4903                 "return true;})()");
4904  CHECK(result->IsTrue());
4905
4906  context1->Exit();
4907  context0->Exit();
4908  context1.Dispose();
4909  context0.Dispose();
4910}
4911
4912
4913static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4914                                            Local<Value> name,
4915                                            v8::AccessType type,
4916                                            Local<Value> data) {
4917  return false;
4918}
4919
4920
4921static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4922                                              uint32_t key,
4923                                              v8::AccessType type,
4924                                              Local<Value> data) {
4925  return false;
4926}
4927
4928
4929THREADED_TEST(AccessControlGetOwnPropertyNames) {
4930  v8::HandleScope handle_scope;
4931  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4932
4933  obj_template->Set(v8_str("x"), v8::Integer::New(42));
4934  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
4935                                        GetOwnPropertyNamesIndexedBlocker);
4936
4937  // Create an environment
4938  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
4939  context0->Enter();
4940
4941  v8::Handle<v8::Object> global0 = context0->Global();
4942
4943  v8::HandleScope scope1;
4944
4945  v8::Persistent<Context> context1 = Context::New();
4946  context1->Enter();
4947
4948  v8::Handle<v8::Object> global1 = context1->Global();
4949  global1->Set(v8_str("other"), global0);
4950  global1->Set(v8_str("object"), obj_template->NewInstance());
4951
4952  v8::Handle<Value> value;
4953
4954  // Attempt to get the property names of the other global object and
4955  // of an object that requires access checks.  Accessing the other
4956  // global object should be blocked by access checks on the global
4957  // proxy object.  Accessing the object that requires access checks
4958  // is blocked by the access checks on the object itself.
4959  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
4960  CHECK(value->IsTrue());
4961
4962  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
4963  CHECK(value->IsTrue());
4964
4965  context1->Exit();
4966  context0->Exit();
4967  context1.Dispose();
4968  context0.Dispose();
4969}
4970
4971
4972static v8::Handle<Value> ConstTenGetter(Local<String> name,
4973                                        const AccessorInfo& info) {
4974  return v8_num(10);
4975}
4976
4977
4978THREADED_TEST(CrossDomainAccessors) {
4979  v8::HandleScope handle_scope;
4980
4981  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4982
4983  v8::Handle<v8::ObjectTemplate> global_template =
4984      func_template->InstanceTemplate();
4985
4986  v8::Handle<v8::ObjectTemplate> proto_template =
4987      func_template->PrototypeTemplate();
4988
4989  // Add an accessor to proto that's accessible by cross-domain JS code.
4990  proto_template->SetAccessor(v8_str("accessible"),
4991                              ConstTenGetter, 0,
4992                              v8::Handle<Value>(),
4993                              v8::ALL_CAN_READ);
4994
4995  // Add an accessor that is not accessible by cross-domain JS code.
4996  global_template->SetAccessor(v8_str("unreachable"),
4997                               UnreachableGetter, 0,
4998                               v8::Handle<Value>(),
4999                               v8::DEFAULT);
5000
5001  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5002  context0->Enter();
5003
5004  Local<v8::Object> global = context0->Global();
5005  // Add a normal property that shadows 'accessible'
5006  global->Set(v8_str("accessible"), v8_num(11));
5007
5008  // Enter a new context.
5009  v8::HandleScope scope1;
5010  v8::Persistent<Context> context1 = Context::New();
5011  context1->Enter();
5012
5013  v8::Handle<v8::Object> global1 = context1->Global();
5014  global1->Set(v8_str("other"), global);
5015
5016  // Should return 10, instead of 11
5017  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5018  CHECK(value->IsNumber());
5019  CHECK_EQ(10, value->Int32Value());
5020
5021  value = v8_compile("other.unreachable")->Run();
5022  CHECK(value->IsUndefined());
5023
5024  context1->Exit();
5025  context0->Exit();
5026  context1.Dispose();
5027  context0.Dispose();
5028}
5029
5030
5031static int named_access_count = 0;
5032static int indexed_access_count = 0;
5033
5034static bool NamedAccessCounter(Local<v8::Object> global,
5035                               Local<Value> name,
5036                               v8::AccessType type,
5037                               Local<Value> data) {
5038  named_access_count++;
5039  return true;
5040}
5041
5042
5043static bool IndexedAccessCounter(Local<v8::Object> global,
5044                                 uint32_t key,
5045                                 v8::AccessType type,
5046                                 Local<Value> data) {
5047  indexed_access_count++;
5048  return true;
5049}
5050
5051
5052// This one is too easily disturbed by other tests.
5053TEST(AccessControlIC) {
5054  named_access_count = 0;
5055  indexed_access_count = 0;
5056
5057  v8::HandleScope handle_scope;
5058
5059  // Create an environment.
5060  v8::Persistent<Context> context0 = Context::New();
5061  context0->Enter();
5062
5063  // Create an object that requires access-check functions to be
5064  // called for cross-domain access.
5065  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5066  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5067                                           IndexedAccessCounter);
5068  Local<v8::Object> object = object_template->NewInstance();
5069
5070  v8::HandleScope scope1;
5071
5072  // Create another environment.
5073  v8::Persistent<Context> context1 = Context::New();
5074  context1->Enter();
5075
5076  // Make easy access to the object from the other environment.
5077  v8::Handle<v8::Object> global1 = context1->Global();
5078  global1->Set(v8_str("obj"), object);
5079
5080  v8::Handle<Value> value;
5081
5082  // Check that the named access-control function is called every time.
5083  CompileRun("function testProp(obj) {"
5084             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5085             "  for (var j = 0; j < 10; j++) obj.prop;"
5086             "  return obj.prop"
5087             "}");
5088  value = CompileRun("testProp(obj)");
5089  CHECK(value->IsNumber());
5090  CHECK_EQ(1, value->Int32Value());
5091  CHECK_EQ(21, named_access_count);
5092
5093  // Check that the named access-control function is called every time.
5094  CompileRun("var p = 'prop';"
5095             "function testKeyed(obj) {"
5096             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5097             "  for (var j = 0; j < 10; j++) obj[p];"
5098             "  return obj[p];"
5099             "}");
5100  // Use obj which requires access checks.  No inline caching is used
5101  // in that case.
5102  value = CompileRun("testKeyed(obj)");
5103  CHECK(value->IsNumber());
5104  CHECK_EQ(1, value->Int32Value());
5105  CHECK_EQ(42, named_access_count);
5106  // Force the inline caches into generic state and try again.
5107  CompileRun("testKeyed({ a: 0 })");
5108  CompileRun("testKeyed({ b: 0 })");
5109  value = CompileRun("testKeyed(obj)");
5110  CHECK(value->IsNumber());
5111  CHECK_EQ(1, value->Int32Value());
5112  CHECK_EQ(63, named_access_count);
5113
5114  // Check that the indexed access-control function is called every time.
5115  CompileRun("function testIndexed(obj) {"
5116             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5117             "  for (var j = 0; j < 10; j++) obj[0];"
5118             "  return obj[0]"
5119             "}");
5120  value = CompileRun("testIndexed(obj)");
5121  CHECK(value->IsNumber());
5122  CHECK_EQ(1, value->Int32Value());
5123  CHECK_EQ(21, indexed_access_count);
5124  // Force the inline caches into generic state.
5125  CompileRun("testIndexed(new Array(1))");
5126  // Test that the indexed access check is called.
5127  value = CompileRun("testIndexed(obj)");
5128  CHECK(value->IsNumber());
5129  CHECK_EQ(1, value->Int32Value());
5130  CHECK_EQ(42, indexed_access_count);
5131
5132  // Check that the named access check is called when invoking
5133  // functions on an object that requires access checks.
5134  CompileRun("obj.f = function() {}");
5135  CompileRun("function testCallNormal(obj) {"
5136             "  for (var i = 0; i < 10; i++) obj.f();"
5137             "}");
5138  CompileRun("testCallNormal(obj)");
5139  CHECK_EQ(74, named_access_count);
5140
5141  // Force obj into slow case.
5142  value = CompileRun("delete obj.prop");
5143  CHECK(value->BooleanValue());
5144  // Force inline caches into dictionary probing mode.
5145  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5146  // Test that the named access check is called.
5147  value = CompileRun("testProp(obj);");
5148  CHECK(value->IsNumber());
5149  CHECK_EQ(1, value->Int32Value());
5150  CHECK_EQ(96, named_access_count);
5151
5152  // Force the call inline cache into dictionary probing mode.
5153  CompileRun("o.f = function() {}; testCallNormal(o)");
5154  // Test that the named access check is still called for each
5155  // invocation of the function.
5156  value = CompileRun("testCallNormal(obj)");
5157  CHECK_EQ(106, named_access_count);
5158
5159  context1->Exit();
5160  context0->Exit();
5161  context1.Dispose();
5162  context0.Dispose();
5163}
5164
5165
5166static bool NamedAccessFlatten(Local<v8::Object> global,
5167                               Local<Value> name,
5168                               v8::AccessType type,
5169                               Local<Value> data) {
5170  char buf[100];
5171  int len;
5172
5173  CHECK(name->IsString());
5174
5175  memset(buf, 0x1, sizeof(buf));
5176  len = name.As<String>()->WriteAscii(buf);
5177  CHECK_EQ(4, len);
5178
5179  uint16_t buf2[100];
5180
5181  memset(buf, 0x1, sizeof(buf));
5182  len = name.As<String>()->Write(buf2);
5183  CHECK_EQ(4, len);
5184
5185  return true;
5186}
5187
5188
5189static bool IndexedAccessFlatten(Local<v8::Object> global,
5190                                 uint32_t key,
5191                                 v8::AccessType type,
5192                                 Local<Value> data) {
5193  return true;
5194}
5195
5196
5197// Regression test.  In access checks, operations that may cause
5198// garbage collection are not allowed.  It used to be the case that
5199// using the Write operation on a string could cause a garbage
5200// collection due to flattening of the string.  This is no longer the
5201// case.
5202THREADED_TEST(AccessControlFlatten) {
5203  named_access_count = 0;
5204  indexed_access_count = 0;
5205
5206  v8::HandleScope handle_scope;
5207
5208  // Create an environment.
5209  v8::Persistent<Context> context0 = Context::New();
5210  context0->Enter();
5211
5212  // Create an object that requires access-check functions to be
5213  // called for cross-domain access.
5214  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5215  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5216                                           IndexedAccessFlatten);
5217  Local<v8::Object> object = object_template->NewInstance();
5218
5219  v8::HandleScope scope1;
5220
5221  // Create another environment.
5222  v8::Persistent<Context> context1 = Context::New();
5223  context1->Enter();
5224
5225  // Make easy access to the object from the other environment.
5226  v8::Handle<v8::Object> global1 = context1->Global();
5227  global1->Set(v8_str("obj"), object);
5228
5229  v8::Handle<Value> value;
5230
5231  value = v8_compile("var p = 'as' + 'df';")->Run();
5232  value = v8_compile("obj[p];")->Run();
5233
5234  context1->Exit();
5235  context0->Exit();
5236  context1.Dispose();
5237  context0.Dispose();
5238}
5239
5240
5241static v8::Handle<Value> AccessControlNamedGetter(
5242    Local<String>, const AccessorInfo&) {
5243  return v8::Integer::New(42);
5244}
5245
5246
5247static v8::Handle<Value> AccessControlNamedSetter(
5248    Local<String>, Local<Value> value, const AccessorInfo&) {
5249  return value;
5250}
5251
5252
5253static v8::Handle<Value> AccessControlIndexedGetter(
5254      uint32_t index,
5255      const AccessorInfo& info) {
5256  return v8_num(42);
5257}
5258
5259
5260static v8::Handle<Value> AccessControlIndexedSetter(
5261    uint32_t, Local<Value> value, const AccessorInfo&) {
5262  return value;
5263}
5264
5265
5266THREADED_TEST(AccessControlInterceptorIC) {
5267  named_access_count = 0;
5268  indexed_access_count = 0;
5269
5270  v8::HandleScope handle_scope;
5271
5272  // Create an environment.
5273  v8::Persistent<Context> context0 = Context::New();
5274  context0->Enter();
5275
5276  // Create an object that requires access-check functions to be
5277  // called for cross-domain access.  The object also has interceptors
5278  // interceptor.
5279  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5280  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5281                                           IndexedAccessCounter);
5282  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5283                                           AccessControlNamedSetter);
5284  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5285                                             AccessControlIndexedSetter);
5286  Local<v8::Object> object = object_template->NewInstance();
5287
5288  v8::HandleScope scope1;
5289
5290  // Create another environment.
5291  v8::Persistent<Context> context1 = Context::New();
5292  context1->Enter();
5293
5294  // Make easy access to the object from the other environment.
5295  v8::Handle<v8::Object> global1 = context1->Global();
5296  global1->Set(v8_str("obj"), object);
5297
5298  v8::Handle<Value> value;
5299
5300  // Check that the named access-control function is called every time
5301  // eventhough there is an interceptor on the object.
5302  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5303  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5304                     "obj.x")->Run();
5305  CHECK(value->IsNumber());
5306  CHECK_EQ(42, value->Int32Value());
5307  CHECK_EQ(21, named_access_count);
5308
5309  value = v8_compile("var p = 'x';")->Run();
5310  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5311  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5312                     "obj[p]")->Run();
5313  CHECK(value->IsNumber());
5314  CHECK_EQ(42, value->Int32Value());
5315  CHECK_EQ(42, named_access_count);
5316
5317  // Check that the indexed access-control function is called every
5318  // time eventhough there is an interceptor on the object.
5319  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5320  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5321                     "obj[0]")->Run();
5322  CHECK(value->IsNumber());
5323  CHECK_EQ(42, value->Int32Value());
5324  CHECK_EQ(21, indexed_access_count);
5325
5326  context1->Exit();
5327  context0->Exit();
5328  context1.Dispose();
5329  context0.Dispose();
5330}
5331
5332
5333THREADED_TEST(Version) {
5334  v8::V8::GetVersion();
5335}
5336
5337
5338static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5339  ApiTestFuzzer::Fuzz();
5340  return v8_num(12);
5341}
5342
5343
5344THREADED_TEST(InstanceProperties) {
5345  v8::HandleScope handle_scope;
5346  LocalContext context;
5347
5348  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5349  Local<ObjectTemplate> instance = t->InstanceTemplate();
5350
5351  instance->Set(v8_str("x"), v8_num(42));
5352  instance->Set(v8_str("f"),
5353                v8::FunctionTemplate::New(InstanceFunctionCallback));
5354
5355  Local<Value> o = t->GetFunction()->NewInstance();
5356
5357  context->Global()->Set(v8_str("i"), o);
5358  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5359  CHECK_EQ(42, value->Int32Value());
5360
5361  value = Script::Compile(v8_str("i.f()"))->Run();
5362  CHECK_EQ(12, value->Int32Value());
5363}
5364
5365
5366static v8::Handle<Value>
5367GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5368  ApiTestFuzzer::Fuzz();
5369  return v8::Handle<Value>();
5370}
5371
5372
5373THREADED_TEST(GlobalObjectInstanceProperties) {
5374  v8::HandleScope handle_scope;
5375
5376  Local<Value> global_object;
5377
5378  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5379  t->InstanceTemplate()->SetNamedPropertyHandler(
5380      GlobalObjectInstancePropertiesGet);
5381  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5382  instance_template->Set(v8_str("x"), v8_num(42));
5383  instance_template->Set(v8_str("f"),
5384                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5385
5386  {
5387    LocalContext env(NULL, instance_template);
5388    // Hold on to the global object so it can be used again in another
5389    // environment initialization.
5390    global_object = env->Global();
5391
5392    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5393    CHECK_EQ(42, value->Int32Value());
5394    value = Script::Compile(v8_str("f()"))->Run();
5395    CHECK_EQ(12, value->Int32Value());
5396  }
5397
5398  {
5399    // Create new environment reusing the global object.
5400    LocalContext env(NULL, instance_template, global_object);
5401    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5402    CHECK_EQ(42, value->Int32Value());
5403    value = Script::Compile(v8_str("f()"))->Run();
5404    CHECK_EQ(12, value->Int32Value());
5405  }
5406}
5407
5408
5409static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5410  ApiTestFuzzer::Fuzz();
5411  return v8_num(42);
5412}
5413
5414
5415static int shadow_y;
5416static int shadow_y_setter_call_count;
5417static int shadow_y_getter_call_count;
5418
5419
5420static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5421  shadow_y_setter_call_count++;
5422  shadow_y = 42;
5423}
5424
5425
5426static v8::Handle<Value> ShadowYGetter(Local<String> name,
5427                                       const AccessorInfo& info) {
5428  ApiTestFuzzer::Fuzz();
5429  shadow_y_getter_call_count++;
5430  return v8_num(shadow_y);
5431}
5432
5433
5434static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5435                                          const AccessorInfo& info) {
5436  return v8::Handle<Value>();
5437}
5438
5439
5440static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5441                                        const AccessorInfo&) {
5442  return v8::Handle<Value>();
5443}
5444
5445
5446THREADED_TEST(ShadowObject) {
5447  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5448  v8::HandleScope handle_scope;
5449
5450  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5451  LocalContext context(NULL, global_template);
5452
5453  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5454  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5455  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5456  Local<ObjectTemplate> proto = t->PrototypeTemplate();
5457  Local<ObjectTemplate> instance = t->InstanceTemplate();
5458
5459  // Only allow calls of f on instances of t.
5460  Local<v8::Signature> signature = v8::Signature::New(t);
5461  proto->Set(v8_str("f"),
5462             v8::FunctionTemplate::New(ShadowFunctionCallback,
5463                                       Local<Value>(),
5464                                       signature));
5465  proto->Set(v8_str("x"), v8_num(12));
5466
5467  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5468
5469  Local<Value> o = t->GetFunction()->NewInstance();
5470  context->Global()->Set(v8_str("__proto__"), o);
5471
5472  Local<Value> value =
5473      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5474  CHECK(value->IsBoolean());
5475  CHECK(!value->BooleanValue());
5476
5477  value = Script::Compile(v8_str("x"))->Run();
5478  CHECK_EQ(12, value->Int32Value());
5479
5480  value = Script::Compile(v8_str("f()"))->Run();
5481  CHECK_EQ(42, value->Int32Value());
5482
5483  Script::Compile(v8_str("y = 42"))->Run();
5484  CHECK_EQ(1, shadow_y_setter_call_count);
5485  value = Script::Compile(v8_str("y"))->Run();
5486  CHECK_EQ(1, shadow_y_getter_call_count);
5487  CHECK_EQ(42, value->Int32Value());
5488}
5489
5490
5491THREADED_TEST(HiddenPrototype) {
5492  v8::HandleScope handle_scope;
5493  LocalContext context;
5494
5495  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5496  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5497  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5498  t1->SetHiddenPrototype(true);
5499  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5500  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5501  t2->SetHiddenPrototype(true);
5502  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5503  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5504  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5505
5506  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5507  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5508  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5509  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5510
5511  // Setting the prototype on an object skips hidden prototypes.
5512  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5513  o0->Set(v8_str("__proto__"), o1);
5514  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5515  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5516  o0->Set(v8_str("__proto__"), o2);
5517  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5518  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5519  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5520  o0->Set(v8_str("__proto__"), o3);
5521  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5522  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5523  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5524  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5525
5526  // Getting the prototype of o0 should get the first visible one
5527  // which is o3.  Therefore, z should not be defined on the prototype
5528  // object.
5529  Local<Value> proto = o0->Get(v8_str("__proto__"));
5530  CHECK(proto->IsObject());
5531  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
5532}
5533
5534
5535THREADED_TEST(SetPrototype) {
5536  v8::HandleScope handle_scope;
5537  LocalContext context;
5538
5539  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5540  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5541  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5542  t1->SetHiddenPrototype(true);
5543  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5544  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5545  t2->SetHiddenPrototype(true);
5546  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5547  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5548  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5549
5550  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5551  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5552  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5553  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5554
5555  // Setting the prototype on an object does not skip hidden prototypes.
5556  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5557  CHECK(o0->SetPrototype(o1));
5558  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5559  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5560  CHECK(o1->SetPrototype(o2));
5561  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5562  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5563  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5564  CHECK(o2->SetPrototype(o3));
5565  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5566  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5567  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5568  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5569
5570  // Getting the prototype of o0 should get the first visible one
5571  // which is o3.  Therefore, z should not be defined on the prototype
5572  // object.
5573  Local<Value> proto = o0->Get(v8_str("__proto__"));
5574  CHECK(proto->IsObject());
5575  CHECK_EQ(proto.As<v8::Object>(), o3);
5576
5577  // However, Object::GetPrototype ignores hidden prototype.
5578  Local<Value> proto0 = o0->GetPrototype();
5579  CHECK(proto0->IsObject());
5580  CHECK_EQ(proto0.As<v8::Object>(), o1);
5581
5582  Local<Value> proto1 = o1->GetPrototype();
5583  CHECK(proto1->IsObject());
5584  CHECK_EQ(proto1.As<v8::Object>(), o2);
5585
5586  Local<Value> proto2 = o2->GetPrototype();
5587  CHECK(proto2->IsObject());
5588  CHECK_EQ(proto2.As<v8::Object>(), o3);
5589}
5590
5591
5592THREADED_TEST(SetPrototypeThrows) {
5593  v8::HandleScope handle_scope;
5594  LocalContext context;
5595
5596  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5597
5598  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5599  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5600
5601  CHECK(o0->SetPrototype(o1));
5602  // If setting the prototype leads to the cycle, SetPrototype should
5603  // return false and keep VM in sane state.
5604  v8::TryCatch try_catch;
5605  CHECK(!o1->SetPrototype(o0));
5606  CHECK(!try_catch.HasCaught());
5607  ASSERT(!i::Top::has_pending_exception());
5608
5609  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5610}
5611
5612
5613THREADED_TEST(GetterSetterExceptions) {
5614  v8::HandleScope handle_scope;
5615  LocalContext context;
5616  CompileRun(
5617    "function Foo() { };"
5618    "function Throw() { throw 5; };"
5619    "var x = { };"
5620    "x.__defineSetter__('set', Throw);"
5621    "x.__defineGetter__('get', Throw);");
5622  Local<v8::Object> x =
5623      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5624  v8::TryCatch try_catch;
5625  x->Set(v8_str("set"), v8::Integer::New(8));
5626  x->Get(v8_str("get"));
5627  x->Set(v8_str("set"), v8::Integer::New(8));
5628  x->Get(v8_str("get"));
5629  x->Set(v8_str("set"), v8::Integer::New(8));
5630  x->Get(v8_str("get"));
5631  x->Set(v8_str("set"), v8::Integer::New(8));
5632  x->Get(v8_str("get"));
5633}
5634
5635
5636THREADED_TEST(Constructor) {
5637  v8::HandleScope handle_scope;
5638  LocalContext context;
5639  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5640  templ->SetClassName(v8_str("Fun"));
5641  Local<Function> cons = templ->GetFunction();
5642  context->Global()->Set(v8_str("Fun"), cons);
5643  Local<v8::Object> inst = cons->NewInstance();
5644  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5645  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5646  CHECK(value->BooleanValue());
5647}
5648
5649THREADED_TEST(FunctionDescriptorException) {
5650  v8::HandleScope handle_scope;
5651  LocalContext context;
5652  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5653  templ->SetClassName(v8_str("Fun"));
5654  Local<Function> cons = templ->GetFunction();
5655  context->Global()->Set(v8_str("Fun"), cons);
5656  Local<Value> value = CompileRun(
5657    "function test() {"
5658    "  try {"
5659    "    (new Fun()).blah()"
5660    "  } catch (e) {"
5661    "    var str = String(e);"
5662    "    if (str.indexOf('TypeError') == -1) return 1;"
5663    "    if (str.indexOf('[object Fun]') != -1) return 2;"
5664    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5665    "    return 0;"
5666    "  }"
5667    "  return 4;"
5668    "}"
5669    "test();");
5670  CHECK_EQ(0, value->Int32Value());
5671}
5672
5673
5674THREADED_TEST(EvalAliasedDynamic) {
5675  v8::HandleScope scope;
5676  LocalContext current;
5677
5678  // Tests where aliased eval can only be resolved dynamically.
5679  Local<Script> script =
5680      Script::Compile(v8_str("function f(x) { "
5681                             "  var foo = 2;"
5682                             "  with (x) { return eval('foo'); }"
5683                             "}"
5684                             "foo = 0;"
5685                             "result1 = f(new Object());"
5686                             "result2 = f(this);"
5687                             "var x = new Object();"
5688                             "x.eval = function(x) { return 1; };"
5689                             "result3 = f(x);"));
5690  script->Run();
5691  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5692  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5693  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5694
5695  v8::TryCatch try_catch;
5696  script =
5697    Script::Compile(v8_str("function f(x) { "
5698                           "  var bar = 2;"
5699                           "  with (x) { return eval('bar'); }"
5700                           "}"
5701                           "f(this)"));
5702  script->Run();
5703  CHECK(try_catch.HasCaught());
5704  try_catch.Reset();
5705}
5706
5707
5708THREADED_TEST(CrossEval) {
5709  v8::HandleScope scope;
5710  LocalContext other;
5711  LocalContext current;
5712
5713  Local<String> token = v8_str("<security token>");
5714  other->SetSecurityToken(token);
5715  current->SetSecurityToken(token);
5716
5717  // Setup reference from current to other.
5718  current->Global()->Set(v8_str("other"), other->Global());
5719
5720  // Check that new variables are introduced in other context.
5721  Local<Script> script =
5722      Script::Compile(v8_str("other.eval('var foo = 1234')"));
5723  script->Run();
5724  Local<Value> foo = other->Global()->Get(v8_str("foo"));
5725  CHECK_EQ(1234, foo->Int32Value());
5726  CHECK(!current->Global()->Has(v8_str("foo")));
5727
5728  // Check that writing to non-existing properties introduces them in
5729  // the other context.
5730  script =
5731      Script::Compile(v8_str("other.eval('na = 1234')"));
5732  script->Run();
5733  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5734  CHECK(!current->Global()->Has(v8_str("na")));
5735
5736  // Check that global variables in current context are not visible in other
5737  // context.
5738  v8::TryCatch try_catch;
5739  script =
5740      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5741  Local<Value> result = script->Run();
5742  CHECK(try_catch.HasCaught());
5743  try_catch.Reset();
5744
5745  // Check that local variables in current context are not visible in other
5746  // context.
5747  script =
5748      Script::Compile(v8_str("(function() { "
5749                             "  var baz = 87;"
5750                             "  return other.eval('baz');"
5751                             "})();"));
5752  result = script->Run();
5753  CHECK(try_catch.HasCaught());
5754  try_catch.Reset();
5755
5756  // Check that global variables in the other environment are visible
5757  // when evaluting code.
5758  other->Global()->Set(v8_str("bis"), v8_num(1234));
5759  script = Script::Compile(v8_str("other.eval('bis')"));
5760  CHECK_EQ(1234, script->Run()->Int32Value());
5761  CHECK(!try_catch.HasCaught());
5762
5763  // Check that the 'this' pointer points to the global object evaluating
5764  // code.
5765  other->Global()->Set(v8_str("t"), other->Global());
5766  script = Script::Compile(v8_str("other.eval('this == t')"));
5767  result = script->Run();
5768  CHECK(result->IsTrue());
5769  CHECK(!try_catch.HasCaught());
5770
5771  // Check that variables introduced in with-statement are not visible in
5772  // other context.
5773  script =
5774      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5775  result = script->Run();
5776  CHECK(try_catch.HasCaught());
5777  try_catch.Reset();
5778
5779  // Check that you cannot use 'eval.call' with another object than the
5780  // current global object.
5781  script =
5782      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5783  result = script->Run();
5784  CHECK(try_catch.HasCaught());
5785}
5786
5787
5788// Test that calling eval in a context which has been detached from
5789// its global throws an exception.  This behavior is consistent with
5790// other JavaScript implementations.
5791THREADED_TEST(EvalInDetachedGlobal) {
5792  v8::HandleScope scope;
5793
5794  v8::Persistent<Context> context0 = Context::New();
5795  v8::Persistent<Context> context1 = Context::New();
5796
5797  // Setup function in context0 that uses eval from context0.
5798  context0->Enter();
5799  v8::Handle<v8::Value> fun =
5800      CompileRun("var x = 42;"
5801                 "(function() {"
5802                 "  var e = eval;"
5803                 "  return function(s) { return e(s); }"
5804                 "})()");
5805  context0->Exit();
5806
5807  // Put the function into context1 and call it before and after
5808  // detaching the global.  Before detaching, the call succeeds and
5809  // after detaching and exception is thrown.
5810  context1->Enter();
5811  context1->Global()->Set(v8_str("fun"), fun);
5812  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5813  CHECK_EQ(42, x_value->Int32Value());
5814  context0->DetachGlobal();
5815  v8::TryCatch catcher;
5816  x_value = CompileRun("fun('x')");
5817  CHECK(x_value.IsEmpty());
5818  CHECK(catcher.HasCaught());
5819  context1->Exit();
5820
5821  context1.Dispose();
5822  context0.Dispose();
5823}
5824
5825
5826THREADED_TEST(CrossLazyLoad) {
5827  v8::HandleScope scope;
5828  LocalContext other;
5829  LocalContext current;
5830
5831  Local<String> token = v8_str("<security token>");
5832  other->SetSecurityToken(token);
5833  current->SetSecurityToken(token);
5834
5835  // Setup reference from current to other.
5836  current->Global()->Set(v8_str("other"), other->Global());
5837
5838  // Trigger lazy loading in other context.
5839  Local<Script> script =
5840      Script::Compile(v8_str("other.eval('new Date(42)')"));
5841  Local<Value> value = script->Run();
5842  CHECK_EQ(42.0, value->NumberValue());
5843}
5844
5845
5846static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
5847  ApiTestFuzzer::Fuzz();
5848  if (args.IsConstructCall()) {
5849    if (args[0]->IsInt32()) {
5850       return v8_num(-args[0]->Int32Value());
5851    }
5852  }
5853
5854  return args[0];
5855}
5856
5857
5858// Test that a call handler can be set for objects which will allow
5859// non-function objects created through the API to be called as
5860// functions.
5861THREADED_TEST(CallAsFunction) {
5862  v8::HandleScope scope;
5863  LocalContext context;
5864
5865  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5866  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5867  instance_template->SetCallAsFunctionHandler(call_as_function);
5868  Local<v8::Object> instance = t->GetFunction()->NewInstance();
5869  context->Global()->Set(v8_str("obj"), instance);
5870  v8::TryCatch try_catch;
5871  Local<Value> value;
5872  CHECK(!try_catch.HasCaught());
5873
5874  value = CompileRun("obj(42)");
5875  CHECK(!try_catch.HasCaught());
5876  CHECK_EQ(42, value->Int32Value());
5877
5878  value = CompileRun("(function(o){return o(49)})(obj)");
5879  CHECK(!try_catch.HasCaught());
5880  CHECK_EQ(49, value->Int32Value());
5881
5882  // test special case of call as function
5883  value = CompileRun("[obj]['0'](45)");
5884  CHECK(!try_catch.HasCaught());
5885  CHECK_EQ(45, value->Int32Value());
5886
5887  value = CompileRun("obj.call = Function.prototype.call;"
5888                     "obj.call(null, 87)");
5889  CHECK(!try_catch.HasCaught());
5890  CHECK_EQ(87, value->Int32Value());
5891
5892  // Regression tests for bug #1116356: Calling call through call/apply
5893  // must work for non-function receivers.
5894  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5895  value = CompileRun(apply_99);
5896  CHECK(!try_catch.HasCaught());
5897  CHECK_EQ(99, value->Int32Value());
5898
5899  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5900  value = CompileRun(call_17);
5901  CHECK(!try_catch.HasCaught());
5902  CHECK_EQ(17, value->Int32Value());
5903
5904  // Check that the call-as-function handler can be called through
5905  // new.
5906  value = CompileRun("new obj(43)");
5907  CHECK(!try_catch.HasCaught());
5908  CHECK_EQ(-43, value->Int32Value());
5909}
5910
5911
5912static int CountHandles() {
5913  return v8::HandleScope::NumberOfHandles();
5914}
5915
5916
5917static int Recurse(int depth, int iterations) {
5918  v8::HandleScope scope;
5919  if (depth == 0) return CountHandles();
5920  for (int i = 0; i < iterations; i++) {
5921    Local<v8::Number> n = v8::Integer::New(42);
5922  }
5923  return Recurse(depth - 1, iterations);
5924}
5925
5926
5927THREADED_TEST(HandleIteration) {
5928  static const int kIterations = 500;
5929  static const int kNesting = 200;
5930  CHECK_EQ(0, CountHandles());
5931  {
5932    v8::HandleScope scope1;
5933    CHECK_EQ(0, CountHandles());
5934    for (int i = 0; i < kIterations; i++) {
5935      Local<v8::Number> n = v8::Integer::New(42);
5936      CHECK_EQ(i + 1, CountHandles());
5937    }
5938
5939    CHECK_EQ(kIterations, CountHandles());
5940    {
5941      v8::HandleScope scope2;
5942      for (int j = 0; j < kIterations; j++) {
5943        Local<v8::Number> n = v8::Integer::New(42);
5944        CHECK_EQ(j + 1 + kIterations, CountHandles());
5945      }
5946    }
5947    CHECK_EQ(kIterations, CountHandles());
5948  }
5949  CHECK_EQ(0, CountHandles());
5950  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
5951}
5952
5953
5954static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5955    Local<String> name,
5956    const AccessorInfo& info) {
5957  ApiTestFuzzer::Fuzz();
5958  return v8::Handle<Value>();
5959}
5960
5961
5962THREADED_TEST(InterceptorHasOwnProperty) {
5963  v8::HandleScope scope;
5964  LocalContext context;
5965  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5966  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5967  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5968  Local<Function> function = fun_templ->GetFunction();
5969  context->Global()->Set(v8_str("constructor"), function);
5970  v8::Handle<Value> value = CompileRun(
5971      "var o = new constructor();"
5972      "o.hasOwnProperty('ostehaps');");
5973  CHECK_EQ(false, value->BooleanValue());
5974  value = CompileRun(
5975      "o.ostehaps = 42;"
5976      "o.hasOwnProperty('ostehaps');");
5977  CHECK_EQ(true, value->BooleanValue());
5978  value = CompileRun(
5979      "var p = new constructor();"
5980      "p.hasOwnProperty('ostehaps');");
5981  CHECK_EQ(false, value->BooleanValue());
5982}
5983
5984
5985static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5986    Local<String> name,
5987    const AccessorInfo& info) {
5988  ApiTestFuzzer::Fuzz();
5989  i::Heap::CollectAllGarbage(false);
5990  return v8::Handle<Value>();
5991}
5992
5993
5994THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5995  v8::HandleScope scope;
5996  LocalContext context;
5997  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5998  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5999  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6000  Local<Function> function = fun_templ->GetFunction();
6001  context->Global()->Set(v8_str("constructor"), function);
6002  // Let's first make some stuff so we can be sure to get a good GC.
6003  CompileRun(
6004      "function makestr(size) {"
6005      "  switch (size) {"
6006      "    case 1: return 'f';"
6007      "    case 2: return 'fo';"
6008      "    case 3: return 'foo';"
6009      "  }"
6010      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6011      "}"
6012      "var x = makestr(12345);"
6013      "x = makestr(31415);"
6014      "x = makestr(23456);");
6015  v8::Handle<Value> value = CompileRun(
6016      "var o = new constructor();"
6017      "o.__proto__ = new String(x);"
6018      "o.hasOwnProperty('ostehaps');");
6019  CHECK_EQ(false, value->BooleanValue());
6020}
6021
6022
6023typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6024                                                 const AccessorInfo& info);
6025
6026
6027static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6028                                   const char* source,
6029                                   int expected) {
6030  v8::HandleScope scope;
6031  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6032  templ->SetNamedPropertyHandler(getter);
6033  LocalContext context;
6034  context->Global()->Set(v8_str("o"), templ->NewInstance());
6035  v8::Handle<Value> value = CompileRun(source);
6036  CHECK_EQ(expected, value->Int32Value());
6037}
6038
6039
6040static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6041                                                 const AccessorInfo& info) {
6042  ApiTestFuzzer::Fuzz();
6043  CHECK(v8_str("x")->Equals(name));
6044  return v8::Integer::New(42);
6045}
6046
6047
6048// This test should hit the load IC for the interceptor case.
6049THREADED_TEST(InterceptorLoadIC) {
6050  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6051    "var result = 0;"
6052    "for (var i = 0; i < 1000; i++) {"
6053    "  result = o.x;"
6054    "}",
6055    42);
6056}
6057
6058
6059// Below go several tests which verify that JITing for various
6060// configurations of interceptor and explicit fields works fine
6061// (those cases are special cased to get better performance).
6062
6063static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6064                                                 const AccessorInfo& info) {
6065  ApiTestFuzzer::Fuzz();
6066  return v8_str("x")->Equals(name)
6067      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6068}
6069
6070
6071THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6072  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6073    "var result = 0;"
6074    "o.y = 239;"
6075    "for (var i = 0; i < 1000; i++) {"
6076    "  result = o.y;"
6077    "}",
6078    239);
6079}
6080
6081
6082THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6083  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6084    "var result = 0;"
6085    "o.__proto__ = { 'y': 239 };"
6086    "for (var i = 0; i < 1000; i++) {"
6087    "  result = o.y + o.x;"
6088    "}",
6089    239 + 42);
6090}
6091
6092
6093THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6094  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6095    "var result = 0;"
6096    "o.__proto__.y = 239;"
6097    "for (var i = 0; i < 1000; i++) {"
6098    "  result = o.y + o.x;"
6099    "}",
6100    239 + 42);
6101}
6102
6103
6104THREADED_TEST(InterceptorLoadICUndefined) {
6105  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6106    "var result = 0;"
6107    "for (var i = 0; i < 1000; i++) {"
6108    "  result = (o.y == undefined) ? 239 : 42;"
6109    "}",
6110    239);
6111}
6112
6113
6114THREADED_TEST(InterceptorLoadICWithOverride) {
6115  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6116    "fst = new Object();  fst.__proto__ = o;"
6117    "snd = new Object();  snd.__proto__ = fst;"
6118    "var result1 = 0;"
6119    "for (var i = 0; i < 1000;  i++) {"
6120    "  result1 = snd.x;"
6121    "}"
6122    "fst.x = 239;"
6123    "var result = 0;"
6124    "for (var i = 0; i < 1000; i++) {"
6125    "  result = snd.x;"
6126    "}"
6127    "result + result1",
6128    239 + 42);
6129}
6130
6131
6132// Test the case when we stored field into
6133// a stub, but interceptor produced value on its own.
6134THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6135  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6136    "proto = new Object();"
6137    "o.__proto__ = proto;"
6138    "proto.x = 239;"
6139    "for (var i = 0; i < 1000; i++) {"
6140    "  o.x;"
6141    // Now it should be ICed and keep a reference to x defined on proto
6142    "}"
6143    "var result = 0;"
6144    "for (var i = 0; i < 1000; i++) {"
6145    "  result += o.x;"
6146    "}"
6147    "result;",
6148    42 * 1000);
6149}
6150
6151
6152// Test the case when we stored field into
6153// a stub, but it got invalidated later on.
6154THREADED_TEST(InterceptorLoadICInvalidatedField) {
6155  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6156    "proto1 = new Object();"
6157    "proto2 = new Object();"
6158    "o.__proto__ = proto1;"
6159    "proto1.__proto__ = proto2;"
6160    "proto2.y = 239;"
6161    "for (var i = 0; i < 1000; i++) {"
6162    "  o.y;"
6163    // Now it should be ICed and keep a reference to y defined on proto2
6164    "}"
6165    "proto1.y = 42;"
6166    "var result = 0;"
6167    "for (var i = 0; i < 1000; i++) {"
6168    "  result += o.y;"
6169    "}"
6170    "result;",
6171    42 * 1000);
6172}
6173
6174
6175static int interceptor_load_not_handled_calls = 0;
6176static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6177                                                   const AccessorInfo& info) {
6178  ++interceptor_load_not_handled_calls;
6179  return v8::Handle<v8::Value>();
6180}
6181
6182
6183// Test how post-interceptor lookups are done in the non-cacheable
6184// case: the interceptor should not be invoked during this lookup.
6185THREADED_TEST(InterceptorLoadICPostInterceptor) {
6186  interceptor_load_not_handled_calls = 0;
6187  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6188    "receiver = new Object();"
6189    "receiver.__proto__ = o;"
6190    "proto = new Object();"
6191    "/* Make proto a slow-case object. */"
6192    "for (var i = 0; i < 1000; i++) {"
6193    "  proto[\"xxxxxxxx\" + i] = [];"
6194    "}"
6195    "proto.x = 17;"
6196    "o.__proto__ = proto;"
6197    "var result = 0;"
6198    "for (var i = 0; i < 1000; i++) {"
6199    "  result += receiver.x;"
6200    "}"
6201    "result;",
6202    17 * 1000);
6203  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6204}
6205
6206
6207// Test the case when we stored field into
6208// a stub, but it got invalidated later on due to override on
6209// global object which is between interceptor and fields' holders.
6210THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6211  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6212    "o.__proto__ = this;"  // set a global to be a proto of o.
6213    "this.__proto__.y = 239;"
6214    "for (var i = 0; i < 10; i++) {"
6215    "  if (o.y != 239) throw 'oops: ' + o.y;"
6216    // Now it should be ICed and keep a reference to y defined on field_holder.
6217    "}"
6218    "this.y = 42;"  // Assign on a global.
6219    "var result = 0;"
6220    "for (var i = 0; i < 10; i++) {"
6221    "  result += o.y;"
6222    "}"
6223    "result;",
6224    42 * 10);
6225}
6226
6227
6228static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6229  ApiTestFuzzer::Fuzz();
6230  return v8_num(239);
6231}
6232
6233
6234static void SetOnThis(Local<String> name,
6235                      Local<Value> value,
6236                      const AccessorInfo& info) {
6237  info.This()->ForceSet(name, value);
6238}
6239
6240
6241THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6242  v8::HandleScope scope;
6243  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6244  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6245  templ->SetAccessor(v8_str("y"), Return239);
6246  LocalContext context;
6247  context->Global()->Set(v8_str("o"), templ->NewInstance());
6248  v8::Handle<Value> value = CompileRun(
6249      "var result = 0;"
6250      "for (var i = 0; i < 7; i++) {"
6251      "  result = o.y;"
6252      "}");
6253  CHECK_EQ(239, value->Int32Value());
6254}
6255
6256
6257THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6258  v8::HandleScope scope;
6259  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6260  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6261  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6262  templ_p->SetAccessor(v8_str("y"), Return239);
6263
6264  LocalContext context;
6265  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6266  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6267
6268  v8::Handle<Value> value = CompileRun(
6269      "o.__proto__ = p;"
6270      "var result = 0;"
6271      "for (var i = 0; i < 7; i++) {"
6272      "  result = o.x + o.y;"
6273      "}");
6274  CHECK_EQ(239 + 42, value->Int32Value());
6275}
6276
6277
6278THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6279  v8::HandleScope scope;
6280  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6281  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6282  templ->SetAccessor(v8_str("y"), Return239);
6283
6284  LocalContext context;
6285  context->Global()->Set(v8_str("o"), templ->NewInstance());
6286
6287  v8::Handle<Value> value = CompileRun(
6288    "fst = new Object();  fst.__proto__ = o;"
6289    "snd = new Object();  snd.__proto__ = fst;"
6290    "var result1 = 0;"
6291    "for (var i = 0; i < 7;  i++) {"
6292    "  result1 = snd.x;"
6293    "}"
6294    "fst.x = 239;"
6295    "var result = 0;"
6296    "for (var i = 0; i < 7; i++) {"
6297    "  result = snd.x;"
6298    "}"
6299    "result + result1");
6300  CHECK_EQ(239 + 42, value->Int32Value());
6301}
6302
6303
6304// Test the case when we stored callback into
6305// a stub, but interceptor produced value on its own.
6306THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6307  v8::HandleScope scope;
6308  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6309  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6310  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6311  templ_p->SetAccessor(v8_str("y"), Return239);
6312
6313  LocalContext context;
6314  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6315  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6316
6317  v8::Handle<Value> value = CompileRun(
6318    "o.__proto__ = p;"
6319    "for (var i = 0; i < 7; i++) {"
6320    "  o.x;"
6321    // Now it should be ICed and keep a reference to x defined on p
6322    "}"
6323    "var result = 0;"
6324    "for (var i = 0; i < 7; i++) {"
6325    "  result += o.x;"
6326    "}"
6327    "result");
6328  CHECK_EQ(42 * 7, value->Int32Value());
6329}
6330
6331
6332// Test the case when we stored callback into
6333// a stub, but it got invalidated later on.
6334THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6335  v8::HandleScope scope;
6336  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6337  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6338  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6339  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6340
6341  LocalContext context;
6342  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6343  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6344
6345  v8::Handle<Value> value = CompileRun(
6346    "inbetween = new Object();"
6347    "o.__proto__ = inbetween;"
6348    "inbetween.__proto__ = p;"
6349    "for (var i = 0; i < 10; i++) {"
6350    "  o.y;"
6351    // Now it should be ICed and keep a reference to y defined on p
6352    "}"
6353    "inbetween.y = 42;"
6354    "var result = 0;"
6355    "for (var i = 0; i < 10; i++) {"
6356    "  result += o.y;"
6357    "}"
6358    "result");
6359  CHECK_EQ(42 * 10, value->Int32Value());
6360}
6361
6362
6363// Test the case when we stored callback into
6364// a stub, but it got invalidated later on due to override on
6365// global object which is between interceptor and callbacks' holders.
6366THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6367  v8::HandleScope scope;
6368  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6369  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6370  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6371  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6372
6373  LocalContext context;
6374  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6375  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6376
6377  v8::Handle<Value> value = CompileRun(
6378    "o.__proto__ = this;"
6379    "this.__proto__ = p;"
6380    "for (var i = 0; i < 10; i++) {"
6381    "  if (o.y != 239) throw 'oops: ' + o.y;"
6382    // Now it should be ICed and keep a reference to y defined on p
6383    "}"
6384    "this.y = 42;"
6385    "var result = 0;"
6386    "for (var i = 0; i < 10; i++) {"
6387    "  result += o.y;"
6388    "}"
6389    "result");
6390  CHECK_EQ(42 * 10, value->Int32Value());
6391}
6392
6393
6394static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6395                                                  const AccessorInfo& info) {
6396  ApiTestFuzzer::Fuzz();
6397  CHECK(v8_str("x")->Equals(name));
6398  return v8::Integer::New(0);
6399}
6400
6401
6402THREADED_TEST(InterceptorReturningZero) {
6403  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6404     "o.x == undefined ? 1 : 0",
6405     0);
6406}
6407
6408
6409static v8::Handle<Value> InterceptorStoreICSetter(
6410    Local<String> key, Local<Value> value, const AccessorInfo&) {
6411  CHECK(v8_str("x")->Equals(key));
6412  CHECK_EQ(42, value->Int32Value());
6413  return value;
6414}
6415
6416
6417// This test should hit the store IC for the interceptor case.
6418THREADED_TEST(InterceptorStoreIC) {
6419  v8::HandleScope scope;
6420  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6421  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6422                                 InterceptorStoreICSetter);
6423  LocalContext context;
6424  context->Global()->Set(v8_str("o"), templ->NewInstance());
6425  v8::Handle<Value> value = CompileRun(
6426    "for (var i = 0; i < 1000; i++) {"
6427    "  o.x = 42;"
6428    "}");
6429}
6430
6431
6432THREADED_TEST(InterceptorStoreICWithNoSetter) {
6433  v8::HandleScope scope;
6434  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6435  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6436  LocalContext context;
6437  context->Global()->Set(v8_str("o"), templ->NewInstance());
6438  v8::Handle<Value> value = CompileRun(
6439    "for (var i = 0; i < 1000; i++) {"
6440    "  o.y = 239;"
6441    "}"
6442    "42 + o.y");
6443  CHECK_EQ(239 + 42, value->Int32Value());
6444}
6445
6446
6447
6448
6449v8::Handle<Value> call_ic_function;
6450v8::Handle<Value> call_ic_function2;
6451v8::Handle<Value> call_ic_function3;
6452
6453static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6454                                                 const AccessorInfo& info) {
6455  ApiTestFuzzer::Fuzz();
6456  CHECK(v8_str("x")->Equals(name));
6457  return call_ic_function;
6458}
6459
6460
6461// This test should hit the call IC for the interceptor case.
6462THREADED_TEST(InterceptorCallIC) {
6463  v8::HandleScope scope;
6464  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6465  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6466  LocalContext context;
6467  context->Global()->Set(v8_str("o"), templ->NewInstance());
6468  call_ic_function =
6469      v8_compile("function f(x) { return x + 1; }; f")->Run();
6470  v8::Handle<Value> value = CompileRun(
6471    "var result = 0;"
6472    "for (var i = 0; i < 1000; i++) {"
6473    "  result = o.x(41);"
6474    "}");
6475  CHECK_EQ(42, value->Int32Value());
6476}
6477
6478
6479// This test checks that if interceptor doesn't provide
6480// a value, we can fetch regular value.
6481THREADED_TEST(InterceptorCallICSeesOthers) {
6482  v8::HandleScope scope;
6483  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6484  templ->SetNamedPropertyHandler(NoBlockGetterX);
6485  LocalContext context;
6486  context->Global()->Set(v8_str("o"), templ->NewInstance());
6487  v8::Handle<Value> value = CompileRun(
6488    "o.x = function f(x) { return x + 1; };"
6489    "var result = 0;"
6490    "for (var i = 0; i < 7; i++) {"
6491    "  result = o.x(41);"
6492    "}");
6493  CHECK_EQ(42, value->Int32Value());
6494}
6495
6496
6497static v8::Handle<Value> call_ic_function4;
6498static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6499                                                  const AccessorInfo& info) {
6500  ApiTestFuzzer::Fuzz();
6501  CHECK(v8_str("x")->Equals(name));
6502  return call_ic_function4;
6503}
6504
6505
6506// This test checks that if interceptor provides a function,
6507// even if we cached shadowed variant, interceptor's function
6508// is invoked
6509THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6510  v8::HandleScope scope;
6511  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6512  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6513  LocalContext context;
6514  context->Global()->Set(v8_str("o"), templ->NewInstance());
6515  call_ic_function4 =
6516      v8_compile("function f(x) { return x - 1; }; f")->Run();
6517  v8::Handle<Value> value = CompileRun(
6518    "o.__proto__.x = function(x) { return x + 1; };"
6519    "var result = 0;"
6520    "for (var i = 0; i < 1000; i++) {"
6521    "  result = o.x(42);"
6522    "}");
6523  CHECK_EQ(41, value->Int32Value());
6524}
6525
6526
6527// Test the case when we stored cacheable lookup into
6528// a stub, but it got invalidated later on
6529THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6530  v8::HandleScope scope;
6531  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6532  templ->SetNamedPropertyHandler(NoBlockGetterX);
6533  LocalContext context;
6534  context->Global()->Set(v8_str("o"), templ->NewInstance());
6535  v8::Handle<Value> value = CompileRun(
6536    "proto1 = new Object();"
6537    "proto2 = new Object();"
6538    "o.__proto__ = proto1;"
6539    "proto1.__proto__ = proto2;"
6540    "proto2.y = function(x) { return x + 1; };"
6541    // Invoke it many times to compile a stub
6542    "for (var i = 0; i < 7; i++) {"
6543    "  o.y(42);"
6544    "}"
6545    "proto1.y = function(x) { return x - 1; };"
6546    "var result = 0;"
6547    "for (var i = 0; i < 7; i++) {"
6548    "  result += o.y(42);"
6549    "}");
6550  CHECK_EQ(41 * 7, value->Int32Value());
6551}
6552
6553
6554static v8::Handle<Value> call_ic_function5;
6555static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6556                                                  const AccessorInfo& info) {
6557  ApiTestFuzzer::Fuzz();
6558  if (v8_str("x")->Equals(name))
6559    return call_ic_function5;
6560  else
6561    return Local<Value>();
6562}
6563
6564
6565// This test checks that if interceptor doesn't provide a function,
6566// cached constant function is used
6567THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6568  v8::HandleScope scope;
6569  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6570  templ->SetNamedPropertyHandler(NoBlockGetterX);
6571  LocalContext context;
6572  context->Global()->Set(v8_str("o"), templ->NewInstance());
6573  v8::Handle<Value> value = CompileRun(
6574    "function inc(x) { return x + 1; };"
6575    "inc(1);"
6576    "o.x = inc;"
6577    "var result = 0;"
6578    "for (var i = 0; i < 1000; i++) {"
6579    "  result = o.x(42);"
6580    "}");
6581  CHECK_EQ(43, value->Int32Value());
6582}
6583
6584
6585// This test checks that if interceptor provides a function,
6586// even if we cached constant function, interceptor's function
6587// is invoked
6588THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6589  v8::HandleScope scope;
6590  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6591  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6592  LocalContext context;
6593  context->Global()->Set(v8_str("o"), templ->NewInstance());
6594  call_ic_function5 =
6595      v8_compile("function f(x) { return x - 1; }; f")->Run();
6596  v8::Handle<Value> value = CompileRun(
6597    "function inc(x) { return x + 1; };"
6598    "inc(1);"
6599    "o.x = inc;"
6600    "var result = 0;"
6601    "for (var i = 0; i < 1000; i++) {"
6602    "  result = o.x(42);"
6603    "}");
6604  CHECK_EQ(41, value->Int32Value());
6605}
6606
6607
6608// Test the case when we stored constant function into
6609// a stub, but it got invalidated later on
6610THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6611  v8::HandleScope scope;
6612  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6613  templ->SetNamedPropertyHandler(NoBlockGetterX);
6614  LocalContext context;
6615  context->Global()->Set(v8_str("o"), templ->NewInstance());
6616  v8::Handle<Value> value = CompileRun(
6617    "function inc(x) { return x + 1; };"
6618    "inc(1);"
6619    "proto1 = new Object();"
6620    "proto2 = new Object();"
6621    "o.__proto__ = proto1;"
6622    "proto1.__proto__ = proto2;"
6623    "proto2.y = inc;"
6624    // Invoke it many times to compile a stub
6625    "for (var i = 0; i < 7; i++) {"
6626    "  o.y(42);"
6627    "}"
6628    "proto1.y = function(x) { return x - 1; };"
6629    "var result = 0;"
6630    "for (var i = 0; i < 7; i++) {"
6631    "  result += o.y(42);"
6632    "}");
6633  CHECK_EQ(41 * 7, value->Int32Value());
6634}
6635
6636
6637// Test the case when we stored constant function into
6638// a stub, but it got invalidated later on due to override on
6639// global object which is between interceptor and constant function' holders.
6640THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6641  v8::HandleScope scope;
6642  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6643  templ->SetNamedPropertyHandler(NoBlockGetterX);
6644  LocalContext context;
6645  context->Global()->Set(v8_str("o"), templ->NewInstance());
6646  v8::Handle<Value> value = CompileRun(
6647    "function inc(x) { return x + 1; };"
6648    "inc(1);"
6649    "o.__proto__ = this;"
6650    "this.__proto__.y = inc;"
6651    // Invoke it many times to compile a stub
6652    "for (var i = 0; i < 7; i++) {"
6653    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6654    "}"
6655    "this.y = function(x) { return x - 1; };"
6656    "var result = 0;"
6657    "for (var i = 0; i < 7; i++) {"
6658    "  result += o.y(42);"
6659    "}");
6660  CHECK_EQ(41 * 7, value->Int32Value());
6661}
6662
6663
6664// Test the case when actual function to call sits on global object.
6665THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6666  v8::HandleScope scope;
6667  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6668  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6669
6670  LocalContext context;
6671  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6672
6673  v8::Handle<Value> value = CompileRun(
6674    "try {"
6675    "  o.__proto__ = this;"
6676    "  for (var i = 0; i < 10; i++) {"
6677    "    var v = o.parseFloat('239');"
6678    "    if (v != 239) throw v;"
6679      // Now it should be ICed and keep a reference to parseFloat.
6680    "  }"
6681    "  var result = 0;"
6682    "  for (var i = 0; i < 10; i++) {"
6683    "    result += o.parseFloat('239');"
6684    "  }"
6685    "  result"
6686    "} catch(e) {"
6687    "  e"
6688    "};");
6689  CHECK_EQ(239 * 10, value->Int32Value());
6690}
6691
6692static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6693                                                  const AccessorInfo& info) {
6694  ApiTestFuzzer::Fuzz();
6695  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6696  ++(*call_count);
6697  if ((*call_count) % 20 == 0) {
6698    v8::internal::Heap::CollectAllGarbage(true);
6699  }
6700  return v8::Handle<Value>();
6701}
6702
6703static v8::Handle<Value> FastApiCallback_TrivialSignature(
6704    const v8::Arguments& args) {
6705  ApiTestFuzzer::Fuzz();
6706  CHECK_EQ(args.This(), args.Holder());
6707  CHECK(args.Data()->Equals(v8_str("method_data")));
6708  return v8::Integer::New(args[0]->Int32Value() + 1);
6709}
6710
6711static v8::Handle<Value> FastApiCallback_SimpleSignature(
6712    const v8::Arguments& args) {
6713  ApiTestFuzzer::Fuzz();
6714  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6715  CHECK(args.Data()->Equals(v8_str("method_data")));
6716  // Note, we're using HasRealNamedProperty instead of Has to avoid
6717  // invoking the interceptor again.
6718  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6719  return v8::Integer::New(args[0]->Int32Value() + 1);
6720}
6721
6722// Helper to maximize the odds of object moving.
6723static void GenerateSomeGarbage() {
6724  CompileRun(
6725      "var garbage;"
6726      "for (var i = 0; i < 1000; i++) {"
6727      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6728      "}"
6729      "garbage = undefined;");
6730}
6731
6732THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6733  int interceptor_call_count = 0;
6734  v8::HandleScope scope;
6735  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6736  v8::Handle<v8::FunctionTemplate> method_templ =
6737      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6738                                v8_str("method_data"),
6739                                v8::Handle<v8::Signature>());
6740  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6741  proto_templ->Set(v8_str("method"), method_templ);
6742  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6743  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6744                                 NULL, NULL, NULL, NULL,
6745                                 v8::External::Wrap(&interceptor_call_count));
6746  LocalContext context;
6747  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6748  GenerateSomeGarbage();
6749  context->Global()->Set(v8_str("o"), fun->NewInstance());
6750  v8::Handle<Value> value = CompileRun(
6751      "var result = 0;"
6752      "for (var i = 0; i < 100; i++) {"
6753      "  result = o.method(41);"
6754      "}");
6755  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6756  CHECK_EQ(100, interceptor_call_count);
6757}
6758
6759THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6760  int interceptor_call_count = 0;
6761  v8::HandleScope scope;
6762  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6763  v8::Handle<v8::FunctionTemplate> method_templ =
6764      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6765                                v8_str("method_data"),
6766                                v8::Signature::New(fun_templ));
6767  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6768  proto_templ->Set(v8_str("method"), method_templ);
6769  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6770  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6771                                 NULL, NULL, NULL, NULL,
6772                                 v8::External::Wrap(&interceptor_call_count));
6773  LocalContext context;
6774  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6775  GenerateSomeGarbage();
6776  context->Global()->Set(v8_str("o"), fun->NewInstance());
6777  v8::Handle<Value> value = CompileRun(
6778      "o.foo = 17;"
6779      "var receiver = {};"
6780      "receiver.__proto__ = o;"
6781      "var result = 0;"
6782      "for (var i = 0; i < 100; i++) {"
6783      "  result = receiver.method(41);"
6784      "}");
6785  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6786  CHECK_EQ(100, interceptor_call_count);
6787}
6788
6789THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6790  int interceptor_call_count = 0;
6791  v8::HandleScope scope;
6792  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6793  v8::Handle<v8::FunctionTemplate> method_templ =
6794      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6795                                v8_str("method_data"),
6796                                v8::Signature::New(fun_templ));
6797  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6798  proto_templ->Set(v8_str("method"), method_templ);
6799  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6800  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6801                                 NULL, NULL, NULL, NULL,
6802                                 v8::External::Wrap(&interceptor_call_count));
6803  LocalContext context;
6804  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6805  GenerateSomeGarbage();
6806  context->Global()->Set(v8_str("o"), fun->NewInstance());
6807  v8::Handle<Value> value = CompileRun(
6808      "o.foo = 17;"
6809      "var receiver = {};"
6810      "receiver.__proto__ = o;"
6811      "var result = 0;"
6812      "var saved_result = 0;"
6813      "for (var i = 0; i < 100; i++) {"
6814      "  result = receiver.method(41);"
6815      "  if (i == 50) {"
6816      "    saved_result = result;"
6817      "    receiver = {method: function(x) { return x - 1 }};"
6818      "  }"
6819      "}");
6820  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6821  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6822  CHECK_GE(interceptor_call_count, 50);
6823}
6824
6825THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6826  int interceptor_call_count = 0;
6827  v8::HandleScope scope;
6828  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6829  v8::Handle<v8::FunctionTemplate> method_templ =
6830      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6831                                v8_str("method_data"),
6832                                v8::Signature::New(fun_templ));
6833  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6834  proto_templ->Set(v8_str("method"), method_templ);
6835  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6836  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6837                                 NULL, NULL, NULL, NULL,
6838                                 v8::External::Wrap(&interceptor_call_count));
6839  LocalContext context;
6840  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6841  GenerateSomeGarbage();
6842  context->Global()->Set(v8_str("o"), fun->NewInstance());
6843  v8::Handle<Value> value = CompileRun(
6844      "o.foo = 17;"
6845      "var receiver = {};"
6846      "receiver.__proto__ = o;"
6847      "var result = 0;"
6848      "var saved_result = 0;"
6849      "for (var i = 0; i < 100; i++) {"
6850      "  result = receiver.method(41);"
6851      "  if (i == 50) {"
6852      "    saved_result = result;"
6853      "    o.method = function(x) { return x - 1 };"
6854      "  }"
6855      "}");
6856  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6857  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6858  CHECK_GE(interceptor_call_count, 50);
6859}
6860
6861THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
6862  int interceptor_call_count = 0;
6863  v8::HandleScope scope;
6864  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6865  v8::Handle<v8::FunctionTemplate> method_templ =
6866      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6867                                v8_str("method_data"),
6868                                v8::Signature::New(fun_templ));
6869  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6870  proto_templ->Set(v8_str("method"), method_templ);
6871  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6872  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6873                                 NULL, NULL, NULL, NULL,
6874                                 v8::External::Wrap(&interceptor_call_count));
6875  LocalContext context;
6876  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6877  GenerateSomeGarbage();
6878  context->Global()->Set(v8_str("o"), fun->NewInstance());
6879  v8::TryCatch try_catch;
6880  v8::Handle<Value> value = CompileRun(
6881      "o.foo = 17;"
6882      "var receiver = {};"
6883      "receiver.__proto__ = o;"
6884      "var result = 0;"
6885      "var saved_result = 0;"
6886      "for (var i = 0; i < 100; i++) {"
6887      "  result = receiver.method(41);"
6888      "  if (i == 50) {"
6889      "    saved_result = result;"
6890      "    receiver = 333;"
6891      "  }"
6892      "}");
6893  CHECK(try_catch.HasCaught());
6894  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6895           try_catch.Exception()->ToString());
6896  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6897  CHECK_GE(interceptor_call_count, 50);
6898}
6899
6900THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6901  int interceptor_call_count = 0;
6902  v8::HandleScope scope;
6903  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6904  v8::Handle<v8::FunctionTemplate> method_templ =
6905      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6906                                v8_str("method_data"),
6907                                v8::Signature::New(fun_templ));
6908  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6909  proto_templ->Set(v8_str("method"), method_templ);
6910  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6911  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6912                                 NULL, NULL, NULL, NULL,
6913                                 v8::External::Wrap(&interceptor_call_count));
6914  LocalContext context;
6915  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6916  GenerateSomeGarbage();
6917  context->Global()->Set(v8_str("o"), fun->NewInstance());
6918  v8::TryCatch try_catch;
6919  v8::Handle<Value> value = CompileRun(
6920      "o.foo = 17;"
6921      "var receiver = {};"
6922      "receiver.__proto__ = o;"
6923      "var result = 0;"
6924      "var saved_result = 0;"
6925      "for (var i = 0; i < 100; i++) {"
6926      "  result = receiver.method(41);"
6927      "  if (i == 50) {"
6928      "    saved_result = result;"
6929      "    receiver = {method: receiver.method};"
6930      "  }"
6931      "}");
6932  CHECK(try_catch.HasCaught());
6933  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
6934           try_catch.Exception()->ToString());
6935  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6936  CHECK_GE(interceptor_call_count, 50);
6937}
6938
6939THREADED_TEST(CallICFastApi_TrivialSignature) {
6940  v8::HandleScope scope;
6941  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6942  v8::Handle<v8::FunctionTemplate> method_templ =
6943      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6944                                v8_str("method_data"),
6945                                v8::Handle<v8::Signature>());
6946  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6947  proto_templ->Set(v8_str("method"), method_templ);
6948  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6949  LocalContext context;
6950  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6951  GenerateSomeGarbage();
6952  context->Global()->Set(v8_str("o"), fun->NewInstance());
6953  v8::Handle<Value> value = CompileRun(
6954      "var result = 0;"
6955      "for (var i = 0; i < 100; i++) {"
6956      "  result = o.method(41);"
6957      "}");
6958
6959  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6960}
6961
6962THREADED_TEST(CallICFastApi_SimpleSignature) {
6963  v8::HandleScope scope;
6964  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6965  v8::Handle<v8::FunctionTemplate> method_templ =
6966      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6967                                v8_str("method_data"),
6968                                v8::Signature::New(fun_templ));
6969  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6970  proto_templ->Set(v8_str("method"), method_templ);
6971  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6972  LocalContext context;
6973  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6974  GenerateSomeGarbage();
6975  context->Global()->Set(v8_str("o"), fun->NewInstance());
6976  v8::Handle<Value> value = CompileRun(
6977      "o.foo = 17;"
6978      "var receiver = {};"
6979      "receiver.__proto__ = o;"
6980      "var result = 0;"
6981      "for (var i = 0; i < 100; i++) {"
6982      "  result = receiver.method(41);"
6983      "}");
6984
6985  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6986}
6987
6988THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
6989  v8::HandleScope scope;
6990  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6991  v8::Handle<v8::FunctionTemplate> method_templ =
6992      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6993                                v8_str("method_data"),
6994                                v8::Signature::New(fun_templ));
6995  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6996  proto_templ->Set(v8_str("method"), method_templ);
6997  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6998  LocalContext context;
6999  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7000  GenerateSomeGarbage();
7001  context->Global()->Set(v8_str("o"), fun->NewInstance());
7002  v8::Handle<Value> value = CompileRun(
7003      "o.foo = 17;"
7004      "var receiver = {};"
7005      "receiver.__proto__ = o;"
7006      "var result = 0;"
7007      "var saved_result = 0;"
7008      "for (var i = 0; i < 100; i++) {"
7009      "  result = receiver.method(41);"
7010      "  if (i == 50) {"
7011      "    saved_result = result;"
7012      "    receiver = {method: function(x) { return x - 1 }};"
7013      "  }"
7014      "}");
7015  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7016  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7017}
7018
7019THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7020  v8::HandleScope scope;
7021  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7022  v8::Handle<v8::FunctionTemplate> method_templ =
7023      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7024                                v8_str("method_data"),
7025                                v8::Signature::New(fun_templ));
7026  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7027  proto_templ->Set(v8_str("method"), method_templ);
7028  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7029  LocalContext context;
7030  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7031  GenerateSomeGarbage();
7032  context->Global()->Set(v8_str("o"), fun->NewInstance());
7033  v8::TryCatch try_catch;
7034  v8::Handle<Value> value = CompileRun(
7035      "o.foo = 17;"
7036      "var receiver = {};"
7037      "receiver.__proto__ = o;"
7038      "var result = 0;"
7039      "var saved_result = 0;"
7040      "for (var i = 0; i < 100; i++) {"
7041      "  result = receiver.method(41);"
7042      "  if (i == 50) {"
7043      "    saved_result = result;"
7044      "    receiver = 333;"
7045      "  }"
7046      "}");
7047  CHECK(try_catch.HasCaught());
7048  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7049           try_catch.Exception()->ToString());
7050  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7051}
7052
7053
7054static int interceptor_call_count = 0;
7055
7056static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7057                                                     const AccessorInfo& info) {
7058  ApiTestFuzzer::Fuzz();
7059  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7060    return call_ic_function2;
7061  }
7062  return v8::Handle<Value>();
7063}
7064
7065
7066// This test should hit load and call ICs for the interceptor case.
7067// Once in a while, the interceptor will reply that a property was not
7068// found in which case we should get a reference error.
7069THREADED_TEST(InterceptorICReferenceErrors) {
7070  v8::HandleScope scope;
7071  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7072  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7073  LocalContext context(0, templ, v8::Handle<Value>());
7074  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7075  v8::Handle<Value> value = CompileRun(
7076    "function f() {"
7077    "  for (var i = 0; i < 1000; i++) {"
7078    "    try { x; } catch(e) { return true; }"
7079    "  }"
7080    "  return false;"
7081    "};"
7082    "f();");
7083  CHECK_EQ(true, value->BooleanValue());
7084  interceptor_call_count = 0;
7085  value = CompileRun(
7086    "function g() {"
7087    "  for (var i = 0; i < 1000; i++) {"
7088    "    try { x(42); } catch(e) { return true; }"
7089    "  }"
7090    "  return false;"
7091    "};"
7092    "g();");
7093  CHECK_EQ(true, value->BooleanValue());
7094}
7095
7096
7097static int interceptor_ic_exception_get_count = 0;
7098
7099static v8::Handle<Value> InterceptorICExceptionGetter(
7100    Local<String> name,
7101    const AccessorInfo& info) {
7102  ApiTestFuzzer::Fuzz();
7103  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7104    return call_ic_function3;
7105  }
7106  if (interceptor_ic_exception_get_count == 20) {
7107    return v8::ThrowException(v8_num(42));
7108  }
7109  // Do not handle get for properties other than x.
7110  return v8::Handle<Value>();
7111}
7112
7113// Test interceptor load/call IC where the interceptor throws an
7114// exception once in a while.
7115THREADED_TEST(InterceptorICGetterExceptions) {
7116  interceptor_ic_exception_get_count = 0;
7117  v8::HandleScope scope;
7118  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7119  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7120  LocalContext context(0, templ, v8::Handle<Value>());
7121  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7122  v8::Handle<Value> value = CompileRun(
7123    "function f() {"
7124    "  for (var i = 0; i < 100; i++) {"
7125    "    try { x; } catch(e) { return true; }"
7126    "  }"
7127    "  return false;"
7128    "};"
7129    "f();");
7130  CHECK_EQ(true, value->BooleanValue());
7131  interceptor_ic_exception_get_count = 0;
7132  value = CompileRun(
7133    "function f() {"
7134    "  for (var i = 0; i < 100; i++) {"
7135    "    try { x(42); } catch(e) { return true; }"
7136    "  }"
7137    "  return false;"
7138    "};"
7139    "f();");
7140  CHECK_EQ(true, value->BooleanValue());
7141}
7142
7143
7144static int interceptor_ic_exception_set_count = 0;
7145
7146static v8::Handle<Value> InterceptorICExceptionSetter(
7147      Local<String> key, Local<Value> value, const AccessorInfo&) {
7148  ApiTestFuzzer::Fuzz();
7149  if (++interceptor_ic_exception_set_count > 20) {
7150    return v8::ThrowException(v8_num(42));
7151  }
7152  // Do not actually handle setting.
7153  return v8::Handle<Value>();
7154}
7155
7156// Test interceptor store IC where the interceptor throws an exception
7157// once in a while.
7158THREADED_TEST(InterceptorICSetterExceptions) {
7159  interceptor_ic_exception_set_count = 0;
7160  v8::HandleScope scope;
7161  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7162  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7163  LocalContext context(0, templ, v8::Handle<Value>());
7164  v8::Handle<Value> value = CompileRun(
7165    "function f() {"
7166    "  for (var i = 0; i < 100; i++) {"
7167    "    try { x = 42; } catch(e) { return true; }"
7168    "  }"
7169    "  return false;"
7170    "};"
7171    "f();");
7172  CHECK_EQ(true, value->BooleanValue());
7173}
7174
7175
7176// Test that we ignore null interceptors.
7177THREADED_TEST(NullNamedInterceptor) {
7178  v8::HandleScope scope;
7179  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7180  templ->SetNamedPropertyHandler(0);
7181  LocalContext context;
7182  templ->Set("x", v8_num(42));
7183  v8::Handle<v8::Object> obj = templ->NewInstance();
7184  context->Global()->Set(v8_str("obj"), obj);
7185  v8::Handle<Value> value = CompileRun("obj.x");
7186  CHECK(value->IsInt32());
7187  CHECK_EQ(42, value->Int32Value());
7188}
7189
7190
7191// Test that we ignore null interceptors.
7192THREADED_TEST(NullIndexedInterceptor) {
7193  v8::HandleScope scope;
7194  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7195  templ->SetIndexedPropertyHandler(0);
7196  LocalContext context;
7197  templ->Set("42", v8_num(42));
7198  v8::Handle<v8::Object> obj = templ->NewInstance();
7199  context->Global()->Set(v8_str("obj"), obj);
7200  v8::Handle<Value> value = CompileRun("obj[42]");
7201  CHECK(value->IsInt32());
7202  CHECK_EQ(42, value->Int32Value());
7203}
7204
7205
7206static v8::Handle<Value> ParentGetter(Local<String> name,
7207                                      const AccessorInfo& info) {
7208  ApiTestFuzzer::Fuzz();
7209  return v8_num(1);
7210}
7211
7212
7213static v8::Handle<Value> ChildGetter(Local<String> name,
7214                                     const AccessorInfo& info) {
7215  ApiTestFuzzer::Fuzz();
7216  return v8_num(42);
7217}
7218
7219
7220THREADED_TEST(Overriding) {
7221  v8::HandleScope scope;
7222  LocalContext context;
7223
7224  // Parent template.
7225  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7226  Local<ObjectTemplate> parent_instance_templ =
7227      parent_templ->InstanceTemplate();
7228  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7229
7230  // Template that inherits from the parent template.
7231  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7232  Local<ObjectTemplate> child_instance_templ =
7233      child_templ->InstanceTemplate();
7234  child_templ->Inherit(parent_templ);
7235  // Override 'f'.  The child version of 'f' should get called for child
7236  // instances.
7237  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7238  // Add 'g' twice.  The 'g' added last should get called for instances.
7239  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7240  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7241
7242  // Add 'h' as an accessor to the proto template with ReadOnly attributes
7243  // so 'h' can be shadowed on the instance object.
7244  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7245  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7246      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7247
7248  // Add 'i' as an accessor to the instance template with ReadOnly attributes
7249  // but the attribute does not have effect because it is duplicated with
7250  // NULL setter.
7251  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7252      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7253
7254
7255
7256  // Instantiate the child template.
7257  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7258
7259  // Check that the child function overrides the parent one.
7260  context->Global()->Set(v8_str("o"), instance);
7261  Local<Value> value = v8_compile("o.f")->Run();
7262  // Check that the 'g' that was added last is hit.
7263  CHECK_EQ(42, value->Int32Value());
7264  value = v8_compile("o.g")->Run();
7265  CHECK_EQ(42, value->Int32Value());
7266
7267  // Check 'h' can be shadowed.
7268  value = v8_compile("o.h = 3; o.h")->Run();
7269  CHECK_EQ(3, value->Int32Value());
7270
7271  // Check 'i' is cannot be shadowed or changed.
7272  value = v8_compile("o.i = 3; o.i")->Run();
7273  CHECK_EQ(42, value->Int32Value());
7274}
7275
7276
7277static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7278  ApiTestFuzzer::Fuzz();
7279  if (args.IsConstructCall()) {
7280    return v8::Boolean::New(true);
7281  }
7282  return v8::Boolean::New(false);
7283}
7284
7285
7286THREADED_TEST(IsConstructCall) {
7287  v8::HandleScope scope;
7288
7289  // Function template with call handler.
7290  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7291  templ->SetCallHandler(IsConstructHandler);
7292
7293  LocalContext context;
7294
7295  context->Global()->Set(v8_str("f"), templ->GetFunction());
7296  Local<Value> value = v8_compile("f()")->Run();
7297  CHECK(!value->BooleanValue());
7298  value = v8_compile("new f()")->Run();
7299  CHECK(value->BooleanValue());
7300}
7301
7302
7303THREADED_TEST(ObjectProtoToString) {
7304  v8::HandleScope scope;
7305  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7306  templ->SetClassName(v8_str("MyClass"));
7307
7308  LocalContext context;
7309
7310  Local<String> customized_tostring = v8_str("customized toString");
7311
7312  // Replace Object.prototype.toString
7313  v8_compile("Object.prototype.toString = function() {"
7314                  "  return 'customized toString';"
7315                  "}")->Run();
7316
7317  // Normal ToString call should call replaced Object.prototype.toString
7318  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7319  Local<String> value = instance->ToString();
7320  CHECK(value->IsString() && value->Equals(customized_tostring));
7321
7322  // ObjectProtoToString should not call replace toString function.
7323  value = instance->ObjectProtoToString();
7324  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7325
7326  // Check global
7327  value = context->Global()->ObjectProtoToString();
7328  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7329
7330  // Check ordinary object
7331  Local<Value> object = v8_compile("new Object()")->Run();
7332  value = object.As<v8::Object>()->ObjectProtoToString();
7333  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7334}
7335
7336
7337bool ApiTestFuzzer::fuzzing_ = false;
7338v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
7339  v8::internal::OS::CreateSemaphore(0);
7340int ApiTestFuzzer::active_tests_;
7341int ApiTestFuzzer::tests_being_run_;
7342int ApiTestFuzzer::current_;
7343
7344
7345// We are in a callback and want to switch to another thread (if we
7346// are currently running the thread fuzzing test).
7347void ApiTestFuzzer::Fuzz() {
7348  if (!fuzzing_) return;
7349  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7350  test->ContextSwitch();
7351}
7352
7353
7354// Let the next thread go.  Since it is also waiting on the V8 lock it may
7355// not start immediately.
7356bool ApiTestFuzzer::NextThread() {
7357  int test_position = GetNextTestNumber();
7358  const char* test_name = RegisterThreadedTest::nth(current_)->name();
7359  if (test_position == current_) {
7360    if (kLogThreading)
7361      printf("Stay with %s\n", test_name);
7362    return false;
7363  }
7364  if (kLogThreading) {
7365    printf("Switch from %s to %s\n",
7366           test_name,
7367           RegisterThreadedTest::nth(test_position)->name());
7368  }
7369  current_ = test_position;
7370  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7371  return true;
7372}
7373
7374
7375void ApiTestFuzzer::Run() {
7376  // When it is our turn...
7377  gate_->Wait();
7378  {
7379    // ... get the V8 lock and start running the test.
7380    v8::Locker locker;
7381    CallTest();
7382  }
7383  // This test finished.
7384  active_ = false;
7385  active_tests_--;
7386  // If it was the last then signal that fact.
7387  if (active_tests_ == 0) {
7388    all_tests_done_->Signal();
7389  } else {
7390    // Otherwise select a new test and start that.
7391    NextThread();
7392  }
7393}
7394
7395
7396static unsigned linear_congruential_generator;
7397
7398
7399void ApiTestFuzzer::Setup(PartOfTest part) {
7400  linear_congruential_generator = i::FLAG_testing_prng_seed;
7401  fuzzing_ = true;
7402  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7403  int end = (part == FIRST_PART)
7404      ? (RegisterThreadedTest::count() >> 1)
7405      : RegisterThreadedTest::count();
7406  active_tests_ = tests_being_run_ = end - start;
7407  for (int i = 0; i < tests_being_run_; i++) {
7408    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7409  }
7410  for (int i = 0; i < active_tests_; i++) {
7411    RegisterThreadedTest::nth(i)->fuzzer_->Start();
7412  }
7413}
7414
7415
7416static void CallTestNumber(int test_number) {
7417  (RegisterThreadedTest::nth(test_number)->callback())();
7418}
7419
7420
7421void ApiTestFuzzer::RunAllTests() {
7422  // Set off the first test.
7423  current_ = -1;
7424  NextThread();
7425  // Wait till they are all done.
7426  all_tests_done_->Wait();
7427}
7428
7429
7430int ApiTestFuzzer::GetNextTestNumber() {
7431  int next_test;
7432  do {
7433    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7434    linear_congruential_generator *= 1664525u;
7435    linear_congruential_generator += 1013904223u;
7436  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7437  return next_test;
7438}
7439
7440
7441void ApiTestFuzzer::ContextSwitch() {
7442  // If the new thread is the same as the current thread there is nothing to do.
7443  if (NextThread()) {
7444    // Now it can start.
7445    v8::Unlocker unlocker;
7446    // Wait till someone starts us again.
7447    gate_->Wait();
7448    // And we're off.
7449  }
7450}
7451
7452
7453void ApiTestFuzzer::TearDown() {
7454  fuzzing_ = false;
7455  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7456    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7457    if (fuzzer != NULL) fuzzer->Join();
7458  }
7459}
7460
7461
7462// Lets not be needlessly self-referential.
7463TEST(Threading) {
7464  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7465  ApiTestFuzzer::RunAllTests();
7466  ApiTestFuzzer::TearDown();
7467}
7468
7469TEST(Threading2) {
7470  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7471  ApiTestFuzzer::RunAllTests();
7472  ApiTestFuzzer::TearDown();
7473}
7474
7475
7476void ApiTestFuzzer::CallTest() {
7477  if (kLogThreading)
7478    printf("Start test %d\n", test_number_);
7479  CallTestNumber(test_number_);
7480  if (kLogThreading)
7481    printf("End test %d\n", test_number_);
7482}
7483
7484
7485static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7486  CHECK(v8::Locker::IsLocked());
7487  ApiTestFuzzer::Fuzz();
7488  v8::Unlocker unlocker;
7489  const char* code = "throw 7;";
7490  {
7491    v8::Locker nested_locker;
7492    v8::HandleScope scope;
7493    v8::Handle<Value> exception;
7494    { v8::TryCatch try_catch;
7495      v8::Handle<Value> value = CompileRun(code);
7496      CHECK(value.IsEmpty());
7497      CHECK(try_catch.HasCaught());
7498      // Make sure to wrap the exception in a new handle because
7499      // the handle returned from the TryCatch is destroyed
7500      // when the TryCatch is destroyed.
7501      exception = Local<Value>::New(try_catch.Exception());
7502    }
7503    return v8::ThrowException(exception);
7504  }
7505}
7506
7507
7508static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7509  CHECK(v8::Locker::IsLocked());
7510  ApiTestFuzzer::Fuzz();
7511  v8::Unlocker unlocker;
7512  const char* code = "throw 7;";
7513  {
7514    v8::Locker nested_locker;
7515    v8::HandleScope scope;
7516    v8::Handle<Value> value = CompileRun(code);
7517    CHECK(value.IsEmpty());
7518    return v8_str("foo");
7519  }
7520}
7521
7522
7523// These are locking tests that don't need to be run again
7524// as part of the locking aggregation tests.
7525TEST(NestedLockers) {
7526  v8::Locker locker;
7527  CHECK(v8::Locker::IsLocked());
7528  v8::HandleScope scope;
7529  LocalContext env;
7530  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7531  Local<Function> fun = fun_templ->GetFunction();
7532  env->Global()->Set(v8_str("throw_in_js"), fun);
7533  Local<Script> script = v8_compile("(function () {"
7534                                    "  try {"
7535                                    "    throw_in_js();"
7536                                    "    return 42;"
7537                                    "  } catch (e) {"
7538                                    "    return e * 13;"
7539                                    "  }"
7540                                    "})();");
7541  CHECK_EQ(91, script->Run()->Int32Value());
7542}
7543
7544
7545// These are locking tests that don't need to be run again
7546// as part of the locking aggregation tests.
7547TEST(NestedLockersNoTryCatch) {
7548  v8::Locker locker;
7549  v8::HandleScope scope;
7550  LocalContext env;
7551  Local<v8::FunctionTemplate> fun_templ =
7552      v8::FunctionTemplate::New(ThrowInJSNoCatch);
7553  Local<Function> fun = fun_templ->GetFunction();
7554  env->Global()->Set(v8_str("throw_in_js"), fun);
7555  Local<Script> script = v8_compile("(function () {"
7556                                    "  try {"
7557                                    "    throw_in_js();"
7558                                    "    return 42;"
7559                                    "  } catch (e) {"
7560                                    "    return e * 13;"
7561                                    "  }"
7562                                    "})();");
7563  CHECK_EQ(91, script->Run()->Int32Value());
7564}
7565
7566
7567THREADED_TEST(RecursiveLocking) {
7568  v8::Locker locker;
7569  {
7570    v8::Locker locker2;
7571    CHECK(v8::Locker::IsLocked());
7572  }
7573}
7574
7575
7576static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7577  ApiTestFuzzer::Fuzz();
7578  v8::Unlocker unlocker;
7579  return v8::Undefined();
7580}
7581
7582
7583THREADED_TEST(LockUnlockLock) {
7584  {
7585    v8::Locker locker;
7586    v8::HandleScope scope;
7587    LocalContext env;
7588    Local<v8::FunctionTemplate> fun_templ =
7589        v8::FunctionTemplate::New(UnlockForAMoment);
7590    Local<Function> fun = fun_templ->GetFunction();
7591    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7592    Local<Script> script = v8_compile("(function () {"
7593                                      "  unlock_for_a_moment();"
7594                                      "  return 42;"
7595                                      "})();");
7596    CHECK_EQ(42, script->Run()->Int32Value());
7597  }
7598  {
7599    v8::Locker locker;
7600    v8::HandleScope scope;
7601    LocalContext env;
7602    Local<v8::FunctionTemplate> fun_templ =
7603        v8::FunctionTemplate::New(UnlockForAMoment);
7604    Local<Function> fun = fun_templ->GetFunction();
7605    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7606    Local<Script> script = v8_compile("(function () {"
7607                                      "  unlock_for_a_moment();"
7608                                      "  return 42;"
7609                                      "})();");
7610    CHECK_EQ(42, script->Run()->Int32Value());
7611  }
7612}
7613
7614
7615static int GetGlobalObjectsCount() {
7616  int count = 0;
7617  v8::internal::HeapIterator it;
7618  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7619    if (object->IsJSGlobalObject()) count++;
7620  return count;
7621}
7622
7623
7624static int GetSurvivingGlobalObjectsCount() {
7625  // We need to collect all garbage twice to be sure that everything
7626  // has been collected.  This is because inline caches are cleared in
7627  // the first garbage collection but some of the maps have already
7628  // been marked at that point.  Therefore some of the maps are not
7629  // collected until the second garbage collection.
7630  v8::internal::Heap::CollectAllGarbage(false);
7631  v8::internal::Heap::CollectAllGarbage(false);
7632  int count = GetGlobalObjectsCount();
7633#ifdef DEBUG
7634  if (count > 0) v8::internal::Heap::TracePathToGlobal();
7635#endif
7636  return count;
7637}
7638
7639
7640TEST(DontLeakGlobalObjects) {
7641  // Regression test for issues 1139850 and 1174891.
7642
7643  v8::V8::Initialize();
7644
7645  int count = GetSurvivingGlobalObjectsCount();
7646
7647  for (int i = 0; i < 5; i++) {
7648    { v8::HandleScope scope;
7649      LocalContext context;
7650    }
7651    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7652
7653    { v8::HandleScope scope;
7654      LocalContext context;
7655      v8_compile("Date")->Run();
7656    }
7657    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7658
7659    { v8::HandleScope scope;
7660      LocalContext context;
7661      v8_compile("/aaa/")->Run();
7662    }
7663    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7664
7665    { v8::HandleScope scope;
7666      const char* extension_list[] = { "v8/gc" };
7667      v8::ExtensionConfiguration extensions(1, extension_list);
7668      LocalContext context(&extensions);
7669      v8_compile("gc();")->Run();
7670    }
7671    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7672  }
7673}
7674
7675
7676v8::Persistent<v8::Object> some_object;
7677v8::Persistent<v8::Object> bad_handle;
7678
7679void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7680  v8::HandleScope scope;
7681  bad_handle = v8::Persistent<v8::Object>::New(some_object);
7682}
7683
7684
7685THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7686  LocalContext context;
7687
7688  v8::Persistent<v8::Object> handle1, handle2;
7689  {
7690    v8::HandleScope scope;
7691    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7692    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7693    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7694  }
7695  // Note: order is implementation dependent alas: currently
7696  // global handle nodes are processed by PostGarbageCollectionProcessing
7697  // in reverse allocation order, so if second allocated handle is deleted,
7698  // weak callback of the first handle would be able to 'reallocate' it.
7699  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7700  handle2.Dispose();
7701  i::Heap::CollectAllGarbage(false);
7702}
7703
7704
7705v8::Persistent<v8::Object> to_be_disposed;
7706
7707void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7708  to_be_disposed.Dispose();
7709  i::Heap::CollectAllGarbage(false);
7710}
7711
7712
7713THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7714  LocalContext context;
7715
7716  v8::Persistent<v8::Object> handle1, handle2;
7717  {
7718    v8::HandleScope scope;
7719    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7720    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7721  }
7722  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7723  to_be_disposed = handle2;
7724  i::Heap::CollectAllGarbage(false);
7725}
7726
7727void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7728  handle.Dispose();
7729}
7730
7731void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7732  v8::HandleScope scope;
7733  v8::Persistent<v8::Object>::New(v8::Object::New());
7734}
7735
7736
7737THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
7738  LocalContext context;
7739
7740  v8::Persistent<v8::Object> handle1, handle2, handle3;
7741  {
7742    v8::HandleScope scope;
7743    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
7744    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7745    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7746  }
7747  handle2.MakeWeak(NULL, DisposingCallback);
7748  handle3.MakeWeak(NULL, HandleCreatingCallback);
7749  i::Heap::CollectAllGarbage(false);
7750}
7751
7752
7753THREADED_TEST(CheckForCrossContextObjectLiterals) {
7754  v8::V8::Initialize();
7755
7756  const int nof = 2;
7757  const char* sources[nof] = {
7758    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
7759    "Object()"
7760  };
7761
7762  for (int i = 0; i < nof; i++) {
7763    const char* source = sources[i];
7764    { v8::HandleScope scope;
7765      LocalContext context;
7766      CompileRun(source);
7767    }
7768    { v8::HandleScope scope;
7769      LocalContext context;
7770      CompileRun(source);
7771    }
7772  }
7773}
7774
7775
7776static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
7777  v8::HandleScope inner;
7778  env->Enter();
7779  v8::Handle<Value> three = v8_num(3);
7780  v8::Handle<Value> value = inner.Close(three);
7781  env->Exit();
7782  return value;
7783}
7784
7785
7786THREADED_TEST(NestedHandleScopeAndContexts) {
7787  v8::HandleScope outer;
7788  v8::Persistent<Context> env = Context::New();
7789  env->Enter();
7790  v8::Handle<Value> value = NestedScope(env);
7791  v8::Handle<String> str = value->ToString();
7792  env->Exit();
7793  env.Dispose();
7794}
7795
7796
7797THREADED_TEST(ExternalAllocatedMemory) {
7798  v8::HandleScope outer;
7799  v8::Persistent<Context> env = Context::New();
7800  const int kSize = 1024*1024;
7801  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
7802  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
7803}
7804
7805
7806THREADED_TEST(DisposeEnteredContext) {
7807  v8::HandleScope scope;
7808  LocalContext outer;
7809  { v8::Persistent<v8::Context> inner = v8::Context::New();
7810    inner->Enter();
7811    inner.Dispose();
7812    inner.Clear();
7813    inner->Exit();
7814  }
7815}
7816
7817
7818// Regression test for issue 54, object templates with internal fields
7819// but no accessors or interceptors did not get their internal field
7820// count set on instances.
7821THREADED_TEST(Regress54) {
7822  v8::HandleScope outer;
7823  LocalContext context;
7824  static v8::Persistent<v8::ObjectTemplate> templ;
7825  if (templ.IsEmpty()) {
7826    v8::HandleScope inner;
7827    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
7828    local->SetInternalFieldCount(1);
7829    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
7830  }
7831  v8::Handle<v8::Object> result = templ->NewInstance();
7832  CHECK_EQ(1, result->InternalFieldCount());
7833}
7834
7835
7836// If part of the threaded tests, this test makes ThreadingTest fail
7837// on mac.
7838TEST(CatchStackOverflow) {
7839  v8::HandleScope scope;
7840  LocalContext context;
7841  v8::TryCatch try_catch;
7842  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
7843    "function f() {"
7844    "  return f();"
7845    "}"
7846    ""
7847    "f();"));
7848  v8::Handle<v8::Value> result = script->Run();
7849  CHECK(result.IsEmpty());
7850}
7851
7852
7853static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
7854                                    const char* resource_name,
7855                                    int line_offset) {
7856  v8::HandleScope scope;
7857  v8::TryCatch try_catch;
7858  v8::Handle<v8::Value> result = script->Run();
7859  CHECK(result.IsEmpty());
7860  CHECK(try_catch.HasCaught());
7861  v8::Handle<v8::Message> message = try_catch.Message();
7862  CHECK(!message.IsEmpty());
7863  CHECK_EQ(10 + line_offset, message->GetLineNumber());
7864  CHECK_EQ(91, message->GetStartPosition());
7865  CHECK_EQ(92, message->GetEndPosition());
7866  CHECK_EQ(2, message->GetStartColumn());
7867  CHECK_EQ(3, message->GetEndColumn());
7868  v8::String::AsciiValue line(message->GetSourceLine());
7869  CHECK_EQ("  throw 'nirk';", *line);
7870  v8::String::AsciiValue name(message->GetScriptResourceName());
7871  CHECK_EQ(resource_name, *name);
7872}
7873
7874
7875THREADED_TEST(TryCatchSourceInfo) {
7876  v8::HandleScope scope;
7877  LocalContext context;
7878  v8::Handle<v8::String> source = v8::String::New(
7879      "function Foo() {\n"
7880      "  return Bar();\n"
7881      "}\n"
7882      "\n"
7883      "function Bar() {\n"
7884      "  return Baz();\n"
7885      "}\n"
7886      "\n"
7887      "function Baz() {\n"
7888      "  throw 'nirk';\n"
7889      "}\n"
7890      "\n"
7891      "Foo();\n");
7892
7893  const char* resource_name;
7894  v8::Handle<v8::Script> script;
7895  resource_name = "test.js";
7896  script = v8::Script::Compile(source, v8::String::New(resource_name));
7897  CheckTryCatchSourceInfo(script, resource_name, 0);
7898
7899  resource_name = "test1.js";
7900  v8::ScriptOrigin origin1(v8::String::New(resource_name));
7901  script = v8::Script::Compile(source, &origin1);
7902  CheckTryCatchSourceInfo(script, resource_name, 0);
7903
7904  resource_name = "test2.js";
7905  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
7906  script = v8::Script::Compile(source, &origin2);
7907  CheckTryCatchSourceInfo(script, resource_name, 7);
7908}
7909
7910
7911THREADED_TEST(CompilationCache) {
7912  v8::HandleScope scope;
7913  LocalContext context;
7914  v8::Handle<v8::String> source0 = v8::String::New("1234");
7915  v8::Handle<v8::String> source1 = v8::String::New("1234");
7916  v8::Handle<v8::Script> script0 =
7917      v8::Script::Compile(source0, v8::String::New("test.js"));
7918  v8::Handle<v8::Script> script1 =
7919      v8::Script::Compile(source1, v8::String::New("test.js"));
7920  v8::Handle<v8::Script> script2 =
7921      v8::Script::Compile(source0);  // different origin
7922  CHECK_EQ(1234, script0->Run()->Int32Value());
7923  CHECK_EQ(1234, script1->Run()->Int32Value());
7924  CHECK_EQ(1234, script2->Run()->Int32Value());
7925}
7926
7927
7928static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
7929  ApiTestFuzzer::Fuzz();
7930  return v8_num(42);
7931}
7932
7933
7934THREADED_TEST(CallbackFunctionName) {
7935  v8::HandleScope scope;
7936  LocalContext context;
7937  Local<ObjectTemplate> t = ObjectTemplate::New();
7938  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
7939  context->Global()->Set(v8_str("obj"), t->NewInstance());
7940  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
7941  CHECK(value->IsString());
7942  v8::String::AsciiValue name(value);
7943  CHECK_EQ("asdf", *name);
7944}
7945
7946
7947THREADED_TEST(DateAccess) {
7948  v8::HandleScope scope;
7949  LocalContext context;
7950  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
7951  CHECK(date->IsDate());
7952  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
7953}
7954
7955
7956void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
7957  v8::Handle<v8::Object> obj = val.As<v8::Object>();
7958  v8::Handle<v8::Array> props = obj->GetPropertyNames();
7959  CHECK_EQ(elmc, props->Length());
7960  for (int i = 0; i < elmc; i++) {
7961    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
7962    CHECK_EQ(elmv[i], *elm);
7963  }
7964}
7965
7966
7967THREADED_TEST(PropertyEnumeration) {
7968  v8::HandleScope scope;
7969  LocalContext context;
7970  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
7971      "var result = [];"
7972      "result[0] = {};"
7973      "result[1] = {a: 1, b: 2};"
7974      "result[2] = [1, 2, 3];"
7975      "var proto = {x: 1, y: 2, z: 3};"
7976      "var x = { __proto__: proto, w: 0, z: 1 };"
7977      "result[3] = x;"
7978      "result;"))->Run();
7979  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
7980  CHECK_EQ(4, elms->Length());
7981  int elmc0 = 0;
7982  const char** elmv0 = NULL;
7983  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
7984  int elmc1 = 2;
7985  const char* elmv1[] = {"a", "b"};
7986  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
7987  int elmc2 = 3;
7988  const char* elmv2[] = {"0", "1", "2"};
7989  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
7990  int elmc3 = 4;
7991  const char* elmv3[] = {"w", "z", "x", "y"};
7992  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
7993}
7994
7995
7996static bool NamedSetAccessBlocker(Local<v8::Object> obj,
7997                                  Local<Value> name,
7998                                  v8::AccessType type,
7999                                  Local<Value> data) {
8000  return type != v8::ACCESS_SET;
8001}
8002
8003
8004static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8005                                    uint32_t key,
8006                                    v8::AccessType type,
8007                                    Local<Value> data) {
8008  return type != v8::ACCESS_SET;
8009}
8010
8011
8012THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8013  v8::HandleScope scope;
8014  LocalContext context;
8015  Local<ObjectTemplate> templ = ObjectTemplate::New();
8016  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8017                                 IndexedSetAccessBlocker);
8018  templ->Set(v8_str("x"), v8::True());
8019  Local<v8::Object> instance = templ->NewInstance();
8020  context->Global()->Set(v8_str("obj"), instance);
8021  Local<Value> value = CompileRun("obj.x");
8022  CHECK(value->BooleanValue());
8023}
8024
8025
8026static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8027                                  Local<Value> name,
8028                                  v8::AccessType type,
8029                                  Local<Value> data) {
8030  return false;
8031}
8032
8033
8034static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8035                                    uint32_t key,
8036                                    v8::AccessType type,
8037                                    Local<Value> data) {
8038  return false;
8039}
8040
8041
8042
8043THREADED_TEST(AccessChecksReenabledCorrectly) {
8044  v8::HandleScope scope;
8045  LocalContext context;
8046  Local<ObjectTemplate> templ = ObjectTemplate::New();
8047  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8048                                 IndexedGetAccessBlocker);
8049  templ->Set(v8_str("a"), v8_str("a"));
8050  // Add more than 8 (see kMaxFastProperties) properties
8051  // so that the constructor will force copying map.
8052  // Cannot sprintf, gcc complains unsafety.
8053  char buf[4];
8054  for (char i = '0'; i <= '9' ; i++) {
8055    buf[0] = i;
8056    for (char j = '0'; j <= '9'; j++) {
8057      buf[1] = j;
8058      for (char k = '0'; k <= '9'; k++) {
8059        buf[2] = k;
8060        buf[3] = 0;
8061        templ->Set(v8_str(buf), v8::Number::New(k));
8062      }
8063    }
8064  }
8065
8066  Local<v8::Object> instance_1 = templ->NewInstance();
8067  context->Global()->Set(v8_str("obj_1"), instance_1);
8068
8069  Local<Value> value_1 = CompileRun("obj_1.a");
8070  CHECK(value_1->IsUndefined());
8071
8072  Local<v8::Object> instance_2 = templ->NewInstance();
8073  context->Global()->Set(v8_str("obj_2"), instance_2);
8074
8075  Local<Value> value_2 = CompileRun("obj_2.a");
8076  CHECK(value_2->IsUndefined());
8077}
8078
8079
8080// This tests that access check information remains on the global
8081// object template when creating contexts.
8082THREADED_TEST(AccessControlRepeatedContextCreation) {
8083  v8::HandleScope handle_scope;
8084  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8085  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8086                                           IndexedSetAccessBlocker);
8087  i::Handle<i::ObjectTemplateInfo> internal_template =
8088      v8::Utils::OpenHandle(*global_template);
8089  CHECK(!internal_template->constructor()->IsUndefined());
8090  i::Handle<i::FunctionTemplateInfo> constructor(
8091      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8092  CHECK(!constructor->access_check_info()->IsUndefined());
8093  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8094  CHECK(!constructor->access_check_info()->IsUndefined());
8095}
8096
8097
8098THREADED_TEST(TurnOnAccessCheck) {
8099  v8::HandleScope handle_scope;
8100
8101  // Create an environment with access check to the global object disabled by
8102  // default.
8103  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8104  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8105                                           IndexedGetAccessBlocker,
8106                                           v8::Handle<v8::Value>(),
8107                                           false);
8108  v8::Persistent<Context> context = Context::New(NULL, global_template);
8109  Context::Scope context_scope(context);
8110
8111  // Set up a property and a number of functions.
8112  context->Global()->Set(v8_str("a"), v8_num(1));
8113  CompileRun("function f1() {return a;}"
8114             "function f2() {return a;}"
8115             "function g1() {return h();}"
8116             "function g2() {return h();}"
8117             "function h() {return 1;}");
8118  Local<Function> f1 =
8119      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8120  Local<Function> f2 =
8121      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8122  Local<Function> g1 =
8123      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8124  Local<Function> g2 =
8125      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8126  Local<Function> h =
8127      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8128
8129  // Get the global object.
8130  v8::Handle<v8::Object> global = context->Global();
8131
8132  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8133  // uses the runtime system to retreive property a whereas f2 uses global load
8134  // inline cache.
8135  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8136  for (int i = 0; i < 4; i++) {
8137    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8138  }
8139
8140  // Same for g1 and g2.
8141  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8142  for (int i = 0; i < 4; i++) {
8143    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8144  }
8145
8146  // Detach the global and turn on access check.
8147  context->DetachGlobal();
8148  context->Global()->TurnOnAccessCheck();
8149
8150  // Failing access check to property get results in undefined.
8151  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8152  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8153
8154  // Failing access check to function call results in exception.
8155  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8156  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8157
8158  // No failing access check when just returning a constant.
8159  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8160}
8161
8162
8163// This test verifies that pre-compilation (aka preparsing) can be called
8164// without initializing the whole VM. Thus we cannot run this test in a
8165// multi-threaded setup.
8166TEST(PreCompile) {
8167  // TODO(155): This test would break without the initialization of V8. This is
8168  // a workaround for now to make this test not fail.
8169  v8::V8::Initialize();
8170  const char* script = "function foo(a) { return a+1; }";
8171  v8::ScriptData* sd =
8172      v8::ScriptData::PreCompile(script, i::StrLength(script));
8173  CHECK_NE(sd->Length(), 0);
8174  CHECK_NE(sd->Data(), NULL);
8175  CHECK(!sd->HasError());
8176  delete sd;
8177}
8178
8179
8180TEST(PreCompileWithError) {
8181  v8::V8::Initialize();
8182  const char* script = "function foo(a) { return 1 * * 2; }";
8183  v8::ScriptData* sd =
8184      v8::ScriptData::PreCompile(script, i::StrLength(script));
8185  CHECK(sd->HasError());
8186  delete sd;
8187}
8188
8189
8190TEST(Regress31661) {
8191  v8::V8::Initialize();
8192  const char* script = " The Definintive Guide";
8193  v8::ScriptData* sd =
8194      v8::ScriptData::PreCompile(script, i::StrLength(script));
8195  CHECK(sd->HasError());
8196  delete sd;
8197}
8198
8199
8200// Tests that ScriptData can be serialized and deserialized.
8201TEST(PreCompileSerialization) {
8202  v8::V8::Initialize();
8203  const char* script = "function foo(a) { return a+1; }";
8204  v8::ScriptData* sd =
8205      v8::ScriptData::PreCompile(script, i::StrLength(script));
8206
8207  // Serialize.
8208  int serialized_data_length = sd->Length();
8209  char* serialized_data = i::NewArray<char>(serialized_data_length);
8210  memcpy(serialized_data, sd->Data(), serialized_data_length);
8211
8212  // Deserialize.
8213  v8::ScriptData* deserialized_sd =
8214      v8::ScriptData::New(serialized_data, serialized_data_length);
8215
8216  // Verify that the original is the same as the deserialized.
8217  CHECK_EQ(sd->Length(), deserialized_sd->Length());
8218  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
8219  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
8220
8221  delete sd;
8222  delete deserialized_sd;
8223}
8224
8225
8226// Attempts to deserialize bad data.
8227TEST(PreCompileDeserializationError) {
8228  v8::V8::Initialize();
8229  const char* data = "DONT CARE";
8230  int invalid_size = 3;
8231  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
8232
8233  CHECK_EQ(0, sd->Length());
8234
8235  delete sd;
8236}
8237
8238
8239// This tests that we do not allow dictionary load/call inline caches
8240// to use functions that have not yet been compiled.  The potential
8241// problem of loading a function that has not yet been compiled can
8242// arise because we share code between contexts via the compilation
8243// cache.
8244THREADED_TEST(DictionaryICLoadedFunction) {
8245  v8::HandleScope scope;
8246  // Test LoadIC.
8247  for (int i = 0; i < 2; i++) {
8248    LocalContext context;
8249    context->Global()->Set(v8_str("tmp"), v8::True());
8250    context->Global()->Delete(v8_str("tmp"));
8251    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8252  }
8253  // Test CallIC.
8254  for (int i = 0; i < 2; i++) {
8255    LocalContext context;
8256    context->Global()->Set(v8_str("tmp"), v8::True());
8257    context->Global()->Delete(v8_str("tmp"));
8258    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8259  }
8260}
8261
8262
8263// Test that cross-context new calls use the context of the callee to
8264// create the new JavaScript object.
8265THREADED_TEST(CrossContextNew) {
8266  v8::HandleScope scope;
8267  v8::Persistent<Context> context0 = Context::New();
8268  v8::Persistent<Context> context1 = Context::New();
8269
8270  // Allow cross-domain access.
8271  Local<String> token = v8_str("<security token>");
8272  context0->SetSecurityToken(token);
8273  context1->SetSecurityToken(token);
8274
8275  // Set an 'x' property on the Object prototype and define a
8276  // constructor function in context0.
8277  context0->Enter();
8278  CompileRun("Object.prototype.x = 42; function C() {};");
8279  context0->Exit();
8280
8281  // Call the constructor function from context0 and check that the
8282  // result has the 'x' property.
8283  context1->Enter();
8284  context1->Global()->Set(v8_str("other"), context0->Global());
8285  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8286  CHECK(value->IsInt32());
8287  CHECK_EQ(42, value->Int32Value());
8288  context1->Exit();
8289
8290  // Dispose the contexts to allow them to be garbage collected.
8291  context0.Dispose();
8292  context1.Dispose();
8293}
8294
8295
8296class RegExpInterruptTest {
8297 public:
8298  RegExpInterruptTest() : block_(NULL) {}
8299  ~RegExpInterruptTest() { delete block_; }
8300  void RunTest() {
8301    block_ = i::OS::CreateSemaphore(0);
8302    gc_count_ = 0;
8303    gc_during_regexp_ = 0;
8304    regexp_success_ = false;
8305    gc_success_ = false;
8306    GCThread gc_thread(this);
8307    gc_thread.Start();
8308    v8::Locker::StartPreemption(1);
8309
8310    LongRunningRegExp();
8311    {
8312      v8::Unlocker unlock;
8313      gc_thread.Join();
8314    }
8315    v8::Locker::StopPreemption();
8316    CHECK(regexp_success_);
8317    CHECK(gc_success_);
8318  }
8319 private:
8320  // Number of garbage collections required.
8321  static const int kRequiredGCs = 5;
8322
8323  class GCThread : public i::Thread {
8324   public:
8325    explicit GCThread(RegExpInterruptTest* test)
8326        : test_(test) {}
8327    virtual void Run() {
8328      test_->CollectGarbage();
8329    }
8330   private:
8331     RegExpInterruptTest* test_;
8332  };
8333
8334  void CollectGarbage() {
8335    block_->Wait();
8336    while (gc_during_regexp_ < kRequiredGCs) {
8337      {
8338        v8::Locker lock;
8339        // TODO(lrn): Perhaps create some garbage before collecting.
8340        i::Heap::CollectAllGarbage(false);
8341        gc_count_++;
8342      }
8343      i::OS::Sleep(1);
8344    }
8345    gc_success_ = true;
8346  }
8347
8348  void LongRunningRegExp() {
8349    block_->Signal();  // Enable garbage collection thread on next preemption.
8350    int rounds = 0;
8351    while (gc_during_regexp_ < kRequiredGCs) {
8352      int gc_before = gc_count_;
8353      {
8354        // Match 15-30 "a"'s against 14 and a "b".
8355        const char* c_source =
8356            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8357            ".exec('aaaaaaaaaaaaaaab') === null";
8358        Local<String> source = String::New(c_source);
8359        Local<Script> script = Script::Compile(source);
8360        Local<Value> result = script->Run();
8361        if (!result->BooleanValue()) {
8362          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
8363          return;
8364        }
8365      }
8366      {
8367        // Match 15-30 "a"'s against 15 and a "b".
8368        const char* c_source =
8369            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8370            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8371        Local<String> source = String::New(c_source);
8372        Local<Script> script = Script::Compile(source);
8373        Local<Value> result = script->Run();
8374        if (!result->BooleanValue()) {
8375          gc_during_regexp_ = kRequiredGCs;
8376          return;
8377        }
8378      }
8379      int gc_after = gc_count_;
8380      gc_during_regexp_ += gc_after - gc_before;
8381      rounds++;
8382      i::OS::Sleep(1);
8383    }
8384    regexp_success_ = true;
8385  }
8386
8387  i::Semaphore* block_;
8388  int gc_count_;
8389  int gc_during_regexp_;
8390  bool regexp_success_;
8391  bool gc_success_;
8392};
8393
8394
8395// Test that a regular expression execution can be interrupted and
8396// survive a garbage collection.
8397TEST(RegExpInterruption) {
8398  v8::Locker lock;
8399  v8::V8::Initialize();
8400  v8::HandleScope scope;
8401  Local<Context> local_env;
8402  {
8403    LocalContext env;
8404    local_env = env.local();
8405  }
8406
8407  // Local context should still be live.
8408  CHECK(!local_env.IsEmpty());
8409  local_env->Enter();
8410
8411  // Should complete without problems.
8412  RegExpInterruptTest().RunTest();
8413
8414  local_env->Exit();
8415}
8416
8417
8418class ApplyInterruptTest {
8419 public:
8420  ApplyInterruptTest() : block_(NULL) {}
8421  ~ApplyInterruptTest() { delete block_; }
8422  void RunTest() {
8423    block_ = i::OS::CreateSemaphore(0);
8424    gc_count_ = 0;
8425    gc_during_apply_ = 0;
8426    apply_success_ = false;
8427    gc_success_ = false;
8428    GCThread gc_thread(this);
8429    gc_thread.Start();
8430    v8::Locker::StartPreemption(1);
8431
8432    LongRunningApply();
8433    {
8434      v8::Unlocker unlock;
8435      gc_thread.Join();
8436    }
8437    v8::Locker::StopPreemption();
8438    CHECK(apply_success_);
8439    CHECK(gc_success_);
8440  }
8441 private:
8442  // Number of garbage collections required.
8443  static const int kRequiredGCs = 2;
8444
8445  class GCThread : public i::Thread {
8446   public:
8447    explicit GCThread(ApplyInterruptTest* test)
8448        : test_(test) {}
8449    virtual void Run() {
8450      test_->CollectGarbage();
8451    }
8452   private:
8453     ApplyInterruptTest* test_;
8454  };
8455
8456  void CollectGarbage() {
8457    block_->Wait();
8458    while (gc_during_apply_ < kRequiredGCs) {
8459      {
8460        v8::Locker lock;
8461        i::Heap::CollectAllGarbage(false);
8462        gc_count_++;
8463      }
8464      i::OS::Sleep(1);
8465    }
8466    gc_success_ = true;
8467  }
8468
8469  void LongRunningApply() {
8470    block_->Signal();
8471    int rounds = 0;
8472    while (gc_during_apply_ < kRequiredGCs) {
8473      int gc_before = gc_count_;
8474      {
8475        const char* c_source =
8476            "function do_very_little(bar) {"
8477            "  this.foo = bar;"
8478            "}"
8479            "for (var i = 0; i < 100000; i++) {"
8480            "  do_very_little.apply(this, ['bar']);"
8481            "}";
8482        Local<String> source = String::New(c_source);
8483        Local<Script> script = Script::Compile(source);
8484        Local<Value> result = script->Run();
8485        // Check that no exception was thrown.
8486        CHECK(!result.IsEmpty());
8487      }
8488      int gc_after = gc_count_;
8489      gc_during_apply_ += gc_after - gc_before;
8490      rounds++;
8491    }
8492    apply_success_ = true;
8493  }
8494
8495  i::Semaphore* block_;
8496  int gc_count_;
8497  int gc_during_apply_;
8498  bool apply_success_;
8499  bool gc_success_;
8500};
8501
8502
8503// Test that nothing bad happens if we get a preemption just when we were
8504// about to do an apply().
8505TEST(ApplyInterruption) {
8506  v8::Locker lock;
8507  v8::V8::Initialize();
8508  v8::HandleScope scope;
8509  Local<Context> local_env;
8510  {
8511    LocalContext env;
8512    local_env = env.local();
8513  }
8514
8515  // Local context should still be live.
8516  CHECK(!local_env.IsEmpty());
8517  local_env->Enter();
8518
8519  // Should complete without problems.
8520  ApplyInterruptTest().RunTest();
8521
8522  local_env->Exit();
8523}
8524
8525
8526// Verify that we can clone an object
8527TEST(ObjectClone) {
8528  v8::HandleScope scope;
8529  LocalContext env;
8530
8531  const char* sample =
8532    "var rv = {};"      \
8533    "rv.alpha = 'hello';" \
8534    "rv.beta = 123;"     \
8535    "rv;";
8536
8537  // Create an object, verify basics.
8538  Local<Value> val = CompileRun(sample);
8539  CHECK(val->IsObject());
8540  Local<v8::Object> obj = val.As<v8::Object>();
8541  obj->Set(v8_str("gamma"), v8_str("cloneme"));
8542
8543  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8544  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8545  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8546
8547  // Clone it.
8548  Local<v8::Object> clone = obj->Clone();
8549  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8550  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8551  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8552
8553  // Set a property on the clone, verify each object.
8554  clone->Set(v8_str("beta"), v8::Integer::New(456));
8555  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8556  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8557}
8558
8559
8560class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8561 public:
8562  explicit AsciiVectorResource(i::Vector<const char> vector)
8563      : data_(vector) {}
8564  virtual ~AsciiVectorResource() {}
8565  virtual size_t length() const { return data_.length(); }
8566  virtual const char* data() const { return data_.start(); }
8567 private:
8568  i::Vector<const char> data_;
8569};
8570
8571
8572class UC16VectorResource : public v8::String::ExternalStringResource {
8573 public:
8574  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8575      : data_(vector) {}
8576  virtual ~UC16VectorResource() {}
8577  virtual size_t length() const { return data_.length(); }
8578  virtual const i::uc16* data() const { return data_.start(); }
8579 private:
8580  i::Vector<const i::uc16> data_;
8581};
8582
8583
8584static void MorphAString(i::String* string,
8585                         AsciiVectorResource* ascii_resource,
8586                         UC16VectorResource* uc16_resource) {
8587  CHECK(i::StringShape(string).IsExternal());
8588  if (string->IsAsciiRepresentation()) {
8589    // Check old map is not symbol or long.
8590    CHECK(string->map() == i::Heap::external_ascii_string_map());
8591    // Morph external string to be TwoByte string.
8592    string->set_map(i::Heap::external_string_map());
8593    i::ExternalTwoByteString* morphed =
8594         i::ExternalTwoByteString::cast(string);
8595    morphed->set_resource(uc16_resource);
8596  } else {
8597    // Check old map is not symbol or long.
8598    CHECK(string->map() == i::Heap::external_string_map());
8599    // Morph external string to be ASCII string.
8600    string->set_map(i::Heap::external_ascii_string_map());
8601    i::ExternalAsciiString* morphed =
8602         i::ExternalAsciiString::cast(string);
8603    morphed->set_resource(ascii_resource);
8604  }
8605}
8606
8607
8608// Test that we can still flatten a string if the components it is built up
8609// from have been turned into 16 bit strings in the mean time.
8610THREADED_TEST(MorphCompositeStringTest) {
8611  const char* c_string = "Now is the time for all good men"
8612                         " to come to the aid of the party";
8613  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8614  {
8615    v8::HandleScope scope;
8616    LocalContext env;
8617    AsciiVectorResource ascii_resource(
8618        i::Vector<const char>(c_string, i::StrLength(c_string)));
8619    UC16VectorResource uc16_resource(
8620        i::Vector<const uint16_t>(two_byte_string,
8621                                  i::StrLength(c_string)));
8622
8623    Local<String> lhs(v8::Utils::ToLocal(
8624        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8625    Local<String> rhs(v8::Utils::ToLocal(
8626        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8627
8628    env->Global()->Set(v8_str("lhs"), lhs);
8629    env->Global()->Set(v8_str("rhs"), rhs);
8630
8631    CompileRun(
8632        "var cons = lhs + rhs;"
8633        "var slice = lhs.substring(1, lhs.length - 1);"
8634        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8635
8636    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8637    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8638
8639    // Now do some stuff to make sure the strings are flattened, etc.
8640    CompileRun(
8641        "/[^a-z]/.test(cons);"
8642        "/[^a-z]/.test(slice);"
8643        "/[^a-z]/.test(slice_on_cons);");
8644    const char* expected_cons =
8645        "Now is the time for all good men to come to the aid of the party"
8646        "Now is the time for all good men to come to the aid of the party";
8647    const char* expected_slice =
8648        "ow is the time for all good men to come to the aid of the part";
8649    const char* expected_slice_on_cons =
8650        "ow is the time for all good men to come to the aid of the party"
8651        "Now is the time for all good men to come to the aid of the part";
8652    CHECK_EQ(String::New(expected_cons),
8653             env->Global()->Get(v8_str("cons")));
8654    CHECK_EQ(String::New(expected_slice),
8655             env->Global()->Get(v8_str("slice")));
8656    CHECK_EQ(String::New(expected_slice_on_cons),
8657             env->Global()->Get(v8_str("slice_on_cons")));
8658  }
8659}
8660
8661
8662TEST(CompileExternalTwoByteSource) {
8663  v8::HandleScope scope;
8664  LocalContext context;
8665
8666  // This is a very short list of sources, which currently is to check for a
8667  // regression caused by r2703.
8668  const char* ascii_sources[] = {
8669    "0.5",
8670    "-0.5",   // This mainly testes PushBack in the Scanner.
8671    "--0.5",  // This mainly testes PushBack in the Scanner.
8672    NULL
8673  };
8674
8675  // Compile the sources as external two byte strings.
8676  for (int i = 0; ascii_sources[i] != NULL; i++) {
8677    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8678    UC16VectorResource uc16_resource(
8679        i::Vector<const uint16_t>(two_byte_string,
8680                                  i::StrLength(ascii_sources[i])));
8681    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8682    v8::Script::Compile(source);
8683  }
8684}
8685
8686
8687class RegExpStringModificationTest {
8688 public:
8689  RegExpStringModificationTest()
8690      : block_(i::OS::CreateSemaphore(0)),
8691        morphs_(0),
8692        morphs_during_regexp_(0),
8693        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8694        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
8695  ~RegExpStringModificationTest() { delete block_; }
8696  void RunTest() {
8697    regexp_success_ = false;
8698    morph_success_ = false;
8699
8700    // Initialize the contents of two_byte_content_ to be a uc16 representation
8701    // of "aaaaaaaaaaaaaab".
8702    for (int i = 0; i < 14; i++) {
8703      two_byte_content_[i] = 'a';
8704    }
8705    two_byte_content_[14] = 'b';
8706
8707    // Create the input string for the regexp - the one we are going to change
8708    // properties of.
8709    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8710
8711    // Inject the input as a global variable.
8712    i::Handle<i::String> input_name =
8713        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
8714    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
8715
8716
8717    MorphThread morph_thread(this);
8718    morph_thread.Start();
8719    v8::Locker::StartPreemption(1);
8720    LongRunningRegExp();
8721    {
8722      v8::Unlocker unlock;
8723      morph_thread.Join();
8724    }
8725    v8::Locker::StopPreemption();
8726    CHECK(regexp_success_);
8727    CHECK(morph_success_);
8728  }
8729 private:
8730
8731  // Number of string modifications required.
8732  static const int kRequiredModifications = 5;
8733  static const int kMaxModifications = 100;
8734
8735  class MorphThread : public i::Thread {
8736   public:
8737    explicit MorphThread(RegExpStringModificationTest* test)
8738        : test_(test) {}
8739    virtual void Run() {
8740      test_->MorphString();
8741    }
8742   private:
8743     RegExpStringModificationTest* test_;
8744  };
8745
8746  void MorphString() {
8747    block_->Wait();
8748    while (morphs_during_regexp_ < kRequiredModifications &&
8749           morphs_ < kMaxModifications) {
8750      {
8751        v8::Locker lock;
8752        // Swap string between ascii and two-byte representation.
8753        i::String* string = *input_;
8754        MorphAString(string, &ascii_resource_, &uc16_resource_);
8755        morphs_++;
8756      }
8757      i::OS::Sleep(1);
8758    }
8759    morph_success_ = true;
8760  }
8761
8762  void LongRunningRegExp() {
8763    block_->Signal();  // Enable morphing thread on next preemption.
8764    while (morphs_during_regexp_ < kRequiredModifications &&
8765           morphs_ < kMaxModifications) {
8766      int morphs_before = morphs_;
8767      {
8768        // Match 15-30 "a"'s against 14 and a "b".
8769        const char* c_source =
8770            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8771            ".exec(input) === null";
8772        Local<String> source = String::New(c_source);
8773        Local<Script> script = Script::Compile(source);
8774        Local<Value> result = script->Run();
8775        CHECK(result->IsTrue());
8776      }
8777      int morphs_after = morphs_;
8778      morphs_during_regexp_ += morphs_after - morphs_before;
8779    }
8780    regexp_success_ = true;
8781  }
8782
8783  i::uc16 two_byte_content_[15];
8784  i::Semaphore* block_;
8785  int morphs_;
8786  int morphs_during_regexp_;
8787  bool regexp_success_;
8788  bool morph_success_;
8789  i::Handle<i::String> input_;
8790  AsciiVectorResource ascii_resource_;
8791  UC16VectorResource uc16_resource_;
8792};
8793
8794
8795// Test that a regular expression execution can be interrupted and
8796// the string changed without failing.
8797TEST(RegExpStringModification) {
8798  v8::Locker lock;
8799  v8::V8::Initialize();
8800  v8::HandleScope scope;
8801  Local<Context> local_env;
8802  {
8803    LocalContext env;
8804    local_env = env.local();
8805  }
8806
8807  // Local context should still be live.
8808  CHECK(!local_env.IsEmpty());
8809  local_env->Enter();
8810
8811  // Should complete without problems.
8812  RegExpStringModificationTest().RunTest();
8813
8814  local_env->Exit();
8815}
8816
8817
8818// Test that we can set a property on the global object even if there
8819// is a read-only property in the prototype chain.
8820TEST(ReadOnlyPropertyInGlobalProto) {
8821  v8::HandleScope scope;
8822  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8823  LocalContext context(0, templ);
8824  v8::Handle<v8::Object> global = context->Global();
8825  v8::Handle<v8::Object> global_proto =
8826      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
8827  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
8828  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
8829  // Check without 'eval' or 'with'.
8830  v8::Handle<v8::Value> res =
8831      CompileRun("function f() { x = 42; return x; }; f()");
8832  // Check with 'eval'.
8833  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
8834  CHECK_EQ(v8::Integer::New(42), res);
8835  // Check with 'with'.
8836  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
8837  CHECK_EQ(v8::Integer::New(42), res);
8838}
8839
8840static int force_set_set_count = 0;
8841static int force_set_get_count = 0;
8842bool pass_on_get = false;
8843
8844static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
8845                                            const v8::AccessorInfo& info) {
8846  force_set_get_count++;
8847  if (pass_on_get) {
8848    return v8::Handle<v8::Value>();
8849  } else {
8850    return v8::Int32::New(3);
8851  }
8852}
8853
8854static void ForceSetSetter(v8::Local<v8::String> name,
8855                           v8::Local<v8::Value> value,
8856                           const v8::AccessorInfo& info) {
8857  force_set_set_count++;
8858}
8859
8860static v8::Handle<v8::Value> ForceSetInterceptSetter(
8861    v8::Local<v8::String> name,
8862    v8::Local<v8::Value> value,
8863    const v8::AccessorInfo& info) {
8864  force_set_set_count++;
8865  return v8::Undefined();
8866}
8867
8868TEST(ForceSet) {
8869  force_set_get_count = 0;
8870  force_set_set_count = 0;
8871  pass_on_get = false;
8872
8873  v8::HandleScope scope;
8874  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8875  v8::Handle<v8::String> access_property = v8::String::New("a");
8876  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
8877  LocalContext context(NULL, templ);
8878  v8::Handle<v8::Object> global = context->Global();
8879
8880  // Ordinary properties
8881  v8::Handle<v8::String> simple_property = v8::String::New("p");
8882  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
8883  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8884  // This should fail because the property is read-only
8885  global->Set(simple_property, v8::Int32::New(5));
8886  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8887  // This should succeed even though the property is read-only
8888  global->ForceSet(simple_property, v8::Int32::New(6));
8889  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
8890
8891  // Accessors
8892  CHECK_EQ(0, force_set_set_count);
8893  CHECK_EQ(0, force_set_get_count);
8894  CHECK_EQ(3, global->Get(access_property)->Int32Value());
8895  // CHECK_EQ the property shouldn't override it, just call the setter
8896  // which in this case does nothing.
8897  global->Set(access_property, v8::Int32::New(7));
8898  CHECK_EQ(3, global->Get(access_property)->Int32Value());
8899  CHECK_EQ(1, force_set_set_count);
8900  CHECK_EQ(2, force_set_get_count);
8901  // Forcing the property to be set should override the accessor without
8902  // calling it
8903  global->ForceSet(access_property, v8::Int32::New(8));
8904  CHECK_EQ(8, global->Get(access_property)->Int32Value());
8905  CHECK_EQ(1, force_set_set_count);
8906  CHECK_EQ(2, force_set_get_count);
8907}
8908
8909TEST(ForceSetWithInterceptor) {
8910  force_set_get_count = 0;
8911  force_set_set_count = 0;
8912  pass_on_get = false;
8913
8914  v8::HandleScope scope;
8915  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8916  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
8917  LocalContext context(NULL, templ);
8918  v8::Handle<v8::Object> global = context->Global();
8919
8920  v8::Handle<v8::String> some_property = v8::String::New("a");
8921  CHECK_EQ(0, force_set_set_count);
8922  CHECK_EQ(0, force_set_get_count);
8923  CHECK_EQ(3, global->Get(some_property)->Int32Value());
8924  // Setting the property shouldn't override it, just call the setter
8925  // which in this case does nothing.
8926  global->Set(some_property, v8::Int32::New(7));
8927  CHECK_EQ(3, global->Get(some_property)->Int32Value());
8928  CHECK_EQ(1, force_set_set_count);
8929  CHECK_EQ(2, force_set_get_count);
8930  // Getting the property when the interceptor returns an empty handle
8931  // should yield undefined, since the property isn't present on the
8932  // object itself yet.
8933  pass_on_get = true;
8934  CHECK(global->Get(some_property)->IsUndefined());
8935  CHECK_EQ(1, force_set_set_count);
8936  CHECK_EQ(3, force_set_get_count);
8937  // Forcing the property to be set should cause the value to be
8938  // set locally without calling the interceptor.
8939  global->ForceSet(some_property, v8::Int32::New(8));
8940  CHECK_EQ(8, global->Get(some_property)->Int32Value());
8941  CHECK_EQ(1, force_set_set_count);
8942  CHECK_EQ(4, force_set_get_count);
8943  // Reenabling the interceptor should cause it to take precedence over
8944  // the property
8945  pass_on_get = false;
8946  CHECK_EQ(3, global->Get(some_property)->Int32Value());
8947  CHECK_EQ(1, force_set_set_count);
8948  CHECK_EQ(5, force_set_get_count);
8949  // The interceptor should also work for other properties
8950  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
8951  CHECK_EQ(1, force_set_set_count);
8952  CHECK_EQ(6, force_set_get_count);
8953}
8954
8955
8956THREADED_TEST(ForceDelete) {
8957  v8::HandleScope scope;
8958  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8959  LocalContext context(NULL, templ);
8960  v8::Handle<v8::Object> global = context->Global();
8961
8962  // Ordinary properties
8963  v8::Handle<v8::String> simple_property = v8::String::New("p");
8964  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
8965  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8966  // This should fail because the property is dont-delete.
8967  CHECK(!global->Delete(simple_property));
8968  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8969  // This should succeed even though the property is dont-delete.
8970  CHECK(global->ForceDelete(simple_property));
8971  CHECK(global->Get(simple_property)->IsUndefined());
8972}
8973
8974
8975static int force_delete_interceptor_count = 0;
8976static bool pass_on_delete = false;
8977
8978
8979static v8::Handle<v8::Boolean> ForceDeleteDeleter(
8980    v8::Local<v8::String> name,
8981    const v8::AccessorInfo& info) {
8982  force_delete_interceptor_count++;
8983  if (pass_on_delete) {
8984    return v8::Handle<v8::Boolean>();
8985  } else {
8986    return v8::True();
8987  }
8988}
8989
8990
8991THREADED_TEST(ForceDeleteWithInterceptor) {
8992  force_delete_interceptor_count = 0;
8993  pass_on_delete = false;
8994
8995  v8::HandleScope scope;
8996  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8997  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
8998  LocalContext context(NULL, templ);
8999  v8::Handle<v8::Object> global = context->Global();
9000
9001  v8::Handle<v8::String> some_property = v8::String::New("a");
9002  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9003
9004  // Deleting a property should get intercepted and nothing should
9005  // happen.
9006  CHECK_EQ(0, force_delete_interceptor_count);
9007  CHECK(global->Delete(some_property));
9008  CHECK_EQ(1, force_delete_interceptor_count);
9009  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9010  // Deleting the property when the interceptor returns an empty
9011  // handle should not delete the property since it is DontDelete.
9012  pass_on_delete = true;
9013  CHECK(!global->Delete(some_property));
9014  CHECK_EQ(2, force_delete_interceptor_count);
9015  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9016  // Forcing the property to be deleted should delete the value
9017  // without calling the interceptor.
9018  CHECK(global->ForceDelete(some_property));
9019  CHECK(global->Get(some_property)->IsUndefined());
9020  CHECK_EQ(2, force_delete_interceptor_count);
9021}
9022
9023
9024// Make sure that forcing a delete invalidates any IC stubs, so we
9025// don't read the hole value.
9026THREADED_TEST(ForceDeleteIC) {
9027  v8::HandleScope scope;
9028  LocalContext context;
9029  // Create a DontDelete variable on the global object.
9030  CompileRun("this.__proto__ = { foo: 'horse' };"
9031             "var foo = 'fish';"
9032             "function f() { return foo.length; }");
9033  // Initialize the IC for foo in f.
9034  CompileRun("for (var i = 0; i < 4; i++) f();");
9035  // Make sure the value of foo is correct before the deletion.
9036  CHECK_EQ(4, CompileRun("f()")->Int32Value());
9037  // Force the deletion of foo.
9038  CHECK(context->Global()->ForceDelete(v8_str("foo")));
9039  // Make sure the value for foo is read from the prototype, and that
9040  // we don't get in trouble with reading the deleted cell value
9041  // sentinel.
9042  CHECK_EQ(5, CompileRun("f()")->Int32Value());
9043}
9044
9045
9046v8::Persistent<Context> calling_context0;
9047v8::Persistent<Context> calling_context1;
9048v8::Persistent<Context> calling_context2;
9049
9050
9051// Check that the call to the callback is initiated in
9052// calling_context2, the directly calling context is calling_context1
9053// and the callback itself is in calling_context0.
9054static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9055  ApiTestFuzzer::Fuzz();
9056  CHECK(Context::GetCurrent() == calling_context0);
9057  CHECK(Context::GetCalling() == calling_context1);
9058  CHECK(Context::GetEntered() == calling_context2);
9059  return v8::Integer::New(42);
9060}
9061
9062
9063THREADED_TEST(GetCallingContext) {
9064  v8::HandleScope scope;
9065
9066  calling_context0 = Context::New();
9067  calling_context1 = Context::New();
9068  calling_context2 = Context::New();
9069
9070  // Allow cross-domain access.
9071  Local<String> token = v8_str("<security token>");
9072  calling_context0->SetSecurityToken(token);
9073  calling_context1->SetSecurityToken(token);
9074  calling_context2->SetSecurityToken(token);
9075
9076  // Create an object with a C++ callback in context0.
9077  calling_context0->Enter();
9078  Local<v8::FunctionTemplate> callback_templ =
9079      v8::FunctionTemplate::New(GetCallingContextCallback);
9080  calling_context0->Global()->Set(v8_str("callback"),
9081                                  callback_templ->GetFunction());
9082  calling_context0->Exit();
9083
9084  // Expose context0 in context1 and setup a function that calls the
9085  // callback function.
9086  calling_context1->Enter();
9087  calling_context1->Global()->Set(v8_str("context0"),
9088                                  calling_context0->Global());
9089  CompileRun("function f() { context0.callback() }");
9090  calling_context1->Exit();
9091
9092  // Expose context1 in context2 and call the callback function in
9093  // context0 indirectly through f in context1.
9094  calling_context2->Enter();
9095  calling_context2->Global()->Set(v8_str("context1"),
9096                                  calling_context1->Global());
9097  CompileRun("context1.f()");
9098  calling_context2->Exit();
9099
9100  // Dispose the contexts to allow them to be garbage collected.
9101  calling_context0.Dispose();
9102  calling_context1.Dispose();
9103  calling_context2.Dispose();
9104  calling_context0.Clear();
9105  calling_context1.Clear();
9106  calling_context2.Clear();
9107}
9108
9109
9110// Check that a variable declaration with no explicit initialization
9111// value does not shadow an existing property in the prototype chain.
9112//
9113// This is consistent with Firefox and Safari.
9114//
9115// See http://crbug.com/12548.
9116THREADED_TEST(InitGlobalVarInProtoChain) {
9117  v8::HandleScope scope;
9118  LocalContext context;
9119  // Introduce a variable in the prototype chain.
9120  CompileRun("__proto__.x = 42");
9121  v8::Handle<v8::Value> result = CompileRun("var x; x");
9122  CHECK(!result->IsUndefined());
9123  CHECK_EQ(42, result->Int32Value());
9124}
9125
9126
9127// Regression test for issue 398.
9128// If a function is added to an object, creating a constant function
9129// field, and the result is cloned, replacing the constant function on the
9130// original should not affect the clone.
9131// See http://code.google.com/p/v8/issues/detail?id=398
9132THREADED_TEST(ReplaceConstantFunction) {
9133  v8::HandleScope scope;
9134  LocalContext context;
9135  v8::Handle<v8::Object> obj = v8::Object::New();
9136  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
9137  v8::Handle<v8::String> foo_string = v8::String::New("foo");
9138  obj->Set(foo_string, func_templ->GetFunction());
9139  v8::Handle<v8::Object> obj_clone = obj->Clone();
9140  obj_clone->Set(foo_string, v8::String::New("Hello"));
9141  CHECK(!obj->Get(foo_string)->IsUndefined());
9142}
9143
9144
9145// Regression test for http://crbug.com/16276.
9146THREADED_TEST(Regress16276) {
9147  v8::HandleScope scope;
9148  LocalContext context;
9149  // Force the IC in f to be a dictionary load IC.
9150  CompileRun("function f(obj) { return obj.x; }\n"
9151             "var obj = { x: { foo: 42 }, y: 87 };\n"
9152             "var x = obj.x;\n"
9153             "delete obj.y;\n"
9154             "for (var i = 0; i < 5; i++) f(obj);");
9155  // Detach the global object to make 'this' refer directly to the
9156  // global object (not the proxy), and make sure that the dictionary
9157  // load IC doesn't mess up loading directly from the global object.
9158  context->DetachGlobal();
9159  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
9160}
9161
9162
9163THREADED_TEST(PixelArray) {
9164  v8::HandleScope scope;
9165  LocalContext context;
9166  const int kElementCount = 260;
9167  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
9168  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
9169                                                              pixel_data);
9170  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9171  for (int i = 0; i < kElementCount; i++) {
9172    pixels->set(i, i % 256);
9173  }
9174  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9175  for (int i = 0; i < kElementCount; i++) {
9176    CHECK_EQ(i % 256, pixels->get(i));
9177    CHECK_EQ(i % 256, pixel_data[i]);
9178  }
9179
9180  v8::Handle<v8::Object> obj = v8::Object::New();
9181  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9182  // Set the elements to be the pixels.
9183  // jsobj->set_elements(*pixels);
9184  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
9185  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9186  obj->Set(v8_str("field"), v8::Int32::New(1503));
9187  context->Global()->Set(v8_str("pixels"), obj);
9188  v8::Handle<v8::Value> result = CompileRun("pixels.field");
9189  CHECK_EQ(1503, result->Int32Value());
9190  result = CompileRun("pixels[1]");
9191  CHECK_EQ(1, result->Int32Value());
9192
9193  result = CompileRun("var sum = 0;"
9194                      "for (var i = 0; i < 8; i++) {"
9195                      "  sum += pixels[i] = pixels[i] = -i;"
9196                      "}"
9197                      "sum;");
9198  CHECK_EQ(-28, result->Int32Value());
9199
9200  result = CompileRun("var sum = 0;"
9201                      "for (var i = 0; i < 8; i++) {"
9202                      "  sum += pixels[i] = pixels[i] = 0;"
9203                      "}"
9204                      "sum;");
9205  CHECK_EQ(0, result->Int32Value());
9206
9207  result = CompileRun("var sum = 0;"
9208                      "for (var i = 0; i < 8; i++) {"
9209                      "  sum += pixels[i] = pixels[i] = 255;"
9210                      "}"
9211                      "sum;");
9212  CHECK_EQ(8 * 255, result->Int32Value());
9213
9214  result = CompileRun("var sum = 0;"
9215                      "for (var i = 0; i < 8; i++) {"
9216                      "  sum += pixels[i] = pixels[i] = 256 + i;"
9217                      "}"
9218                      "sum;");
9219  CHECK_EQ(2076, result->Int32Value());
9220
9221  result = CompileRun("var sum = 0;"
9222                      "for (var i = 0; i < 8; i++) {"
9223                      "  sum += pixels[i] = pixels[i] = i;"
9224                      "}"
9225                      "sum;");
9226  CHECK_EQ(28, result->Int32Value());
9227
9228  result = CompileRun("var sum = 0;"
9229                      "for (var i = 0; i < 8; i++) {"
9230                      "  sum += pixels[i];"
9231                      "}"
9232                      "sum;");
9233  CHECK_EQ(28, result->Int32Value());
9234
9235  i::Handle<i::Smi> value(i::Smi::FromInt(2));
9236  i::SetElement(jsobj, 1, value);
9237  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9238  *value.location() = i::Smi::FromInt(256);
9239  i::SetElement(jsobj, 1, value);
9240  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9241  *value.location() = i::Smi::FromInt(-1);
9242  i::SetElement(jsobj, 1, value);
9243  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9244
9245  result = CompileRun("for (var i = 0; i < 8; i++) {"
9246                      "  pixels[i] = (i * 65) - 109;"
9247                      "}"
9248                      "pixels[1] + pixels[6];");
9249  CHECK_EQ(255, result->Int32Value());
9250  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9251  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9252  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9253  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9254  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9255  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9256  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9257  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9258  result = CompileRun("var sum = 0;"
9259                      "for (var i = 0; i < 8; i++) {"
9260                      "  sum += pixels[i];"
9261                      "}"
9262                      "sum;");
9263  CHECK_EQ(984, result->Int32Value());
9264
9265  result = CompileRun("for (var i = 0; i < 8; i++) {"
9266                      "  pixels[i] = (i * 1.1);"
9267                      "}"
9268                      "pixels[1] + pixels[6];");
9269  CHECK_EQ(8, result->Int32Value());
9270  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9271  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9272  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9273  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9274  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9275  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9276  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9277  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9278
9279  result = CompileRun("for (var i = 0; i < 8; i++) {"
9280                      "  pixels[7] = undefined;"
9281                      "}"
9282                      "pixels[7];");
9283  CHECK_EQ(0, result->Int32Value());
9284  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9285
9286  result = CompileRun("for (var i = 0; i < 8; i++) {"
9287                      "  pixels[6] = '2.3';"
9288                      "}"
9289                      "pixels[6];");
9290  CHECK_EQ(2, result->Int32Value());
9291  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9292
9293  result = CompileRun("for (var i = 0; i < 8; i++) {"
9294                      "  pixels[5] = NaN;"
9295                      "}"
9296                      "pixels[5];");
9297  CHECK_EQ(0, result->Int32Value());
9298  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9299
9300  result = CompileRun("for (var i = 0; i < 8; i++) {"
9301                      "  pixels[8] = Infinity;"
9302                      "}"
9303                      "pixels[8];");
9304  CHECK_EQ(255, result->Int32Value());
9305  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9306
9307  result = CompileRun("for (var i = 0; i < 8; i++) {"
9308                      "  pixels[9] = -Infinity;"
9309                      "}"
9310                      "pixels[9];");
9311  CHECK_EQ(0, result->Int32Value());
9312  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9313
9314  result = CompileRun("pixels[3] = 33;"
9315                      "delete pixels[3];"
9316                      "pixels[3];");
9317  CHECK_EQ(33, result->Int32Value());
9318
9319  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9320                      "pixels[2] = 12; pixels[3] = 13;"
9321                      "pixels.__defineGetter__('2',"
9322                      "function() { return 120; });"
9323                      "pixels[2];");
9324  CHECK_EQ(12, result->Int32Value());
9325
9326  result = CompileRun("var js_array = new Array(40);"
9327                      "js_array[0] = 77;"
9328                      "js_array;");
9329  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9330
9331  result = CompileRun("pixels[1] = 23;"
9332                      "pixels.__proto__ = [];"
9333                      "js_array.__proto__ = pixels;"
9334                      "js_array.concat(pixels);");
9335  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9336  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9337
9338  result = CompileRun("pixels[1] = 23;");
9339  CHECK_EQ(23, result->Int32Value());
9340
9341  // Test for index greater than 255.  Regression test for:
9342  // http://code.google.com/p/chromium/issues/detail?id=26337.
9343  result = CompileRun("pixels[256] = 255;");
9344  CHECK_EQ(255, result->Int32Value());
9345  result = CompileRun("var i = 0;"
9346                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9347                      "i");
9348  CHECK_EQ(255, result->Int32Value());
9349
9350  free(pixel_data);
9351}
9352
9353
9354template <class ExternalArrayClass, class ElementType>
9355static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9356                                    int64_t low,
9357                                    int64_t high) {
9358  v8::HandleScope scope;
9359  LocalContext context;
9360  const int kElementCount = 40;
9361  int element_size = 0;
9362  switch (array_type) {
9363    case v8::kExternalByteArray:
9364    case v8::kExternalUnsignedByteArray:
9365      element_size = 1;
9366      break;
9367    case v8::kExternalShortArray:
9368    case v8::kExternalUnsignedShortArray:
9369      element_size = 2;
9370      break;
9371    case v8::kExternalIntArray:
9372    case v8::kExternalUnsignedIntArray:
9373    case v8::kExternalFloatArray:
9374      element_size = 4;
9375      break;
9376    default:
9377      UNREACHABLE();
9378      break;
9379  }
9380  ElementType* array_data =
9381      static_cast<ElementType*>(malloc(kElementCount * element_size));
9382  i::Handle<ExternalArrayClass> array =
9383      i::Handle<ExternalArrayClass>::cast(
9384          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9385  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9386  for (int i = 0; i < kElementCount; i++) {
9387    array->set(i, static_cast<ElementType>(i));
9388  }
9389  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9390  for (int i = 0; i < kElementCount; i++) {
9391    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9392    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9393  }
9394
9395  v8::Handle<v8::Object> obj = v8::Object::New();
9396  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9397  // Set the elements to be the external array.
9398  obj->SetIndexedPropertiesToExternalArrayData(array_data,
9399                                               array_type,
9400                                               kElementCount);
9401  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9402  obj->Set(v8_str("field"), v8::Int32::New(1503));
9403  context->Global()->Set(v8_str("ext_array"), obj);
9404  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9405  CHECK_EQ(1503, result->Int32Value());
9406  result = CompileRun("ext_array[1]");
9407  CHECK_EQ(1, result->Int32Value());
9408
9409  // Check pass through of assigned smis
9410  result = CompileRun("var sum = 0;"
9411                      "for (var i = 0; i < 8; i++) {"
9412                      "  sum += ext_array[i] = ext_array[i] = -i;"
9413                      "}"
9414                      "sum;");
9415  CHECK_EQ(-28, result->Int32Value());
9416
9417  // Check assigned smis
9418  result = CompileRun("for (var i = 0; i < 8; i++) {"
9419                      "  ext_array[i] = i;"
9420                      "}"
9421                      "var sum = 0;"
9422                      "for (var i = 0; i < 8; i++) {"
9423                      "  sum += ext_array[i];"
9424                      "}"
9425                      "sum;");
9426  CHECK_EQ(28, result->Int32Value());
9427
9428  // Check assigned smis in reverse order
9429  result = CompileRun("for (var i = 8; --i >= 0; ) {"
9430                      "  ext_array[i] = i;"
9431                      "}"
9432                      "var sum = 0;"
9433                      "for (var i = 0; i < 8; i++) {"
9434                      "  sum += ext_array[i];"
9435                      "}"
9436                      "sum;");
9437  CHECK_EQ(28, result->Int32Value());
9438
9439  // Check pass through of assigned HeapNumbers
9440  result = CompileRun("var sum = 0;"
9441                      "for (var i = 0; i < 16; i+=2) {"
9442                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9443                      "}"
9444                      "sum;");
9445  CHECK_EQ(-28, result->Int32Value());
9446
9447  // Check assigned HeapNumbers
9448  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9449                      "  ext_array[i] = (i * 0.5);"
9450                      "}"
9451                      "var sum = 0;"
9452                      "for (var i = 0; i < 16; i+=2) {"
9453                      "  sum += ext_array[i];"
9454                      "}"
9455                      "sum;");
9456  CHECK_EQ(28, result->Int32Value());
9457
9458  // Check assigned HeapNumbers in reverse order
9459  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9460                      "  ext_array[i] = (i * 0.5);"
9461                      "}"
9462                      "var sum = 0;"
9463                      "for (var i = 0; i < 16; i+=2) {"
9464                      "  sum += ext_array[i];"
9465                      "}"
9466                      "sum;");
9467  CHECK_EQ(28, result->Int32Value());
9468
9469  i::ScopedVector<char> test_buf(1024);
9470
9471  // Check legal boundary conditions.
9472  // The repeated loads and stores ensure the ICs are exercised.
9473  const char* boundary_program =
9474      "var res = 0;"
9475      "for (var i = 0; i < 16; i++) {"
9476      "  ext_array[i] = %lld;"
9477      "  if (i > 8) {"
9478      "    res = ext_array[i];"
9479      "  }"
9480      "}"
9481      "res;";
9482  i::OS::SNPrintF(test_buf,
9483                  boundary_program,
9484                  low);
9485  result = CompileRun(test_buf.start());
9486  CHECK_EQ(low, result->IntegerValue());
9487
9488  i::OS::SNPrintF(test_buf,
9489                  boundary_program,
9490                  high);
9491  result = CompileRun(test_buf.start());
9492  CHECK_EQ(high, result->IntegerValue());
9493
9494  // Check misprediction of type in IC.
9495  result = CompileRun("var tmp_array = ext_array;"
9496                      "var sum = 0;"
9497                      "for (var i = 0; i < 8; i++) {"
9498                      "  tmp_array[i] = i;"
9499                      "  sum += tmp_array[i];"
9500                      "  if (i == 4) {"
9501                      "    tmp_array = {};"
9502                      "  }"
9503                      "}"
9504                      "sum;");
9505  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9506  CHECK_EQ(28, result->Int32Value());
9507
9508  // Make sure out-of-range loads do not throw.
9509  i::OS::SNPrintF(test_buf,
9510                  "var caught_exception = false;"
9511                  "try {"
9512                  "  ext_array[%d];"
9513                  "} catch (e) {"
9514                  "  caught_exception = true;"
9515                  "}"
9516                  "caught_exception;",
9517                  kElementCount);
9518  result = CompileRun(test_buf.start());
9519  CHECK_EQ(false, result->BooleanValue());
9520
9521  // Make sure out-of-range stores do not throw.
9522  i::OS::SNPrintF(test_buf,
9523                  "var caught_exception = false;"
9524                  "try {"
9525                  "  ext_array[%d] = 1;"
9526                  "} catch (e) {"
9527                  "  caught_exception = true;"
9528                  "}"
9529                  "caught_exception;",
9530                  kElementCount);
9531  result = CompileRun(test_buf.start());
9532  CHECK_EQ(false, result->BooleanValue());
9533
9534  // Check other boundary conditions, values and operations.
9535  result = CompileRun("for (var i = 0; i < 8; i++) {"
9536                      "  ext_array[7] = undefined;"
9537                      "}"
9538                      "ext_array[7];");
9539  CHECK_EQ(0, result->Int32Value());
9540  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9541
9542  result = CompileRun("for (var i = 0; i < 8; i++) {"
9543                      "  ext_array[6] = '2.3';"
9544                      "}"
9545                      "ext_array[6];");
9546  CHECK_EQ(2, result->Int32Value());
9547  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9548
9549  if (array_type != v8::kExternalFloatArray) {
9550    // Though the specification doesn't state it, be explicit about
9551    // converting NaNs and +/-Infinity to zero.
9552    result = CompileRun("for (var i = 0; i < 8; i++) {"
9553                        "  ext_array[i] = 5;"
9554                        "}"
9555                        "for (var i = 0; i < 8; i++) {"
9556                        "  ext_array[i] = NaN;"
9557                        "}"
9558                        "ext_array[5];");
9559    CHECK_EQ(0, result->Int32Value());
9560    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9561
9562    result = CompileRun("for (var i = 0; i < 8; i++) {"
9563                        "  ext_array[i] = 5;"
9564                        "}"
9565                        "for (var i = 0; i < 8; i++) {"
9566                        "  ext_array[i] = Infinity;"
9567                        "}"
9568                        "ext_array[5];");
9569    CHECK_EQ(0, result->Int32Value());
9570    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9571
9572    result = CompileRun("for (var i = 0; i < 8; i++) {"
9573                        "  ext_array[i] = 5;"
9574                        "}"
9575                        "for (var i = 0; i < 8; i++) {"
9576                        "  ext_array[i] = -Infinity;"
9577                        "}"
9578                        "ext_array[5];");
9579    CHECK_EQ(0, result->Int32Value());
9580    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9581  }
9582
9583  result = CompileRun("ext_array[3] = 33;"
9584                      "delete ext_array[3];"
9585                      "ext_array[3];");
9586  CHECK_EQ(33, result->Int32Value());
9587
9588  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9589                      "ext_array[2] = 12; ext_array[3] = 13;"
9590                      "ext_array.__defineGetter__('2',"
9591                      "function() { return 120; });"
9592                      "ext_array[2];");
9593  CHECK_EQ(12, result->Int32Value());
9594
9595  result = CompileRun("var js_array = new Array(40);"
9596                      "js_array[0] = 77;"
9597                      "js_array;");
9598  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9599
9600  result = CompileRun("ext_array[1] = 23;"
9601                      "ext_array.__proto__ = [];"
9602                      "js_array.__proto__ = ext_array;"
9603                      "js_array.concat(ext_array);");
9604  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9605  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9606
9607  result = CompileRun("ext_array[1] = 23;");
9608  CHECK_EQ(23, result->Int32Value());
9609
9610  // Test more complex manipulations which cause eax to contain values
9611  // that won't be completely overwritten by loads from the arrays.
9612  // This catches bugs in the instructions used for the KeyedLoadIC
9613  // for byte and word types.
9614  {
9615    const int kXSize = 300;
9616    const int kYSize = 300;
9617    const int kLargeElementCount = kXSize * kYSize * 4;
9618    ElementType* large_array_data =
9619        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9620    i::Handle<ExternalArrayClass> large_array =
9621        i::Handle<ExternalArrayClass>::cast(
9622            i::Factory::NewExternalArray(kLargeElementCount,
9623                                         array_type,
9624                                         array_data));
9625    v8::Handle<v8::Object> large_obj = v8::Object::New();
9626    // Set the elements to be the external array.
9627    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9628                                                       array_type,
9629                                                       kLargeElementCount);
9630    context->Global()->Set(v8_str("large_array"), large_obj);
9631    // Initialize contents of a few rows.
9632    for (int x = 0; x < 300; x++) {
9633      int row = 0;
9634      int offset = row * 300 * 4;
9635      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9636      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9637      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9638      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9639      row = 150;
9640      offset = row * 300 * 4;
9641      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9642      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9643      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9644      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9645      row = 298;
9646      offset = row * 300 * 4;
9647      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9648      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9649      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9650      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9651    }
9652    // The goal of the code below is to make "offset" large enough
9653    // that the computation of the index (which goes into eax) has
9654    // high bits set which will not be overwritten by a byte or short
9655    // load.
9656    result = CompileRun("var failed = false;"
9657                        "var offset = 0;"
9658                        "for (var i = 0; i < 300; i++) {"
9659                        "  if (large_array[4 * i] != 127 ||"
9660                        "      large_array[4 * i + 1] != 0 ||"
9661                        "      large_array[4 * i + 2] != 0 ||"
9662                        "      large_array[4 * i + 3] != 127) {"
9663                        "    failed = true;"
9664                        "  }"
9665                        "}"
9666                        "offset = 150 * 300 * 4;"
9667                        "for (var i = 0; i < 300; i++) {"
9668                        "  if (large_array[offset + 4 * i] != 127 ||"
9669                        "      large_array[offset + 4 * i + 1] != 0 ||"
9670                        "      large_array[offset + 4 * i + 2] != 0 ||"
9671                        "      large_array[offset + 4 * i + 3] != 127) {"
9672                        "    failed = true;"
9673                        "  }"
9674                        "}"
9675                        "offset = 298 * 300 * 4;"
9676                        "for (var i = 0; i < 300; i++) {"
9677                        "  if (large_array[offset + 4 * i] != 127 ||"
9678                        "      large_array[offset + 4 * i + 1] != 0 ||"
9679                        "      large_array[offset + 4 * i + 2] != 0 ||"
9680                        "      large_array[offset + 4 * i + 3] != 127) {"
9681                        "    failed = true;"
9682                        "  }"
9683                        "}"
9684                        "!failed;");
9685    CHECK_EQ(true, result->BooleanValue());
9686    free(large_array_data);
9687  }
9688
9689  free(array_data);
9690}
9691
9692
9693THREADED_TEST(ExternalByteArray) {
9694  ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
9695      v8::kExternalByteArray,
9696      -128,
9697      127);
9698}
9699
9700
9701THREADED_TEST(ExternalUnsignedByteArray) {
9702  ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
9703      v8::kExternalUnsignedByteArray,
9704      0,
9705      255);
9706}
9707
9708
9709THREADED_TEST(ExternalShortArray) {
9710  ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
9711      v8::kExternalShortArray,
9712      -32768,
9713      32767);
9714}
9715
9716
9717THREADED_TEST(ExternalUnsignedShortArray) {
9718  ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
9719      v8::kExternalUnsignedShortArray,
9720      0,
9721      65535);
9722}
9723
9724
9725THREADED_TEST(ExternalIntArray) {
9726  ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
9727      v8::kExternalIntArray,
9728      INT_MIN,   // -2147483648
9729      INT_MAX);  //  2147483647
9730}
9731
9732
9733THREADED_TEST(ExternalUnsignedIntArray) {
9734  ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
9735      v8::kExternalUnsignedIntArray,
9736      0,
9737      UINT_MAX);  // 4294967295
9738}
9739
9740
9741THREADED_TEST(ExternalFloatArray) {
9742  ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
9743      v8::kExternalFloatArray,
9744      -500,
9745      500);
9746}
9747
9748
9749THREADED_TEST(ExternalArrays) {
9750  TestExternalByteArray();
9751  TestExternalUnsignedByteArray();
9752  TestExternalShortArray();
9753  TestExternalUnsignedShortArray();
9754  TestExternalIntArray();
9755  TestExternalUnsignedIntArray();
9756  TestExternalFloatArray();
9757}
9758
9759
9760THREADED_TEST(ScriptContextDependence) {
9761  v8::HandleScope scope;
9762  LocalContext c1;
9763  const char *source = "foo";
9764  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
9765  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
9766  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
9767  CHECK_EQ(dep->Run()->Int32Value(), 100);
9768  CHECK_EQ(indep->Run()->Int32Value(), 100);
9769  LocalContext c2;
9770  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
9771  CHECK_EQ(dep->Run()->Int32Value(), 100);
9772  CHECK_EQ(indep->Run()->Int32Value(), 101);
9773}
9774
9775
9776THREADED_TEST(StackTrace) {
9777  v8::HandleScope scope;
9778  LocalContext context;
9779  v8::TryCatch try_catch;
9780  const char *source = "function foo() { FAIL.FAIL; }; foo();";
9781  v8::Handle<v8::String> src = v8::String::New(source);
9782  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
9783  v8::Script::New(src, origin)->Run();
9784  CHECK(try_catch.HasCaught());
9785  v8::String::Utf8Value stack(try_catch.StackTrace());
9786  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
9787}
9788
9789
9790// Checks that a StackFrame has certain expected values.
9791void checkStackFrame(const char* expected_script_name,
9792    const char* expected_func_name, int expected_line_number,
9793    int expected_column, bool is_eval, bool is_constructor,
9794    v8::Handle<v8::StackFrame> frame) {
9795  v8::HandleScope scope;
9796  v8::String::Utf8Value func_name(frame->GetFunctionName());
9797  v8::String::Utf8Value script_name(frame->GetScriptName());
9798  if (*script_name == NULL) {
9799    // The situation where there is no associated script, like for evals.
9800    CHECK(expected_script_name == NULL);
9801  } else {
9802    CHECK(strstr(*script_name, expected_script_name) != NULL);
9803  }
9804  CHECK(strstr(*func_name, expected_func_name) != NULL);
9805  CHECK_EQ(expected_line_number, frame->GetLineNumber());
9806  CHECK_EQ(expected_column, frame->GetColumn());
9807  CHECK_EQ(is_eval, frame->IsEval());
9808  CHECK_EQ(is_constructor, frame->IsConstructor());
9809}
9810
9811
9812v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
9813  v8::HandleScope scope;
9814  const char* origin = "capture-stack-trace-test";
9815  const int kOverviewTest = 1;
9816  const int kDetailedTest = 2;
9817
9818  ASSERT(args.Length() == 1);
9819
9820  int testGroup = args[0]->Int32Value();
9821  if (testGroup == kOverviewTest) {
9822    v8::Handle<v8::StackTrace> stackTrace =
9823        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
9824    CHECK_EQ(4, stackTrace->GetFrameCount());
9825    checkStackFrame(origin, "bar", 2, 10, false, false,
9826                    stackTrace->GetFrame(0));
9827    checkStackFrame(origin, "foo", 6, 3, false, false,
9828                    stackTrace->GetFrame(1));
9829    checkStackFrame(NULL, "", 1, 1, false, false,
9830                    stackTrace->GetFrame(2));
9831    // The last frame is an anonymous function that has the initial call.
9832    checkStackFrame(origin, "", 8, 7, false, false,
9833                    stackTrace->GetFrame(3));
9834
9835    CHECK(stackTrace->AsArray()->IsArray());
9836  } else if (testGroup == kDetailedTest) {
9837    v8::Handle<v8::StackTrace> stackTrace =
9838        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
9839    CHECK_EQ(4, stackTrace->GetFrameCount());
9840    checkStackFrame(origin, "bat", 4, 22, false, false,
9841                    stackTrace->GetFrame(0));
9842    checkStackFrame(origin, "baz", 8, 3, false, true,
9843                    stackTrace->GetFrame(1));
9844    checkStackFrame(NULL, "", 1, 1, true, false,
9845                    stackTrace->GetFrame(2));
9846    // The last frame is an anonymous function that has the initial call to foo.
9847    checkStackFrame(origin, "", 10, 1, false, false,
9848                    stackTrace->GetFrame(3));
9849
9850    CHECK(stackTrace->AsArray()->IsArray());
9851  }
9852  return v8::Undefined();
9853}
9854
9855
9856// Tests the C++ StackTrace API.
9857THREADED_TEST(CaptureStackTrace) {
9858  v8::HandleScope scope;
9859  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
9860  Local<ObjectTemplate> templ = ObjectTemplate::New();
9861  templ->Set(v8_str("AnalyzeStackInNativeCode"),
9862             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
9863  LocalContext context(0, templ);
9864
9865  // Test getting OVERVIEW information. Should ignore information that is not
9866  // script name, function name, line number, and column offset.
9867  const char *overview_source =
9868    "function bar() {\n"
9869    "  var y; AnalyzeStackInNativeCode(1);\n"
9870    "}\n"
9871    "function foo() {\n"
9872    "\n"
9873    "  bar();\n"
9874    "}\n"
9875    "var x;eval('new foo();');";
9876  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
9877  v8::Handle<Value> overview_result =
9878      v8::Script::New(overview_src, origin)->Run();
9879  ASSERT(!overview_result.IsEmpty());
9880  ASSERT(overview_result->IsObject());
9881
9882  // Test getting DETAILED information.
9883  const char *detailed_source =
9884    "function bat() {AnalyzeStackInNativeCode(2);\n"
9885    "}\n"
9886    "\n"
9887    "function baz() {\n"
9888    "  bat();\n"
9889    "}\n"
9890    "eval('new baz();');";
9891  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
9892  // Make the script using a non-zero line and column offset.
9893  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
9894  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
9895  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
9896  v8::Handle<v8::Script> detailed_script(
9897      v8::Script::New(detailed_src, &detailed_origin));
9898  v8::Handle<Value> detailed_result = detailed_script->Run();
9899  ASSERT(!detailed_result.IsEmpty());
9900  ASSERT(detailed_result->IsObject());
9901}
9902
9903
9904// Test that idle notification can be handled and eventually returns true.
9905THREADED_TEST(IdleNotification) {
9906  bool rv = false;
9907  for (int i = 0; i < 100; i++) {
9908    rv = v8::V8::IdleNotification();
9909    if (rv)
9910      break;
9911  }
9912  CHECK(rv == true);
9913}
9914
9915
9916static uint32_t* stack_limit;
9917
9918static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
9919  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
9920  return v8::Undefined();
9921}
9922
9923
9924// Uses the address of a local variable to determine the stack top now.
9925// Given a size, returns an address that is that far from the current
9926// top of stack.
9927static uint32_t* ComputeStackLimit(uint32_t size) {
9928  uint32_t* answer = &size - (size / sizeof(size));
9929  // If the size is very large and the stack is very near the bottom of
9930  // memory then the calculation above may wrap around and give an address
9931  // that is above the (downwards-growing) stack.  In that case we return
9932  // a very low address.
9933  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
9934  return answer;
9935}
9936
9937
9938TEST(SetResourceConstraints) {
9939  static const int K = 1024;
9940  uint32_t* set_limit = ComputeStackLimit(128 * K);
9941
9942  // Set stack limit.
9943  v8::ResourceConstraints constraints;
9944  constraints.set_stack_limit(set_limit);
9945  CHECK(v8::SetResourceConstraints(&constraints));
9946
9947  // Execute a script.
9948  v8::HandleScope scope;
9949  LocalContext env;
9950  Local<v8::FunctionTemplate> fun_templ =
9951      v8::FunctionTemplate::New(GetStackLimitCallback);
9952  Local<Function> fun = fun_templ->GetFunction();
9953  env->Global()->Set(v8_str("get_stack_limit"), fun);
9954  CompileRun("get_stack_limit();");
9955
9956  CHECK(stack_limit == set_limit);
9957}
9958
9959
9960TEST(SetResourceConstraintsInThread) {
9961  uint32_t* set_limit;
9962  {
9963    v8::Locker locker;
9964    static const int K = 1024;
9965    set_limit = ComputeStackLimit(128 * K);
9966
9967    // Set stack limit.
9968    v8::ResourceConstraints constraints;
9969    constraints.set_stack_limit(set_limit);
9970    CHECK(v8::SetResourceConstraints(&constraints));
9971
9972    // Execute a script.
9973    v8::HandleScope scope;
9974    LocalContext env;
9975    Local<v8::FunctionTemplate> fun_templ =
9976        v8::FunctionTemplate::New(GetStackLimitCallback);
9977    Local<Function> fun = fun_templ->GetFunction();
9978    env->Global()->Set(v8_str("get_stack_limit"), fun);
9979    CompileRun("get_stack_limit();");
9980
9981    CHECK(stack_limit == set_limit);
9982  }
9983  {
9984    v8::Locker locker;
9985    CHECK(stack_limit == set_limit);
9986  }
9987}
9988
9989
9990THREADED_TEST(GetHeapStatistics) {
9991  v8::HandleScope scope;
9992  LocalContext c1;
9993  v8::HeapStatistics heap_statistics;
9994  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
9995  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
9996  v8::V8::GetHeapStatistics(&heap_statistics);
9997  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
9998  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
9999}
10000
10001
10002static double DoubleFromBits(uint64_t value) {
10003  double target;
10004#ifdef BIG_ENDIAN_FLOATING_POINT
10005  const int kIntSize = 4;
10006  // Somebody swapped the lower and higher half of doubles.
10007  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10008  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10009#else
10010  memcpy(&target, &value, sizeof(target));
10011#endif
10012  return target;
10013}
10014
10015
10016static uint64_t DoubleToBits(double value) {
10017  uint64_t target;
10018#ifdef BIG_ENDIAN_FLOATING_POINT
10019  const int kIntSize = 4;
10020  // Somebody swapped the lower and higher half of doubles.
10021  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10022  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10023#else
10024  memcpy(&target, &value, sizeof(target));
10025#endif
10026  return target;
10027}
10028
10029
10030static double DoubleToDateTime(double input) {
10031  double date_limit = 864e13;
10032  if (IsNaN(input) || input < -date_limit || input > date_limit) {
10033    return i::OS::nan_value();
10034  }
10035  return (input < 0) ? -(floor(-input)) : floor(input);
10036}
10037
10038// We don't have a consistent way to write 64-bit constants syntactically, so we
10039// split them into two 32-bit constants and combine them programmatically.
10040static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
10041  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
10042}
10043
10044
10045THREADED_TEST(QuietSignalingNaNs) {
10046  v8::HandleScope scope;
10047  LocalContext context;
10048  v8::TryCatch try_catch;
10049
10050  // Special double values.
10051  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
10052  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
10053  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
10054  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
10055  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
10056  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
10057  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
10058
10059  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
10060  // on either side of the epoch.
10061  double date_limit = 864e13;
10062
10063  double test_values[] = {
10064      snan,
10065      qnan,
10066      infinity,
10067      max_normal,
10068      date_limit + 1,
10069      date_limit,
10070      min_normal,
10071      max_denormal,
10072      min_denormal,
10073      0,
10074      -0,
10075      -min_denormal,
10076      -max_denormal,
10077      -min_normal,
10078      -date_limit,
10079      -date_limit - 1,
10080      -max_normal,
10081      -infinity,
10082      -qnan,
10083      -snan
10084  };
10085  int num_test_values = 20;
10086
10087  for (int i = 0; i < num_test_values; i++) {
10088    double test_value = test_values[i];
10089
10090    // Check that Number::New preserves non-NaNs and quiets SNaNs.
10091    v8::Handle<v8::Value> number = v8::Number::New(test_value);
10092    double stored_number = number->NumberValue();
10093    if (!IsNaN(test_value)) {
10094      CHECK_EQ(test_value, stored_number);
10095    } else {
10096      uint64_t stored_bits = DoubleToBits(stored_number);
10097      // Check if quiet nan (bits 51..62 all set).
10098      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10099    }
10100
10101    // Check that Date::New preserves non-NaNs in the date range and
10102    // quiets SNaNs.
10103    v8::Handle<v8::Value> date = v8::Date::New(test_value);
10104    double expected_stored_date = DoubleToDateTime(test_value);
10105    double stored_date = date->NumberValue();
10106    if (!IsNaN(expected_stored_date)) {
10107      CHECK_EQ(expected_stored_date, stored_date);
10108    } else {
10109      uint64_t stored_bits = DoubleToBits(stored_date);
10110      // Check if quiet nan (bits 51..62 all set).
10111      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10112    }
10113  }
10114}
10115
10116
10117static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
10118  v8::HandleScope scope;
10119  v8::TryCatch tc;
10120  v8::Handle<v8::String> str = args[0]->ToString();
10121  if (tc.HasCaught())
10122    return tc.ReThrow();
10123  return v8::Undefined();
10124}
10125
10126
10127// Test that an exception can be propagated down through a spaghetti
10128// stack using ReThrow.
10129THREADED_TEST(SpaghettiStackReThrow) {
10130  v8::HandleScope scope;
10131  LocalContext context;
10132  context->Global()->Set(
10133      v8::String::New("s"),
10134      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
10135  v8::TryCatch try_catch;
10136  CompileRun(
10137      "var i = 0;"
10138      "var o = {"
10139      "  toString: function () {"
10140      "    if (i == 10) {"
10141      "      throw 'Hey!';"
10142      "    } else {"
10143      "      i++;"
10144      "      return s(o);"
10145      "    }"
10146      "  }"
10147      "};"
10148      "s(o);");
10149  CHECK(try_catch.HasCaught());
10150  v8::String::Utf8Value value(try_catch.Exception());
10151  CHECK_EQ(0, strcmp(*value, "Hey!"));
10152}
10153
10154
10155TEST(Regress528) {
10156  v8::V8::Initialize();
10157
10158  v8::HandleScope scope;
10159  v8::Persistent<Context> context;
10160  v8::Persistent<Context> other_context;
10161  int gc_count;
10162
10163  // Create a context used to keep the code from aging in the compilation
10164  // cache.
10165  other_context = Context::New();
10166
10167  // Context-dependent context data creates reference from the compilation
10168  // cache to the global object.
10169  const char* source_simple = "1";
10170  context = Context::New();
10171  {
10172    v8::HandleScope scope;
10173
10174    context->Enter();
10175    Local<v8::String> obj = v8::String::New("");
10176    context->SetData(obj);
10177    CompileRun(source_simple);
10178    context->Exit();
10179  }
10180  context.Dispose();
10181  for (gc_count = 1; gc_count < 10; gc_count++) {
10182    other_context->Enter();
10183    CompileRun(source_simple);
10184    other_context->Exit();
10185    v8::internal::Heap::CollectAllGarbage(false);
10186    if (GetGlobalObjectsCount() == 1) break;
10187  }
10188  CHECK_GE(2, gc_count);
10189  CHECK_EQ(1, GetGlobalObjectsCount());
10190
10191  // Eval in a function creates reference from the compilation cache to the
10192  // global object.
10193  const char* source_eval = "function f(){eval('1')}; f()";
10194  context = Context::New();
10195  {
10196    v8::HandleScope scope;
10197
10198    context->Enter();
10199    CompileRun(source_eval);
10200    context->Exit();
10201  }
10202  context.Dispose();
10203  for (gc_count = 1; gc_count < 10; gc_count++) {
10204    other_context->Enter();
10205    CompileRun(source_eval);
10206    other_context->Exit();
10207    v8::internal::Heap::CollectAllGarbage(false);
10208    if (GetGlobalObjectsCount() == 1) break;
10209  }
10210  CHECK_GE(2, gc_count);
10211  CHECK_EQ(1, GetGlobalObjectsCount());
10212
10213  // Looking up the line number for an exception creates reference from the
10214  // compilation cache to the global object.
10215  const char* source_exception = "function f(){throw 1;} f()";
10216  context = Context::New();
10217  {
10218    v8::HandleScope scope;
10219
10220    context->Enter();
10221    v8::TryCatch try_catch;
10222    CompileRun(source_exception);
10223    CHECK(try_catch.HasCaught());
10224    v8::Handle<v8::Message> message = try_catch.Message();
10225    CHECK(!message.IsEmpty());
10226    CHECK_EQ(1, message->GetLineNumber());
10227    context->Exit();
10228  }
10229  context.Dispose();
10230  for (gc_count = 1; gc_count < 10; gc_count++) {
10231    other_context->Enter();
10232    CompileRun(source_exception);
10233    other_context->Exit();
10234    v8::internal::Heap::CollectAllGarbage(false);
10235    if (GetGlobalObjectsCount() == 1) break;
10236  }
10237  CHECK_GE(2, gc_count);
10238  CHECK_EQ(1, GetGlobalObjectsCount());
10239
10240  other_context.Dispose();
10241}
10242
10243
10244THREADED_TEST(ScriptOrigin) {
10245  v8::HandleScope scope;
10246  LocalContext env;
10247  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10248  v8::Handle<v8::String> script = v8::String::New(
10249      "function f() {}\n\nfunction g() {}");
10250  v8::Script::Compile(script, &origin)->Run();
10251  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10252      env->Global()->Get(v8::String::New("f")));
10253  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10254      env->Global()->Get(v8::String::New("g")));
10255
10256  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10257  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10258  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
10259
10260  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
10261  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
10262  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
10263}
10264
10265
10266THREADED_TEST(ScriptLineNumber) {
10267  v8::HandleScope scope;
10268  LocalContext env;
10269  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10270  v8::Handle<v8::String> script = v8::String::New(
10271      "function f() {}\n\nfunction g() {}");
10272  v8::Script::Compile(script, &origin)->Run();
10273  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10274      env->Global()->Get(v8::String::New("f")));
10275  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10276      env->Global()->Get(v8::String::New("g")));
10277  CHECK_EQ(0, f->GetScriptLineNumber());
10278  CHECK_EQ(2, g->GetScriptLineNumber());
10279}
10280
10281
10282static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
10283                                              const AccessorInfo& info) {
10284  return v8_num(42);
10285}
10286
10287
10288static void SetterWhichSetsYOnThisTo23(Local<String> name,
10289                                       Local<Value> value,
10290                                       const AccessorInfo& info) {
10291  info.This()->Set(v8_str("y"), v8_num(23));
10292}
10293
10294
10295TEST(SetterOnConstructorPrototype) {
10296  v8::HandleScope scope;
10297  Local<ObjectTemplate> templ = ObjectTemplate::New();
10298  templ->SetAccessor(v8_str("x"),
10299                     GetterWhichReturns42,
10300                     SetterWhichSetsYOnThisTo23);
10301  LocalContext context;
10302  context->Global()->Set(v8_str("P"), templ->NewInstance());
10303  CompileRun("function C1() {"
10304             "  this.x = 23;"
10305             "};"
10306             "C1.prototype = P;"
10307             "function C2() {"
10308             "  this.x = 23"
10309             "};"
10310             "C2.prototype = { };"
10311             "C2.prototype.__proto__ = P;");
10312
10313  v8::Local<v8::Script> script;
10314  script = v8::Script::Compile(v8_str("new C1();"));
10315  for (int i = 0; i < 10; i++) {
10316    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10317    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10318    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10319  }
10320
10321  script = v8::Script::Compile(v8_str("new C2();"));
10322  for (int i = 0; i < 10; i++) {
10323    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10324    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10325    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10326  }
10327}
10328
10329
10330static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10331    Local<String> name, const AccessorInfo& info) {
10332  return v8_num(42);
10333}
10334
10335
10336static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10337    Local<String> name, Local<Value> value, const AccessorInfo& info) {
10338  if (name->Equals(v8_str("x"))) {
10339    info.This()->Set(v8_str("y"), v8_num(23));
10340  }
10341  return v8::Handle<Value>();
10342}
10343
10344
10345THREADED_TEST(InterceptorOnConstructorPrototype) {
10346  v8::HandleScope scope;
10347  Local<ObjectTemplate> templ = ObjectTemplate::New();
10348  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10349                                 NamedPropertySetterWhichSetsYOnThisTo23);
10350  LocalContext context;
10351  context->Global()->Set(v8_str("P"), templ->NewInstance());
10352  CompileRun("function C1() {"
10353             "  this.x = 23;"
10354             "};"
10355             "C1.prototype = P;"
10356             "function C2() {"
10357             "  this.x = 23"
10358             "};"
10359             "C2.prototype = { };"
10360             "C2.prototype.__proto__ = P;");
10361
10362  v8::Local<v8::Script> script;
10363  script = v8::Script::Compile(v8_str("new C1();"));
10364  for (int i = 0; i < 10; i++) {
10365    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10366    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10367    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10368  }
10369
10370  script = v8::Script::Compile(v8_str("new C2();"));
10371  for (int i = 0; i < 10; i++) {
10372    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10373    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10374    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10375  }
10376}
10377
10378
10379TEST(Bug618) {
10380  const char* source = "function C1() {"
10381                       "  this.x = 23;"
10382                       "};"
10383                       "C1.prototype = P;";
10384
10385  v8::HandleScope scope;
10386  LocalContext context;
10387  v8::Local<v8::Script> script;
10388
10389  // Use a simple object as prototype.
10390  v8::Local<v8::Object> prototype = v8::Object::New();
10391  prototype->Set(v8_str("y"), v8_num(42));
10392  context->Global()->Set(v8_str("P"), prototype);
10393
10394  // This compile will add the code to the compilation cache.
10395  CompileRun(source);
10396
10397  script = v8::Script::Compile(v8_str("new C1();"));
10398  for (int i = 0; i < 10; i++) {
10399    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10400    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10401    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10402  }
10403
10404  // Use an API object with accessors as prototype.
10405  Local<ObjectTemplate> templ = ObjectTemplate::New();
10406  templ->SetAccessor(v8_str("x"),
10407                     GetterWhichReturns42,
10408                     SetterWhichSetsYOnThisTo23);
10409  context->Global()->Set(v8_str("P"), templ->NewInstance());
10410
10411  // This compile will get the code from the compilation cache.
10412  CompileRun(source);
10413
10414  script = v8::Script::Compile(v8_str("new C1();"));
10415  for (int i = 0; i < 10; i++) {
10416    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10417    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10418    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10419  }
10420}
10421
10422int prologue_call_count = 0;
10423int epilogue_call_count = 0;
10424int prologue_call_count_second = 0;
10425int epilogue_call_count_second = 0;
10426
10427void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10428  ++prologue_call_count;
10429}
10430
10431void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10432  ++epilogue_call_count;
10433}
10434
10435void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10436  ++prologue_call_count_second;
10437}
10438
10439void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10440  ++epilogue_call_count_second;
10441}
10442
10443TEST(GCCallbacks) {
10444  LocalContext context;
10445
10446  v8::V8::AddGCPrologueCallback(PrologueCallback);
10447  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10448  CHECK_EQ(0, prologue_call_count);
10449  CHECK_EQ(0, epilogue_call_count);
10450  i::Heap::CollectAllGarbage(false);
10451  CHECK_EQ(1, prologue_call_count);
10452  CHECK_EQ(1, epilogue_call_count);
10453  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10454  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10455  i::Heap::CollectAllGarbage(false);
10456  CHECK_EQ(2, prologue_call_count);
10457  CHECK_EQ(2, epilogue_call_count);
10458  CHECK_EQ(1, prologue_call_count_second);
10459  CHECK_EQ(1, epilogue_call_count_second);
10460  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10461  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10462  i::Heap::CollectAllGarbage(false);
10463  CHECK_EQ(2, prologue_call_count);
10464  CHECK_EQ(2, epilogue_call_count);
10465  CHECK_EQ(2, prologue_call_count_second);
10466  CHECK_EQ(2, epilogue_call_count_second);
10467  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10468  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
10469  i::Heap::CollectAllGarbage(false);
10470  CHECK_EQ(2, prologue_call_count);
10471  CHECK_EQ(2, epilogue_call_count);
10472  CHECK_EQ(2, prologue_call_count_second);
10473  CHECK_EQ(2, epilogue_call_count_second);
10474}
10475
10476
10477THREADED_TEST(AddToJSFunctionResultCache) {
10478  i::FLAG_allow_natives_syntax = true;
10479  v8::HandleScope scope;
10480
10481  LocalContext context;
10482
10483  const char* code =
10484      "(function() {"
10485      "  var key0 = 'a';"
10486      "  var key1 = 'b';"
10487      "  var r0 = %_GetFromCache(0, key0);"
10488      "  var r1 = %_GetFromCache(0, key1);"
10489      "  var r0_ = %_GetFromCache(0, key0);"
10490      "  if (r0 !== r0_)"
10491      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
10492      "  var r1_ = %_GetFromCache(0, key1);"
10493      "  if (r1 !== r1_)"
10494      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
10495      "  return 'PASSED';"
10496      "})()";
10497  v8::internal::Heap::ClearJSFunctionResultCaches();
10498  ExpectString(code, "PASSED");
10499}
10500
10501
10502static const int k0CacheSize = 16;
10503
10504THREADED_TEST(FillJSFunctionResultCache) {
10505  i::FLAG_allow_natives_syntax = true;
10506  v8::HandleScope scope;
10507
10508  LocalContext context;
10509
10510  const char* code =
10511      "(function() {"
10512      "  var k = 'a';"
10513      "  var r = %_GetFromCache(0, k);"
10514      "  for (var i = 0; i < 16; i++) {"
10515      "    %_GetFromCache(0, 'a' + i);"
10516      "  };"
10517      "  if (r === %_GetFromCache(0, k))"
10518      "    return 'FAILED: k0CacheSize is too small';"
10519      "  return 'PASSED';"
10520      "})()";
10521  v8::internal::Heap::ClearJSFunctionResultCaches();
10522  ExpectString(code, "PASSED");
10523}
10524
10525
10526THREADED_TEST(RoundRobinGetFromCache) {
10527  i::FLAG_allow_natives_syntax = true;
10528  v8::HandleScope scope;
10529
10530  LocalContext context;
10531
10532  const char* code =
10533      "(function() {"
10534      "  var keys = [];"
10535      "  for (var i = 0; i < 16; i++) keys.push(i);"
10536      "  var values = [];"
10537      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10538      "  for (var i = 0; i < 16; i++) {"
10539      "    var v = %_GetFromCache(0, keys[i]);"
10540      "    if (v !== values[i])"
10541      "      return 'Wrong value for ' + "
10542      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10543      "  };"
10544      "  return 'PASSED';"
10545      "})()";
10546  v8::internal::Heap::ClearJSFunctionResultCaches();
10547  ExpectString(code, "PASSED");
10548}
10549
10550
10551THREADED_TEST(ReverseGetFromCache) {
10552  i::FLAG_allow_natives_syntax = true;
10553  v8::HandleScope scope;
10554
10555  LocalContext context;
10556
10557  const char* code =
10558      "(function() {"
10559      "  var keys = [];"
10560      "  for (var i = 0; i < 16; i++) keys.push(i);"
10561      "  var values = [];"
10562      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10563      "  for (var i = 15; i >= 16; i--) {"
10564      "    var v = %_GetFromCache(0, keys[i]);"
10565      "    if (v !== values[i])"
10566      "      return 'Wrong value for ' + "
10567      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10568      "  };"
10569      "  return 'PASSED';"
10570      "})()";
10571  v8::internal::Heap::ClearJSFunctionResultCaches();
10572  ExpectString(code, "PASSED");
10573}
10574
10575
10576THREADED_TEST(TestEviction) {
10577  i::FLAG_allow_natives_syntax = true;
10578  v8::HandleScope scope;
10579
10580  LocalContext context;
10581
10582  const char* code =
10583      "(function() {"
10584      "  for (var i = 0; i < 2*16; i++) {"
10585      "    %_GetFromCache(0, 'a' + i);"
10586      "  };"
10587      "  return 'PASSED';"
10588      "})()";
10589  v8::internal::Heap::ClearJSFunctionResultCaches();
10590  ExpectString(code, "PASSED");
10591}
10592