test-api.cc revision 7f4d5bd8c03935e2c0cd412e561b8fc5a6a880ae
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#define USE_NEW_QUERY_CALLBACKS
31
32#include "v8.h"
33
34#include "api.h"
35#include "compilation-cache.h"
36#include "execution.h"
37#include "snapshot.h"
38#include "platform.h"
39#include "top.h"
40#include "utils.h"
41#include "cctest.h"
42
43static const bool kLogThreading = true;
44
45static bool IsNaN(double x) {
46#ifdef WIN32
47  return _isnan(x);
48#else
49  return isnan(x);
50#endif
51}
52
53using ::v8::ObjectTemplate;
54using ::v8::Value;
55using ::v8::Context;
56using ::v8::Local;
57using ::v8::String;
58using ::v8::Script;
59using ::v8::Function;
60using ::v8::AccessorInfo;
61using ::v8::Extension;
62
63namespace i = ::v8::internal;
64
65
66static void ExpectString(const char* code, const char* expected) {
67  Local<Value> result = CompileRun(code);
68  CHECK(result->IsString());
69  String::AsciiValue ascii(result);
70  CHECK_EQ(expected, *ascii);
71}
72
73
74static void ExpectBoolean(const char* code, bool expected) {
75  Local<Value> result = CompileRun(code);
76  CHECK(result->IsBoolean());
77  CHECK_EQ(expected, result->BooleanValue());
78}
79
80
81static void ExpectTrue(const char* code) {
82  ExpectBoolean(code, true);
83}
84
85
86static void ExpectObject(const char* code, Local<Value> expected) {
87  Local<Value> result = CompileRun(code);
88  CHECK(result->Equals(expected));
89}
90
91
92static int signature_callback_count;
93static v8::Handle<Value> IncrementingSignatureCallback(
94    const v8::Arguments& args) {
95  ApiTestFuzzer::Fuzz();
96  signature_callback_count++;
97  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
98  for (int i = 0; i < args.Length(); i++)
99    result->Set(v8::Integer::New(i), args[i]);
100  return result;
101}
102
103
104static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
105  ApiTestFuzzer::Fuzz();
106  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
107  for (int i = 0; i < args.Length(); i++) {
108    result->Set(v8::Integer::New(i), args[i]);
109  }
110  return result;
111}
112
113
114THREADED_TEST(Handles) {
115  v8::HandleScope scope;
116  Local<Context> local_env;
117  {
118    LocalContext env;
119    local_env = env.local();
120  }
121
122  // Local context should still be live.
123  CHECK(!local_env.IsEmpty());
124  local_env->Enter();
125
126  v8::Handle<v8::Primitive> undef = v8::Undefined();
127  CHECK(!undef.IsEmpty());
128  CHECK(undef->IsUndefined());
129
130  const char* c_source = "1 + 2 + 3";
131  Local<String> source = String::New(c_source);
132  Local<Script> script = Script::Compile(source);
133  CHECK_EQ(6, script->Run()->Int32Value());
134
135  local_env->Exit();
136}
137
138
139THREADED_TEST(ReceiverSignature) {
140  v8::HandleScope scope;
141  LocalContext env;
142  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
143  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
144  fun->PrototypeTemplate()->Set(
145      v8_str("m"),
146      v8::FunctionTemplate::New(IncrementingSignatureCallback,
147                                v8::Handle<Value>(),
148                                sig));
149  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
150  signature_callback_count = 0;
151  CompileRun(
152      "var o = new Fun();"
153      "o.m();");
154  CHECK_EQ(1, signature_callback_count);
155  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
156  sub_fun->Inherit(fun);
157  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
158  CompileRun(
159      "var o = new SubFun();"
160      "o.m();");
161  CHECK_EQ(2, signature_callback_count);
162
163  v8::TryCatch try_catch;
164  CompileRun(
165      "var o = { };"
166      "o.m = Fun.prototype.m;"
167      "o.m();");
168  CHECK_EQ(2, signature_callback_count);
169  CHECK(try_catch.HasCaught());
170  try_catch.Reset();
171  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
172  sub_fun->Inherit(fun);
173  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
174  CompileRun(
175      "var o = new UnrelFun();"
176      "o.m = Fun.prototype.m;"
177      "o.m();");
178  CHECK_EQ(2, signature_callback_count);
179  CHECK(try_catch.HasCaught());
180}
181
182
183
184
185THREADED_TEST(ArgumentSignature) {
186  v8::HandleScope scope;
187  LocalContext env;
188  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
189  cons->SetClassName(v8_str("Cons"));
190  v8::Handle<v8::Signature> sig =
191      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
192  v8::Handle<v8::FunctionTemplate> fun =
193      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
194  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
195  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
196
197  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
198  CHECK(value1->IsTrue());
199
200  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
201  CHECK(value2->IsTrue());
202
203  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
204  CHECK(value3->IsTrue());
205
206  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
207  cons1->SetClassName(v8_str("Cons1"));
208  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
209  cons2->SetClassName(v8_str("Cons2"));
210  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
211  cons3->SetClassName(v8_str("Cons3"));
212
213  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
214  v8::Handle<v8::Signature> wsig =
215      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
216  v8::Handle<v8::FunctionTemplate> fun2 =
217      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
218
219  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
220  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
221  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
222  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
223  v8::Handle<Value> value4 = CompileRun(
224      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
225      "'[object Cons1],[object Cons2],[object Cons3]'");
226  CHECK(value4->IsTrue());
227
228  v8::Handle<Value> value5 = CompileRun(
229      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
230  CHECK(value5->IsTrue());
231
232  v8::Handle<Value> value6 = CompileRun(
233      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
234  CHECK(value6->IsTrue());
235
236  v8::Handle<Value> value7 = CompileRun(
237      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
238      "'[object Cons1],[object Cons2],[object Cons3],d';");
239  CHECK(value7->IsTrue());
240
241  v8::Handle<Value> value8 = CompileRun(
242      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
243  CHECK(value8->IsTrue());
244}
245
246
247THREADED_TEST(HulIgennem) {
248  v8::HandleScope scope;
249  LocalContext env;
250  v8::Handle<v8::Primitive> undef = v8::Undefined();
251  Local<String> undef_str = undef->ToString();
252  char* value = i::NewArray<char>(undef_str->Length() + 1);
253  undef_str->WriteAscii(value);
254  CHECK_EQ(0, strcmp(value, "undefined"));
255  i::DeleteArray(value);
256}
257
258
259THREADED_TEST(Access) {
260  v8::HandleScope scope;
261  LocalContext env;
262  Local<v8::Object> obj = v8::Object::New();
263  Local<Value> foo_before = obj->Get(v8_str("foo"));
264  CHECK(foo_before->IsUndefined());
265  Local<String> bar_str = v8_str("bar");
266  obj->Set(v8_str("foo"), bar_str);
267  Local<Value> foo_after = obj->Get(v8_str("foo"));
268  CHECK(!foo_after->IsUndefined());
269  CHECK(foo_after->IsString());
270  CHECK_EQ(bar_str, foo_after);
271}
272
273
274THREADED_TEST(AccessElement) {
275  v8::HandleScope scope;
276  LocalContext env;
277  Local<v8::Object> obj = v8::Object::New();
278  Local<Value> before = obj->Get(1);
279  CHECK(before->IsUndefined());
280  Local<String> bar_str = v8_str("bar");
281  obj->Set(1, bar_str);
282  Local<Value> after = obj->Get(1);
283  CHECK(!after->IsUndefined());
284  CHECK(after->IsString());
285  CHECK_EQ(bar_str, after);
286
287  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
288  CHECK_EQ(v8_str("a"), value->Get(0));
289  CHECK_EQ(v8_str("b"), value->Get(1));
290}
291
292
293THREADED_TEST(Script) {
294  v8::HandleScope scope;
295  LocalContext env;
296  const char* c_source = "1 + 2 + 3";
297  Local<String> source = String::New(c_source);
298  Local<Script> script = Script::Compile(source);
299  CHECK_EQ(6, script->Run()->Int32Value());
300}
301
302
303static uint16_t* AsciiToTwoByteString(const char* source) {
304  int array_length = i::StrLength(source) + 1;
305  uint16_t* converted = i::NewArray<uint16_t>(array_length);
306  for (int i = 0; i < array_length; i++) converted[i] = source[i];
307  return converted;
308}
309
310
311class TestResource: public String::ExternalStringResource {
312 public:
313  static int dispose_count;
314
315  explicit TestResource(uint16_t* data)
316      : data_(data), length_(0) {
317    while (data[length_]) ++length_;
318  }
319
320  ~TestResource() {
321    i::DeleteArray(data_);
322    ++dispose_count;
323  }
324
325  const uint16_t* data() const {
326    return data_;
327  }
328
329  size_t length() const {
330    return length_;
331  }
332 private:
333  uint16_t* data_;
334  size_t length_;
335};
336
337
338int TestResource::dispose_count = 0;
339
340
341class TestAsciiResource: public String::ExternalAsciiStringResource {
342 public:
343  static int dispose_count;
344
345  explicit TestAsciiResource(const char* data)
346      : data_(data),
347        length_(strlen(data)) { }
348
349  ~TestAsciiResource() {
350    i::DeleteArray(data_);
351    ++dispose_count;
352  }
353
354  const char* data() const {
355    return data_;
356  }
357
358  size_t length() const {
359    return length_;
360  }
361 private:
362  const char* data_;
363  size_t length_;
364};
365
366
367int TestAsciiResource::dispose_count = 0;
368
369
370THREADED_TEST(ScriptUsingStringResource) {
371  TestResource::dispose_count = 0;
372  const char* c_source = "1 + 2 * 3";
373  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
374  {
375    v8::HandleScope scope;
376    LocalContext env;
377    TestResource* resource = new TestResource(two_byte_source);
378    Local<String> source = String::NewExternal(resource);
379    Local<Script> script = Script::Compile(source);
380    Local<Value> value = script->Run();
381    CHECK(value->IsNumber());
382    CHECK_EQ(7, value->Int32Value());
383    CHECK(source->IsExternal());
384    CHECK_EQ(resource,
385             static_cast<TestResource*>(source->GetExternalStringResource()));
386    v8::internal::Heap::CollectAllGarbage(false);
387    CHECK_EQ(0, TestResource::dispose_count);
388  }
389  v8::internal::CompilationCache::Clear();
390  v8::internal::Heap::CollectAllGarbage(false);
391  CHECK_EQ(1, TestResource::dispose_count);
392}
393
394
395THREADED_TEST(ScriptUsingAsciiStringResource) {
396  TestAsciiResource::dispose_count = 0;
397  const char* c_source = "1 + 2 * 3";
398  {
399    v8::HandleScope scope;
400    LocalContext env;
401    Local<String> source =
402        String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
403    Local<Script> script = Script::Compile(source);
404    Local<Value> value = script->Run();
405    CHECK(value->IsNumber());
406    CHECK_EQ(7, value->Int32Value());
407    v8::internal::Heap::CollectAllGarbage(false);
408    CHECK_EQ(0, TestAsciiResource::dispose_count);
409  }
410  v8::internal::CompilationCache::Clear();
411  v8::internal::Heap::CollectAllGarbage(false);
412  CHECK_EQ(1, TestAsciiResource::dispose_count);
413}
414
415
416THREADED_TEST(ScriptMakingExternalString) {
417  TestResource::dispose_count = 0;
418  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
419  {
420    v8::HandleScope scope;
421    LocalContext env;
422    Local<String> source = String::New(two_byte_source);
423    // Trigger GCs so that the newly allocated string moves to old gen.
424    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
425    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
426    bool success = source->MakeExternal(new TestResource(two_byte_source));
427    CHECK(success);
428    Local<Script> script = Script::Compile(source);
429    Local<Value> value = script->Run();
430    CHECK(value->IsNumber());
431    CHECK_EQ(7, value->Int32Value());
432    v8::internal::Heap::CollectAllGarbage(false);
433    CHECK_EQ(0, TestResource::dispose_count);
434  }
435  v8::internal::CompilationCache::Clear();
436  v8::internal::Heap::CollectAllGarbage(false);
437  CHECK_EQ(1, TestResource::dispose_count);
438}
439
440
441THREADED_TEST(ScriptMakingExternalAsciiString) {
442  TestAsciiResource::dispose_count = 0;
443  const char* c_source = "1 + 2 * 3";
444  {
445    v8::HandleScope scope;
446    LocalContext env;
447    Local<String> source = v8_str(c_source);
448    // Trigger GCs so that the newly allocated string moves to old gen.
449    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
450    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
451    bool success = source->MakeExternal(
452        new TestAsciiResource(i::StrDup(c_source)));
453    CHECK(success);
454    Local<Script> script = Script::Compile(source);
455    Local<Value> value = script->Run();
456    CHECK(value->IsNumber());
457    CHECK_EQ(7, value->Int32Value());
458    v8::internal::Heap::CollectAllGarbage(false);
459    CHECK_EQ(0, TestAsciiResource::dispose_count);
460  }
461  v8::internal::CompilationCache::Clear();
462  v8::internal::Heap::CollectAllGarbage(false);
463  CHECK_EQ(1, TestAsciiResource::dispose_count);
464}
465
466
467TEST(MakingExternalStringConditions) {
468  v8::HandleScope scope;
469  LocalContext env;
470
471  // Free some space in the new space so that we can check freshness.
472  i::Heap::CollectGarbage(0, i::NEW_SPACE);
473  i::Heap::CollectGarbage(0, i::NEW_SPACE);
474
475  Local<String> small_string = String::New(AsciiToTwoByteString("small"));
476  // We should refuse to externalize newly created small string.
477  CHECK(!small_string->CanMakeExternal());
478  // Trigger GCs so that the newly allocated string moves to old gen.
479  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
480  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
481  // Old space strings should be accepted.
482  CHECK(small_string->CanMakeExternal());
483
484  small_string = String::New(AsciiToTwoByteString("small 2"));
485  // We should refuse externalizing newly created small string.
486  CHECK(!small_string->CanMakeExternal());
487  for (int i = 0; i < 100; i++) {
488    String::Value value(small_string);
489  }
490  // Frequently used strings should be accepted.
491  CHECK(small_string->CanMakeExternal());
492
493  const int buf_size = 10 * 1024;
494  char* buf = i::NewArray<char>(buf_size);
495  memset(buf, 'a', buf_size);
496  buf[buf_size - 1] = '\0';
497  Local<String> large_string = String::New(AsciiToTwoByteString(buf));
498  i::DeleteArray(buf);
499  // Large strings should be immediately accepted.
500  CHECK(large_string->CanMakeExternal());
501}
502
503
504TEST(MakingExternalAsciiStringConditions) {
505  v8::HandleScope scope;
506  LocalContext env;
507
508  // Free some space in the new space so that we can check freshness.
509  i::Heap::CollectGarbage(0, i::NEW_SPACE);
510  i::Heap::CollectGarbage(0, i::NEW_SPACE);
511
512  Local<String> small_string = String::New("small");
513  // We should refuse to externalize newly created small string.
514  CHECK(!small_string->CanMakeExternal());
515  // Trigger GCs so that the newly allocated string moves to old gen.
516  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
517  i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
518  // Old space strings should be accepted.
519  CHECK(small_string->CanMakeExternal());
520
521  small_string = String::New("small 2");
522  // We should refuse externalizing newly created small string.
523  CHECK(!small_string->CanMakeExternal());
524  for (int i = 0; i < 100; i++) {
525    String::Value value(small_string);
526  }
527  // Frequently used strings should be accepted.
528  CHECK(small_string->CanMakeExternal());
529
530  const int buf_size = 10 * 1024;
531  char* buf = i::NewArray<char>(buf_size);
532  memset(buf, 'a', buf_size);
533  buf[buf_size - 1] = '\0';
534  Local<String> large_string = String::New(buf);
535  i::DeleteArray(buf);
536  // Large strings should be immediately accepted.
537  CHECK(large_string->CanMakeExternal());
538}
539
540
541THREADED_TEST(UsingExternalString) {
542  {
543    v8::HandleScope scope;
544    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
545    Local<String> string =
546        String::NewExternal(new TestResource(two_byte_string));
547    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
548    // Trigger GCs so that the newly allocated string moves to old gen.
549    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
550    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
551    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
552    CHECK(isymbol->IsSymbol());
553  }
554  i::Heap::CollectAllGarbage(false);
555  i::Heap::CollectAllGarbage(false);
556}
557
558
559THREADED_TEST(UsingExternalAsciiString) {
560  {
561    v8::HandleScope scope;
562    const char* one_byte_string = "test string";
563    Local<String> string = String::NewExternal(
564        new TestAsciiResource(i::StrDup(one_byte_string)));
565    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
566    // Trigger GCs so that the newly allocated string moves to old gen.
567    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
568    i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
569    i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
570    CHECK(isymbol->IsSymbol());
571  }
572  i::Heap::CollectAllGarbage(false);
573  i::Heap::CollectAllGarbage(false);
574}
575
576
577THREADED_TEST(ScavengeExternalString) {
578  TestResource::dispose_count = 0;
579  bool in_new_space = false;
580  {
581    v8::HandleScope scope;
582    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
583    Local<String> string =
584        String::NewExternal(new TestResource(two_byte_string));
585    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
586    i::Heap::CollectGarbage(0, i::NEW_SPACE);
587    in_new_space = i::Heap::InNewSpace(*istring);
588    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
589    CHECK_EQ(0, TestResource::dispose_count);
590  }
591  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
592  CHECK_EQ(1, TestResource::dispose_count);
593}
594
595
596THREADED_TEST(ScavengeExternalAsciiString) {
597  TestAsciiResource::dispose_count = 0;
598  bool in_new_space = false;
599  {
600    v8::HandleScope scope;
601    const char* one_byte_string = "test string";
602    Local<String> string = String::NewExternal(
603        new TestAsciiResource(i::StrDup(one_byte_string)));
604    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
605    i::Heap::CollectGarbage(0, i::NEW_SPACE);
606    in_new_space = i::Heap::InNewSpace(*istring);
607    CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
608    CHECK_EQ(0, TestAsciiResource::dispose_count);
609  }
610  i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
611  CHECK_EQ(1, TestAsciiResource::dispose_count);
612}
613
614
615class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
616 public:
617  static int dispose_calls;
618
619  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
620      : TestAsciiResource(data),
621        dispose_(dispose) { }
622
623  void Dispose() {
624    ++dispose_calls;
625    if (dispose_) delete this;
626  }
627 private:
628  bool dispose_;
629};
630
631
632int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
633
634
635TEST(ExternalStringWithDisposeHandling) {
636  const char* c_source = "1 + 2 * 3";
637
638  // Use a stack allocated external string resource allocated object.
639  TestAsciiResource::dispose_count = 0;
640  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
641  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
642  {
643    v8::HandleScope scope;
644    LocalContext env;
645    Local<String> source =  String::NewExternal(&res_stack);
646    Local<Script> script = Script::Compile(source);
647    Local<Value> value = script->Run();
648    CHECK(value->IsNumber());
649    CHECK_EQ(7, value->Int32Value());
650    v8::internal::Heap::CollectAllGarbage(false);
651    CHECK_EQ(0, TestAsciiResource::dispose_count);
652  }
653  v8::internal::CompilationCache::Clear();
654  v8::internal::Heap::CollectAllGarbage(false);
655  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
656  CHECK_EQ(0, TestAsciiResource::dispose_count);
657
658  // Use a heap allocated external string resource allocated object.
659  TestAsciiResource::dispose_count = 0;
660  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
661  TestAsciiResource* res_heap =
662      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
663  {
664    v8::HandleScope scope;
665    LocalContext env;
666    Local<String> source =  String::NewExternal(res_heap);
667    Local<Script> script = Script::Compile(source);
668    Local<Value> value = script->Run();
669    CHECK(value->IsNumber());
670    CHECK_EQ(7, value->Int32Value());
671    v8::internal::Heap::CollectAllGarbage(false);
672    CHECK_EQ(0, TestAsciiResource::dispose_count);
673  }
674  v8::internal::CompilationCache::Clear();
675  v8::internal::Heap::CollectAllGarbage(false);
676  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
677  CHECK_EQ(1, TestAsciiResource::dispose_count);
678}
679
680
681THREADED_TEST(StringConcat) {
682  {
683    v8::HandleScope scope;
684    LocalContext env;
685    const char* one_byte_string_1 = "function a_times_t";
686    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
687    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
688    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
689    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
690    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
691    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
692    Local<String> left = v8_str(one_byte_string_1);
693    Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
694    Local<String> source = String::Concat(left, right);
695    right = String::NewExternal(
696        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
697    source = String::Concat(source, right);
698    right = String::NewExternal(
699        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
700    source = String::Concat(source, right);
701    right = v8_str(one_byte_string_2);
702    source = String::Concat(source, right);
703    right = String::New(AsciiToTwoByteString(two_byte_string_2));
704    source = String::Concat(source, right);
705    right = String::NewExternal(
706        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
707    source = String::Concat(source, right);
708    Local<Script> script = Script::Compile(source);
709    Local<Value> value = script->Run();
710    CHECK(value->IsNumber());
711    CHECK_EQ(68, value->Int32Value());
712  }
713  v8::internal::CompilationCache::Clear();
714  i::Heap::CollectAllGarbage(false);
715  i::Heap::CollectAllGarbage(false);
716}
717
718
719THREADED_TEST(GlobalProperties) {
720  v8::HandleScope scope;
721  LocalContext env;
722  v8::Handle<v8::Object> global = env->Global();
723  global->Set(v8_str("pi"), v8_num(3.1415926));
724  Local<Value> pi = global->Get(v8_str("pi"));
725  CHECK_EQ(3.1415926, pi->NumberValue());
726}
727
728
729static v8::Handle<Value> handle_call(const v8::Arguments& args) {
730  ApiTestFuzzer::Fuzz();
731  return v8_num(102);
732}
733
734
735static v8::Handle<Value> construct_call(const v8::Arguments& args) {
736  ApiTestFuzzer::Fuzz();
737  args.This()->Set(v8_str("x"), v8_num(1));
738  args.This()->Set(v8_str("y"), v8_num(2));
739  return args.This();
740}
741
742THREADED_TEST(FunctionTemplate) {
743  v8::HandleScope scope;
744  LocalContext env;
745  {
746    Local<v8::FunctionTemplate> fun_templ =
747        v8::FunctionTemplate::New(handle_call);
748    Local<Function> fun = fun_templ->GetFunction();
749    env->Global()->Set(v8_str("obj"), fun);
750    Local<Script> script = v8_compile("obj()");
751    CHECK_EQ(102, script->Run()->Int32Value());
752  }
753  // Use SetCallHandler to initialize a function template, should work like the
754  // previous one.
755  {
756    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
757    fun_templ->SetCallHandler(handle_call);
758    Local<Function> fun = fun_templ->GetFunction();
759    env->Global()->Set(v8_str("obj"), fun);
760    Local<Script> script = v8_compile("obj()");
761    CHECK_EQ(102, script->Run()->Int32Value());
762  }
763  // Test constructor calls.
764  {
765    Local<v8::FunctionTemplate> fun_templ =
766        v8::FunctionTemplate::New(construct_call);
767    fun_templ->SetClassName(v8_str("funky"));
768    Local<Function> fun = fun_templ->GetFunction();
769    env->Global()->Set(v8_str("obj"), fun);
770    Local<Script> script = v8_compile("var s = new obj(); s.x");
771    CHECK_EQ(1, script->Run()->Int32Value());
772
773    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
774    CHECK_EQ(v8_str("[object funky]"), result);
775  }
776}
777
778
779THREADED_TEST(FindInstanceInPrototypeChain) {
780  v8::HandleScope scope;
781  LocalContext env;
782
783  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
784  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
785  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
786  derived->Inherit(base);
787
788  Local<v8::Function> base_function = base->GetFunction();
789  Local<v8::Function> derived_function = derived->GetFunction();
790  Local<v8::Function> other_function = other->GetFunction();
791
792  Local<v8::Object> base_instance = base_function->NewInstance();
793  Local<v8::Object> derived_instance = derived_function->NewInstance();
794  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
795  Local<v8::Object> other_instance = other_function->NewInstance();
796  derived_instance2->Set(v8_str("__proto__"), derived_instance);
797  other_instance->Set(v8_str("__proto__"), derived_instance2);
798
799  // base_instance is only an instance of base.
800  CHECK_EQ(base_instance,
801           base_instance->FindInstanceInPrototypeChain(base));
802  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
803  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
804
805  // derived_instance is an instance of base and derived.
806  CHECK_EQ(derived_instance,
807           derived_instance->FindInstanceInPrototypeChain(base));
808  CHECK_EQ(derived_instance,
809           derived_instance->FindInstanceInPrototypeChain(derived));
810  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
811
812  // other_instance is an instance of other and its immediate
813  // prototype derived_instance2 is an instance of base and derived.
814  // Note, derived_instance is an instance of base and derived too,
815  // but it comes after derived_instance2 in the prototype chain of
816  // other_instance.
817  CHECK_EQ(derived_instance2,
818           other_instance->FindInstanceInPrototypeChain(base));
819  CHECK_EQ(derived_instance2,
820           other_instance->FindInstanceInPrototypeChain(derived));
821  CHECK_EQ(other_instance,
822           other_instance->FindInstanceInPrototypeChain(other));
823}
824
825
826THREADED_TEST(TinyInteger) {
827  v8::HandleScope scope;
828  LocalContext env;
829  int32_t value = 239;
830  Local<v8::Integer> value_obj = v8::Integer::New(value);
831  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
832}
833
834
835THREADED_TEST(BigSmiInteger) {
836  v8::HandleScope scope;
837  LocalContext env;
838  int32_t value = i::Smi::kMaxValue;
839  // We cannot add one to a Smi::kMaxValue without wrapping.
840  if (i::kSmiValueSize < 32) {
841    CHECK(i::Smi::IsValid(value));
842    CHECK(!i::Smi::IsValid(value + 1));
843    Local<v8::Integer> value_obj = v8::Integer::New(value);
844    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
845  }
846}
847
848
849THREADED_TEST(BigInteger) {
850  v8::HandleScope scope;
851  LocalContext env;
852  // We cannot add one to a Smi::kMaxValue without wrapping.
853  if (i::kSmiValueSize < 32) {
854    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
855    // The code will not be run in that case, due to the "if" guard.
856    int32_t value =
857        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
858    CHECK(value > i::Smi::kMaxValue);
859    CHECK(!i::Smi::IsValid(value));
860    Local<v8::Integer> value_obj = v8::Integer::New(value);
861    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
862  }
863}
864
865
866THREADED_TEST(TinyUnsignedInteger) {
867  v8::HandleScope scope;
868  LocalContext env;
869  uint32_t value = 239;
870  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
871  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
872}
873
874
875THREADED_TEST(BigUnsignedSmiInteger) {
876  v8::HandleScope scope;
877  LocalContext env;
878  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
879  CHECK(i::Smi::IsValid(value));
880  CHECK(!i::Smi::IsValid(value + 1));
881  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
882  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
883}
884
885
886THREADED_TEST(BigUnsignedInteger) {
887  v8::HandleScope scope;
888  LocalContext env;
889  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
890  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
891  CHECK(!i::Smi::IsValid(value));
892  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
893  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
894}
895
896
897THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
898  v8::HandleScope scope;
899  LocalContext env;
900  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
901  uint32_t value = INT32_MAX_AS_UINT + 1;
902  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
903  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
904  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
905}
906
907
908THREADED_TEST(Number) {
909  v8::HandleScope scope;
910  LocalContext env;
911  double PI = 3.1415926;
912  Local<v8::Number> pi_obj = v8::Number::New(PI);
913  CHECK_EQ(PI, pi_obj->NumberValue());
914}
915
916
917THREADED_TEST(ToNumber) {
918  v8::HandleScope scope;
919  LocalContext env;
920  Local<String> str = v8_str("3.1415926");
921  CHECK_EQ(3.1415926, str->NumberValue());
922  v8::Handle<v8::Boolean> t = v8::True();
923  CHECK_EQ(1.0, t->NumberValue());
924  v8::Handle<v8::Boolean> f = v8::False();
925  CHECK_EQ(0.0, f->NumberValue());
926}
927
928
929THREADED_TEST(Date) {
930  v8::HandleScope scope;
931  LocalContext env;
932  double PI = 3.1415926;
933  Local<Value> date_obj = v8::Date::New(PI);
934  CHECK_EQ(3.0, date_obj->NumberValue());
935}
936
937
938THREADED_TEST(Boolean) {
939  v8::HandleScope scope;
940  LocalContext env;
941  v8::Handle<v8::Boolean> t = v8::True();
942  CHECK(t->Value());
943  v8::Handle<v8::Boolean> f = v8::False();
944  CHECK(!f->Value());
945  v8::Handle<v8::Primitive> u = v8::Undefined();
946  CHECK(!u->BooleanValue());
947  v8::Handle<v8::Primitive> n = v8::Null();
948  CHECK(!n->BooleanValue());
949  v8::Handle<String> str1 = v8_str("");
950  CHECK(!str1->BooleanValue());
951  v8::Handle<String> str2 = v8_str("x");
952  CHECK(str2->BooleanValue());
953  CHECK(!v8::Number::New(0)->BooleanValue());
954  CHECK(v8::Number::New(-1)->BooleanValue());
955  CHECK(v8::Number::New(1)->BooleanValue());
956  CHECK(v8::Number::New(42)->BooleanValue());
957  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
958}
959
960
961static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
962  ApiTestFuzzer::Fuzz();
963  return v8_num(13.4);
964}
965
966
967static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
968  ApiTestFuzzer::Fuzz();
969  return v8_num(876);
970}
971
972
973THREADED_TEST(GlobalPrototype) {
974  v8::HandleScope scope;
975  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
976  func_templ->PrototypeTemplate()->Set(
977      "dummy",
978      v8::FunctionTemplate::New(DummyCallHandler));
979  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
980  templ->Set("x", v8_num(200));
981  templ->SetAccessor(v8_str("m"), GetM);
982  LocalContext env(0, templ);
983  v8::Handle<v8::Object> obj = env->Global();
984  v8::Handle<Script> script = v8_compile("dummy()");
985  v8::Handle<Value> result = script->Run();
986  CHECK_EQ(13.4, result->NumberValue());
987  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
988  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
989}
990
991
992THREADED_TEST(ObjectTemplate) {
993  v8::HandleScope scope;
994  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
995  templ1->Set("x", v8_num(10));
996  templ1->Set("y", v8_num(13));
997  LocalContext env;
998  Local<v8::Object> instance1 = templ1->NewInstance();
999  env->Global()->Set(v8_str("p"), instance1);
1000  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1001  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1002  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1003  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1004  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1005  templ2->Set("a", v8_num(12));
1006  templ2->Set("b", templ1);
1007  Local<v8::Object> instance2 = templ2->NewInstance();
1008  env->Global()->Set(v8_str("q"), instance2);
1009  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1010  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1011  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1012  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1013}
1014
1015
1016static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1017  ApiTestFuzzer::Fuzz();
1018  return v8_num(17.2);
1019}
1020
1021
1022static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1023  ApiTestFuzzer::Fuzz();
1024  return v8_num(15.2);
1025}
1026
1027
1028THREADED_TEST(DescriptorInheritance) {
1029  v8::HandleScope scope;
1030  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1031  super->PrototypeTemplate()->Set("flabby",
1032                                  v8::FunctionTemplate::New(GetFlabby));
1033  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1034
1035  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1036
1037  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1038  base1->Inherit(super);
1039  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1040
1041  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1042  base2->Inherit(super);
1043  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1044
1045  LocalContext env;
1046
1047  env->Global()->Set(v8_str("s"), super->GetFunction());
1048  env->Global()->Set(v8_str("base1"), base1->GetFunction());
1049  env->Global()->Set(v8_str("base2"), base2->GetFunction());
1050
1051  // Checks right __proto__ chain.
1052  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1053  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1054
1055  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1056
1057  // Instance accessor should not be visible on function object or its prototype
1058  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1059  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1060  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1061
1062  env->Global()->Set(v8_str("obj"),
1063                     base1->GetFunction()->NewInstance());
1064  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1065  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1066  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1067  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1068  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1069
1070  env->Global()->Set(v8_str("obj2"),
1071                     base2->GetFunction()->NewInstance());
1072  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1073  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1074  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1075  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1076  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1077
1078  // base1 and base2 cannot cross reference to each's prototype
1079  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1080  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1081}
1082
1083
1084int echo_named_call_count;
1085
1086
1087static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1088                                           const AccessorInfo& info) {
1089  ApiTestFuzzer::Fuzz();
1090  CHECK_EQ(v8_str("data"), info.Data());
1091  echo_named_call_count++;
1092  return name;
1093}
1094
1095
1096THREADED_TEST(NamedPropertyHandlerGetter) {
1097  echo_named_call_count = 0;
1098  v8::HandleScope scope;
1099  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1100  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1101                                                     0, 0, 0, 0,
1102                                                     v8_str("data"));
1103  LocalContext env;
1104  env->Global()->Set(v8_str("obj"),
1105                     templ->GetFunction()->NewInstance());
1106  CHECK_EQ(echo_named_call_count, 0);
1107  v8_compile("obj.x")->Run();
1108  CHECK_EQ(echo_named_call_count, 1);
1109  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1110  v8::Handle<Value> str = CompileRun(code);
1111  String::AsciiValue value(str);
1112  CHECK_EQ(*value, "oddlepoddle");
1113  // Check default behavior
1114  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1115  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1116  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1117}
1118
1119
1120int echo_indexed_call_count = 0;
1121
1122
1123static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1124                                             const AccessorInfo& info) {
1125  ApiTestFuzzer::Fuzz();
1126  CHECK_EQ(v8_num(637), info.Data());
1127  echo_indexed_call_count++;
1128  return v8_num(index);
1129}
1130
1131
1132THREADED_TEST(IndexedPropertyHandlerGetter) {
1133  v8::HandleScope scope;
1134  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1135  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1136                                                       0, 0, 0, 0,
1137                                                       v8_num(637));
1138  LocalContext env;
1139  env->Global()->Set(v8_str("obj"),
1140                     templ->GetFunction()->NewInstance());
1141  Local<Script> script = v8_compile("obj[900]");
1142  CHECK_EQ(script->Run()->Int32Value(), 900);
1143}
1144
1145
1146v8::Handle<v8::Object> bottom;
1147
1148static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1149    uint32_t index,
1150    const AccessorInfo& info) {
1151  ApiTestFuzzer::Fuzz();
1152  CHECK(info.This()->Equals(bottom));
1153  return v8::Handle<Value>();
1154}
1155
1156static v8::Handle<Value> CheckThisNamedPropertyHandler(
1157    Local<String> name,
1158    const AccessorInfo& info) {
1159  ApiTestFuzzer::Fuzz();
1160  CHECK(info.This()->Equals(bottom));
1161  return v8::Handle<Value>();
1162}
1163
1164
1165v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1166                                                 Local<Value> value,
1167                                                 const AccessorInfo& info) {
1168  ApiTestFuzzer::Fuzz();
1169  CHECK(info.This()->Equals(bottom));
1170  return v8::Handle<Value>();
1171}
1172
1173
1174v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1175                                               Local<Value> value,
1176                                               const AccessorInfo& info) {
1177  ApiTestFuzzer::Fuzz();
1178  CHECK(info.This()->Equals(bottom));
1179  return v8::Handle<Value>();
1180}
1181
1182v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1183    uint32_t index,
1184    const AccessorInfo& info) {
1185  ApiTestFuzzer::Fuzz();
1186  CHECK(info.This()->Equals(bottom));
1187  return v8::Handle<v8::Boolean>();
1188}
1189
1190
1191v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1192                                                    const AccessorInfo& info) {
1193  ApiTestFuzzer::Fuzz();
1194  CHECK(info.This()->Equals(bottom));
1195  return v8::Handle<v8::Integer>();
1196}
1197
1198
1199v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1200    uint32_t index,
1201    const AccessorInfo& info) {
1202  ApiTestFuzzer::Fuzz();
1203  CHECK(info.This()->Equals(bottom));
1204  return v8::Handle<v8::Boolean>();
1205}
1206
1207
1208v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1209    Local<String> property,
1210    const AccessorInfo& info) {
1211  ApiTestFuzzer::Fuzz();
1212  CHECK(info.This()->Equals(bottom));
1213  return v8::Handle<v8::Boolean>();
1214}
1215
1216
1217v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1218    const AccessorInfo& info) {
1219  ApiTestFuzzer::Fuzz();
1220  CHECK(info.This()->Equals(bottom));
1221  return v8::Handle<v8::Array>();
1222}
1223
1224
1225v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1226    const AccessorInfo& info) {
1227  ApiTestFuzzer::Fuzz();
1228  CHECK(info.This()->Equals(bottom));
1229  return v8::Handle<v8::Array>();
1230}
1231
1232
1233THREADED_TEST(PropertyHandlerInPrototype) {
1234  v8::HandleScope scope;
1235  LocalContext env;
1236
1237  // Set up a prototype chain with three interceptors.
1238  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1239  templ->InstanceTemplate()->SetIndexedPropertyHandler(
1240      CheckThisIndexedPropertyHandler,
1241      CheckThisIndexedPropertySetter,
1242      CheckThisIndexedPropertyQuery,
1243      CheckThisIndexedPropertyDeleter,
1244      CheckThisIndexedPropertyEnumerator);
1245
1246  templ->InstanceTemplate()->SetNamedPropertyHandler(
1247      CheckThisNamedPropertyHandler,
1248      CheckThisNamedPropertySetter,
1249      CheckThisNamedPropertyQuery,
1250      CheckThisNamedPropertyDeleter,
1251      CheckThisNamedPropertyEnumerator);
1252
1253  bottom = templ->GetFunction()->NewInstance();
1254  Local<v8::Object> top = templ->GetFunction()->NewInstance();
1255  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1256
1257  bottom->Set(v8_str("__proto__"), middle);
1258  middle->Set(v8_str("__proto__"), top);
1259  env->Global()->Set(v8_str("obj"), bottom);
1260
1261  // Indexed and named get.
1262  Script::Compile(v8_str("obj[0]"))->Run();
1263  Script::Compile(v8_str("obj.x"))->Run();
1264
1265  // Indexed and named set.
1266  Script::Compile(v8_str("obj[1] = 42"))->Run();
1267  Script::Compile(v8_str("obj.y = 42"))->Run();
1268
1269  // Indexed and named query.
1270  Script::Compile(v8_str("0 in obj"))->Run();
1271  Script::Compile(v8_str("'x' in obj"))->Run();
1272
1273  // Indexed and named deleter.
1274  Script::Compile(v8_str("delete obj[0]"))->Run();
1275  Script::Compile(v8_str("delete obj.x"))->Run();
1276
1277  // Enumerators.
1278  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1279}
1280
1281
1282static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1283                                               const AccessorInfo& info) {
1284  ApiTestFuzzer::Fuzz();
1285  if (v8_str("pre")->Equals(key)) {
1286    return v8_str("PrePropertyHandler: pre");
1287  }
1288  return v8::Handle<String>();
1289}
1290
1291
1292static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1293                                                       const AccessorInfo&) {
1294  if (v8_str("pre")->Equals(key)) {
1295    return v8::Integer::New(v8::None);
1296  }
1297
1298  return v8::Handle<v8::Integer>();  // do not intercept the call
1299}
1300
1301
1302THREADED_TEST(PrePropertyHandler) {
1303  v8::HandleScope scope;
1304  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1305  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1306                                                    0,
1307                                                    PrePropertyHandlerQuery);
1308  LocalContext env(NULL, desc->InstanceTemplate());
1309  Script::Compile(v8_str(
1310      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1311  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1312  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1313  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1314  CHECK_EQ(v8_str("Object: on"), result_on);
1315  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1316  CHECK(result_post.IsEmpty());
1317}
1318
1319
1320THREADED_TEST(UndefinedIsNotEnumerable) {
1321  v8::HandleScope scope;
1322  LocalContext env;
1323  v8::Handle<Value> result = Script::Compile(v8_str(
1324      "this.propertyIsEnumerable(undefined)"))->Run();
1325  CHECK(result->IsFalse());
1326}
1327
1328
1329v8::Handle<Script> call_recursively_script;
1330static const int kTargetRecursionDepth = 200;  // near maximum
1331
1332
1333static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1334  ApiTestFuzzer::Fuzz();
1335  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1336  if (depth == kTargetRecursionDepth) return v8::Undefined();
1337  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1338  return call_recursively_script->Run();
1339}
1340
1341
1342static v8::Handle<Value> CallFunctionRecursivelyCall(
1343    const v8::Arguments& args) {
1344  ApiTestFuzzer::Fuzz();
1345  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1346  if (depth == kTargetRecursionDepth) {
1347    printf("[depth = %d]\n", depth);
1348    return v8::Undefined();
1349  }
1350  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1351  v8::Handle<Value> function =
1352      args.This()->Get(v8_str("callFunctionRecursively"));
1353  return function.As<Function>()->Call(args.This(), 0, NULL);
1354}
1355
1356
1357THREADED_TEST(DeepCrossLanguageRecursion) {
1358  v8::HandleScope scope;
1359  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1360  global->Set(v8_str("callScriptRecursively"),
1361              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1362  global->Set(v8_str("callFunctionRecursively"),
1363              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1364  LocalContext env(NULL, global);
1365
1366  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1367  call_recursively_script = v8_compile("callScriptRecursively()");
1368  v8::Handle<Value> result = call_recursively_script->Run();
1369  call_recursively_script = v8::Handle<Script>();
1370
1371  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1372  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1373}
1374
1375
1376static v8::Handle<Value>
1377    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1378  ApiTestFuzzer::Fuzz();
1379  return v8::ThrowException(key);
1380}
1381
1382
1383static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1384                                                    Local<Value>,
1385                                                    const AccessorInfo&) {
1386  v8::ThrowException(key);
1387  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1388}
1389
1390
1391THREADED_TEST(CallbackExceptionRegression) {
1392  v8::HandleScope scope;
1393  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1394  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1395                               ThrowingPropertyHandlerSet);
1396  LocalContext env;
1397  env->Global()->Set(v8_str("obj"), obj->NewInstance());
1398  v8::Handle<Value> otto = Script::Compile(v8_str(
1399      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1400  CHECK_EQ(v8_str("otto"), otto);
1401  v8::Handle<Value> netto = Script::Compile(v8_str(
1402      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1403  CHECK_EQ(v8_str("netto"), netto);
1404}
1405
1406
1407THREADED_TEST(FunctionPrototype) {
1408  v8::HandleScope scope;
1409  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1410  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1411  LocalContext env;
1412  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1413  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1414  CHECK_EQ(script->Run()->Int32Value(), 321);
1415}
1416
1417
1418THREADED_TEST(InternalFields) {
1419  v8::HandleScope scope;
1420  LocalContext env;
1421
1422  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1423  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1424  instance_templ->SetInternalFieldCount(1);
1425  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1426  CHECK_EQ(1, obj->InternalFieldCount());
1427  CHECK(obj->GetInternalField(0)->IsUndefined());
1428  obj->SetInternalField(0, v8_num(17));
1429  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1430}
1431
1432
1433THREADED_TEST(GlobalObjectInternalFields) {
1434  v8::HandleScope scope;
1435  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1436  global_template->SetInternalFieldCount(1);
1437  LocalContext env(NULL, global_template);
1438  v8::Handle<v8::Object> global_proxy = env->Global();
1439  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1440  CHECK_EQ(1, global->InternalFieldCount());
1441  CHECK(global->GetInternalField(0)->IsUndefined());
1442  global->SetInternalField(0, v8_num(17));
1443  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1444}
1445
1446
1447THREADED_TEST(InternalFieldsNativePointers) {
1448  v8::HandleScope scope;
1449  LocalContext env;
1450
1451  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1452  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1453  instance_templ->SetInternalFieldCount(1);
1454  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1455  CHECK_EQ(1, obj->InternalFieldCount());
1456  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1457
1458  char* data = new char[100];
1459
1460  void* aligned = data;
1461  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1462  void* unaligned = data + 1;
1463  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1464
1465  // Check reading and writing aligned pointers.
1466  obj->SetPointerInInternalField(0, aligned);
1467  i::Heap::CollectAllGarbage(false);
1468  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1469
1470  // Check reading and writing unaligned pointers.
1471  obj->SetPointerInInternalField(0, unaligned);
1472  i::Heap::CollectAllGarbage(false);
1473  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1474
1475  delete[] data;
1476}
1477
1478
1479THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1480  v8::HandleScope scope;
1481  LocalContext env;
1482
1483  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1484  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1485  instance_templ->SetInternalFieldCount(1);
1486  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1487  CHECK_EQ(1, obj->InternalFieldCount());
1488  CHECK(obj->GetPointerFromInternalField(0) == NULL);
1489
1490  char* data = new char[100];
1491
1492  void* aligned = data;
1493  CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1494  void* unaligned = data + 1;
1495  CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1496
1497  obj->SetPointerInInternalField(0, aligned);
1498  i::Heap::CollectAllGarbage(false);
1499  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1500
1501  obj->SetPointerInInternalField(0, unaligned);
1502  i::Heap::CollectAllGarbage(false);
1503  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1504
1505  obj->SetInternalField(0, v8::External::Wrap(aligned));
1506  i::Heap::CollectAllGarbage(false);
1507  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1508
1509  obj->SetInternalField(0, v8::External::Wrap(unaligned));
1510  i::Heap::CollectAllGarbage(false);
1511  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1512
1513  delete[] data;
1514}
1515
1516
1517THREADED_TEST(IdentityHash) {
1518  v8::HandleScope scope;
1519  LocalContext env;
1520
1521  // Ensure that the test starts with an fresh heap to test whether the hash
1522  // code is based on the address.
1523  i::Heap::CollectAllGarbage(false);
1524  Local<v8::Object> obj = v8::Object::New();
1525  int hash = obj->GetIdentityHash();
1526  int hash1 = obj->GetIdentityHash();
1527  CHECK_EQ(hash, hash1);
1528  int hash2 = v8::Object::New()->GetIdentityHash();
1529  // Since the identity hash is essentially a random number two consecutive
1530  // objects should not be assigned the same hash code. If the test below fails
1531  // the random number generator should be evaluated.
1532  CHECK_NE(hash, hash2);
1533  i::Heap::CollectAllGarbage(false);
1534  int hash3 = v8::Object::New()->GetIdentityHash();
1535  // Make sure that the identity hash is not based on the initial address of
1536  // the object alone. If the test below fails the random number generator
1537  // should be evaluated.
1538  CHECK_NE(hash, hash3);
1539  int hash4 = obj->GetIdentityHash();
1540  CHECK_EQ(hash, hash4);
1541}
1542
1543
1544THREADED_TEST(HiddenProperties) {
1545  v8::HandleScope scope;
1546  LocalContext env;
1547
1548  v8::Local<v8::Object> obj = v8::Object::New();
1549  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1550  v8::Local<v8::String> empty = v8_str("");
1551  v8::Local<v8::String> prop_name = v8_str("prop_name");
1552
1553  i::Heap::CollectAllGarbage(false);
1554
1555  // Make sure delete of a non-existent hidden value works
1556  CHECK(obj->DeleteHiddenValue(key));
1557
1558  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1559  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1560  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1561  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1562
1563  i::Heap::CollectAllGarbage(false);
1564
1565  // Make sure we do not find the hidden property.
1566  CHECK(!obj->Has(empty));
1567  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1568  CHECK(obj->Get(empty)->IsUndefined());
1569  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1570  CHECK(obj->Set(empty, v8::Integer::New(2003)));
1571  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1572  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1573
1574  i::Heap::CollectAllGarbage(false);
1575
1576  // Add another property and delete it afterwards to force the object in
1577  // slow case.
1578  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1579  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1580  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1581  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1582  CHECK(obj->Delete(prop_name));
1583  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1584
1585  i::Heap::CollectAllGarbage(false);
1586
1587  CHECK(obj->DeleteHiddenValue(key));
1588  CHECK(obj->GetHiddenValue(key).IsEmpty());
1589}
1590
1591
1592static bool interceptor_for_hidden_properties_called;
1593static v8::Handle<Value> InterceptorForHiddenProperties(
1594    Local<String> name, const AccessorInfo& info) {
1595  interceptor_for_hidden_properties_called = true;
1596  return v8::Handle<Value>();
1597}
1598
1599
1600THREADED_TEST(HiddenPropertiesWithInterceptors) {
1601  v8::HandleScope scope;
1602  LocalContext context;
1603
1604  interceptor_for_hidden_properties_called = false;
1605
1606  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1607
1608  // Associate an interceptor with an object and start setting hidden values.
1609  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1610  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1611  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1612  Local<v8::Function> function = fun_templ->GetFunction();
1613  Local<v8::Object> obj = function->NewInstance();
1614  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1615  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1616  CHECK(!interceptor_for_hidden_properties_called);
1617}
1618
1619
1620THREADED_TEST(External) {
1621  v8::HandleScope scope;
1622  int x = 3;
1623  Local<v8::External> ext = v8::External::New(&x);
1624  LocalContext env;
1625  env->Global()->Set(v8_str("ext"), ext);
1626  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1627  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
1628  int* ptr = static_cast<int*>(reext->Value());
1629  CHECK_EQ(x, 3);
1630  *ptr = 10;
1631  CHECK_EQ(x, 10);
1632
1633  // Make sure unaligned pointers are wrapped properly.
1634  char* data = i::StrDup("0123456789");
1635  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1636  Local<v8::Value> one = v8::External::Wrap(&data[1]);
1637  Local<v8::Value> two = v8::External::Wrap(&data[2]);
1638  Local<v8::Value> three = v8::External::Wrap(&data[3]);
1639
1640  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1641  CHECK_EQ('0', *char_ptr);
1642  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1643  CHECK_EQ('1', *char_ptr);
1644  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1645  CHECK_EQ('2', *char_ptr);
1646  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1647  CHECK_EQ('3', *char_ptr);
1648  i::DeleteArray(data);
1649}
1650
1651
1652THREADED_TEST(GlobalHandle) {
1653  v8::Persistent<String> global;
1654  {
1655    v8::HandleScope scope;
1656    Local<String> str = v8_str("str");
1657    global = v8::Persistent<String>::New(str);
1658  }
1659  CHECK_EQ(global->Length(), 3);
1660  global.Dispose();
1661}
1662
1663
1664THREADED_TEST(ScriptException) {
1665  v8::HandleScope scope;
1666  LocalContext env;
1667  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1668  v8::TryCatch try_catch;
1669  Local<Value> result = script->Run();
1670  CHECK(result.IsEmpty());
1671  CHECK(try_catch.HasCaught());
1672  String::AsciiValue exception_value(try_catch.Exception());
1673  CHECK_EQ(*exception_value, "panama!");
1674}
1675
1676
1677bool message_received;
1678
1679
1680static void check_message(v8::Handle<v8::Message> message,
1681                          v8::Handle<Value> data) {
1682  CHECK_EQ(5.76, data->NumberValue());
1683  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1684  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1685  message_received = true;
1686}
1687
1688
1689THREADED_TEST(MessageHandlerData) {
1690  message_received = false;
1691  v8::HandleScope scope;
1692  CHECK(!message_received);
1693  v8::V8::AddMessageListener(check_message, v8_num(5.76));
1694  LocalContext context;
1695  v8::ScriptOrigin origin =
1696      v8::ScriptOrigin(v8_str("6.75"));
1697  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1698                                                  &origin);
1699  script->SetData(v8_str("7.56"));
1700  script->Run();
1701  CHECK(message_received);
1702  // clear out the message listener
1703  v8::V8::RemoveMessageListeners(check_message);
1704}
1705
1706
1707THREADED_TEST(GetSetProperty) {
1708  v8::HandleScope scope;
1709  LocalContext context;
1710  context->Global()->Set(v8_str("foo"), v8_num(14));
1711  context->Global()->Set(v8_str("12"), v8_num(92));
1712  context->Global()->Set(v8::Integer::New(16), v8_num(32));
1713  context->Global()->Set(v8_num(13), v8_num(56));
1714  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1715  CHECK_EQ(14, foo->Int32Value());
1716  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1717  CHECK_EQ(92, twelve->Int32Value());
1718  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1719  CHECK_EQ(32, sixteen->Int32Value());
1720  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1721  CHECK_EQ(56, thirteen->Int32Value());
1722  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1723  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1724  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1725  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1726  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1727  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1728  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1729  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1730  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1731}
1732
1733
1734THREADED_TEST(PropertyAttributes) {
1735  v8::HandleScope scope;
1736  LocalContext context;
1737  // read-only
1738  Local<String> prop = v8_str("read_only");
1739  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1740  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1741  Script::Compile(v8_str("read_only = 9"))->Run();
1742  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1743  context->Global()->Set(prop, v8_num(10));
1744  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1745  // dont-delete
1746  prop = v8_str("dont_delete");
1747  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1748  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1749  Script::Compile(v8_str("delete dont_delete"))->Run();
1750  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1751}
1752
1753
1754THREADED_TEST(Array) {
1755  v8::HandleScope scope;
1756  LocalContext context;
1757  Local<v8::Array> array = v8::Array::New();
1758  CHECK_EQ(0, array->Length());
1759  CHECK(array->Get(0)->IsUndefined());
1760  CHECK(!array->Has(0));
1761  CHECK(array->Get(100)->IsUndefined());
1762  CHECK(!array->Has(100));
1763  array->Set(2, v8_num(7));
1764  CHECK_EQ(3, array->Length());
1765  CHECK(!array->Has(0));
1766  CHECK(!array->Has(1));
1767  CHECK(array->Has(2));
1768  CHECK_EQ(7, array->Get(2)->Int32Value());
1769  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1770  Local<v8::Array> arr = obj.As<v8::Array>();
1771  CHECK_EQ(3, arr->Length());
1772  CHECK_EQ(1, arr->Get(0)->Int32Value());
1773  CHECK_EQ(2, arr->Get(1)->Int32Value());
1774  CHECK_EQ(3, arr->Get(2)->Int32Value());
1775}
1776
1777
1778v8::Handle<Value> HandleF(const v8::Arguments& args) {
1779  v8::HandleScope scope;
1780  ApiTestFuzzer::Fuzz();
1781  Local<v8::Array> result = v8::Array::New(args.Length());
1782  for (int i = 0; i < args.Length(); i++)
1783    result->Set(i, args[i]);
1784  return scope.Close(result);
1785}
1786
1787
1788THREADED_TEST(Vector) {
1789  v8::HandleScope scope;
1790  Local<ObjectTemplate> global = ObjectTemplate::New();
1791  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1792  LocalContext context(0, global);
1793
1794  const char* fun = "f()";
1795  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
1796  CHECK_EQ(0, a0->Length());
1797
1798  const char* fun2 = "f(11)";
1799  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
1800  CHECK_EQ(1, a1->Length());
1801  CHECK_EQ(11, a1->Get(0)->Int32Value());
1802
1803  const char* fun3 = "f(12, 13)";
1804  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
1805  CHECK_EQ(2, a2->Length());
1806  CHECK_EQ(12, a2->Get(0)->Int32Value());
1807  CHECK_EQ(13, a2->Get(1)->Int32Value());
1808
1809  const char* fun4 = "f(14, 15, 16)";
1810  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
1811  CHECK_EQ(3, a3->Length());
1812  CHECK_EQ(14, a3->Get(0)->Int32Value());
1813  CHECK_EQ(15, a3->Get(1)->Int32Value());
1814  CHECK_EQ(16, a3->Get(2)->Int32Value());
1815
1816  const char* fun5 = "f(17, 18, 19, 20)";
1817  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
1818  CHECK_EQ(4, a4->Length());
1819  CHECK_EQ(17, a4->Get(0)->Int32Value());
1820  CHECK_EQ(18, a4->Get(1)->Int32Value());
1821  CHECK_EQ(19, a4->Get(2)->Int32Value());
1822  CHECK_EQ(20, a4->Get(3)->Int32Value());
1823}
1824
1825
1826THREADED_TEST(FunctionCall) {
1827  v8::HandleScope scope;
1828  LocalContext context;
1829  CompileRun(
1830    "function Foo() {"
1831    "  var result = [];"
1832    "  for (var i = 0; i < arguments.length; i++) {"
1833    "    result.push(arguments[i]);"
1834    "  }"
1835    "  return result;"
1836    "}");
1837  Local<Function> Foo =
1838      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1839
1840  v8::Handle<Value>* args0 = NULL;
1841  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1842  CHECK_EQ(0, a0->Length());
1843
1844  v8::Handle<Value> args1[] = { v8_num(1.1) };
1845  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1846  CHECK_EQ(1, a1->Length());
1847  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1848
1849  v8::Handle<Value> args2[] = { v8_num(2.2),
1850                                v8_num(3.3) };
1851  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1852  CHECK_EQ(2, a2->Length());
1853  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1854  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1855
1856  v8::Handle<Value> args3[] = { v8_num(4.4),
1857                                v8_num(5.5),
1858                                v8_num(6.6) };
1859  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1860  CHECK_EQ(3, a3->Length());
1861  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1862  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1863  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1864
1865  v8::Handle<Value> args4[] = { v8_num(7.7),
1866                                v8_num(8.8),
1867                                v8_num(9.9),
1868                                v8_num(10.11) };
1869  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1870  CHECK_EQ(4, a4->Length());
1871  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1872  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1873  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1874  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1875}
1876
1877
1878static const char* js_code_causing_out_of_memory =
1879    "var a = new Array(); while(true) a.push(a);";
1880
1881
1882// These tests run for a long time and prevent us from running tests
1883// that come after them so they cannot run in parallel.
1884TEST(OutOfMemory) {
1885  // It's not possible to read a snapshot into a heap with different dimensions.
1886  if (v8::internal::Snapshot::IsEnabled()) return;
1887  // Set heap limits.
1888  static const int K = 1024;
1889  v8::ResourceConstraints constraints;
1890  constraints.set_max_young_space_size(256 * K);
1891  constraints.set_max_old_space_size(4 * K * K);
1892  v8::SetResourceConstraints(&constraints);
1893
1894  // Execute a script that causes out of memory.
1895  v8::HandleScope scope;
1896  LocalContext context;
1897  v8::V8::IgnoreOutOfMemoryException();
1898  Local<Script> script =
1899      Script::Compile(String::New(js_code_causing_out_of_memory));
1900  Local<Value> result = script->Run();
1901
1902  // Check for out of memory state.
1903  CHECK(result.IsEmpty());
1904  CHECK(context->HasOutOfMemoryException());
1905}
1906
1907
1908v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1909  ApiTestFuzzer::Fuzz();
1910
1911  v8::HandleScope scope;
1912  LocalContext context;
1913  Local<Script> script =
1914      Script::Compile(String::New(js_code_causing_out_of_memory));
1915  Local<Value> result = script->Run();
1916
1917  // Check for out of memory state.
1918  CHECK(result.IsEmpty());
1919  CHECK(context->HasOutOfMemoryException());
1920
1921  return result;
1922}
1923
1924
1925TEST(OutOfMemoryNested) {
1926  // It's not possible to read a snapshot into a heap with different dimensions.
1927  if (v8::internal::Snapshot::IsEnabled()) return;
1928  // Set heap limits.
1929  static const int K = 1024;
1930  v8::ResourceConstraints constraints;
1931  constraints.set_max_young_space_size(256 * K);
1932  constraints.set_max_old_space_size(4 * K * K);
1933  v8::SetResourceConstraints(&constraints);
1934
1935  v8::HandleScope scope;
1936  Local<ObjectTemplate> templ = ObjectTemplate::New();
1937  templ->Set(v8_str("ProvokeOutOfMemory"),
1938             v8::FunctionTemplate::New(ProvokeOutOfMemory));
1939  LocalContext context(0, templ);
1940  v8::V8::IgnoreOutOfMemoryException();
1941  Local<Value> result = CompileRun(
1942    "var thrown = false;"
1943    "try {"
1944    "  ProvokeOutOfMemory();"
1945    "} catch (e) {"
1946    "  thrown = true;"
1947    "}");
1948  // Check for out of memory state.
1949  CHECK(result.IsEmpty());
1950  CHECK(context->HasOutOfMemoryException());
1951}
1952
1953
1954TEST(HugeConsStringOutOfMemory) {
1955  // It's not possible to read a snapshot into a heap with different dimensions.
1956  if (v8::internal::Snapshot::IsEnabled()) return;
1957  v8::HandleScope scope;
1958  LocalContext context;
1959  // Set heap limits.
1960  static const int K = 1024;
1961  v8::ResourceConstraints constraints;
1962  constraints.set_max_young_space_size(256 * K);
1963  constraints.set_max_old_space_size(2 * K * K);
1964  v8::SetResourceConstraints(&constraints);
1965
1966  // Execute a script that causes out of memory.
1967  v8::V8::IgnoreOutOfMemoryException();
1968
1969  // Build huge string. This should fail with out of memory exception.
1970  Local<Value> result = CompileRun(
1971    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1972    "for (var i = 0; i < 22; i++) { str = str + str; }");
1973
1974  // Check for out of memory state.
1975  CHECK(result.IsEmpty());
1976  CHECK(context->HasOutOfMemoryException());
1977}
1978
1979
1980THREADED_TEST(ConstructCall) {
1981  v8::HandleScope scope;
1982  LocalContext context;
1983  CompileRun(
1984    "function Foo() {"
1985    "  var result = [];"
1986    "  for (var i = 0; i < arguments.length; i++) {"
1987    "    result.push(arguments[i]);"
1988    "  }"
1989    "  return result;"
1990    "}");
1991  Local<Function> Foo =
1992      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1993
1994  v8::Handle<Value>* args0 = NULL;
1995  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1996  CHECK_EQ(0, a0->Length());
1997
1998  v8::Handle<Value> args1[] = { v8_num(1.1) };
1999  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2000  CHECK_EQ(1, a1->Length());
2001  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2002
2003  v8::Handle<Value> args2[] = { v8_num(2.2),
2004                                v8_num(3.3) };
2005  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2006  CHECK_EQ(2, a2->Length());
2007  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2008  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2009
2010  v8::Handle<Value> args3[] = { v8_num(4.4),
2011                                v8_num(5.5),
2012                                v8_num(6.6) };
2013  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2014  CHECK_EQ(3, a3->Length());
2015  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2016  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2017  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2018
2019  v8::Handle<Value> args4[] = { v8_num(7.7),
2020                                v8_num(8.8),
2021                                v8_num(9.9),
2022                                v8_num(10.11) };
2023  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2024  CHECK_EQ(4, a4->Length());
2025  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2026  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2027  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2028  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2029}
2030
2031
2032static void CheckUncle(v8::TryCatch* try_catch) {
2033  CHECK(try_catch->HasCaught());
2034  String::AsciiValue str_value(try_catch->Exception());
2035  CHECK_EQ(*str_value, "uncle?");
2036  try_catch->Reset();
2037}
2038
2039
2040THREADED_TEST(ConversionNumber) {
2041  v8::HandleScope scope;
2042  LocalContext env;
2043  // Very large number.
2044  CompileRun("var obj = Math.pow(2,32) * 1237;");
2045  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2046  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2047  CHECK_EQ(0, obj->ToInt32()->Value());
2048  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2049  // Large number.
2050  CompileRun("var obj = -1234567890123;");
2051  obj = env->Global()->Get(v8_str("obj"));
2052  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2053  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2054  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2055  // Small positive integer.
2056  CompileRun("var obj = 42;");
2057  obj = env->Global()->Get(v8_str("obj"));
2058  CHECK_EQ(42.0, obj->ToNumber()->Value());
2059  CHECK_EQ(42, obj->ToInt32()->Value());
2060  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2061  // Negative integer.
2062  CompileRun("var obj = -37;");
2063  obj = env->Global()->Get(v8_str("obj"));
2064  CHECK_EQ(-37.0, obj->ToNumber()->Value());
2065  CHECK_EQ(-37, obj->ToInt32()->Value());
2066  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2067  // Positive non-int32 integer.
2068  CompileRun("var obj = 0x81234567;");
2069  obj = env->Global()->Get(v8_str("obj"));
2070  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2071  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2072  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2073  // Fraction.
2074  CompileRun("var obj = 42.3;");
2075  obj = env->Global()->Get(v8_str("obj"));
2076  CHECK_EQ(42.3, obj->ToNumber()->Value());
2077  CHECK_EQ(42, obj->ToInt32()->Value());
2078  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2079  // Large negative fraction.
2080  CompileRun("var obj = -5726623061.75;");
2081  obj = env->Global()->Get(v8_str("obj"));
2082  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2083  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2084  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2085}
2086
2087
2088THREADED_TEST(isNumberType) {
2089  v8::HandleScope scope;
2090  LocalContext env;
2091  // Very large number.
2092  CompileRun("var obj = Math.pow(2,32) * 1237;");
2093  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2094  CHECK(!obj->IsInt32());
2095  CHECK(!obj->IsUint32());
2096  // Large negative number.
2097  CompileRun("var obj = -1234567890123;");
2098  obj = env->Global()->Get(v8_str("obj"));
2099  CHECK(!obj->IsInt32());
2100  CHECK(!obj->IsUint32());
2101  // Small positive integer.
2102  CompileRun("var obj = 42;");
2103  obj = env->Global()->Get(v8_str("obj"));
2104  CHECK(obj->IsInt32());
2105  CHECK(obj->IsUint32());
2106  // Negative integer.
2107  CompileRun("var obj = -37;");
2108  obj = env->Global()->Get(v8_str("obj"));
2109  CHECK(obj->IsInt32());
2110  CHECK(!obj->IsUint32());
2111  // Positive non-int32 integer.
2112  CompileRun("var obj = 0x81234567;");
2113  obj = env->Global()->Get(v8_str("obj"));
2114  CHECK(!obj->IsInt32());
2115  CHECK(obj->IsUint32());
2116  // Fraction.
2117  CompileRun("var obj = 42.3;");
2118  obj = env->Global()->Get(v8_str("obj"));
2119  CHECK(!obj->IsInt32());
2120  CHECK(!obj->IsUint32());
2121  // Large negative fraction.
2122  CompileRun("var obj = -5726623061.75;");
2123  obj = env->Global()->Get(v8_str("obj"));
2124  CHECK(!obj->IsInt32());
2125  CHECK(!obj->IsUint32());
2126}
2127
2128
2129THREADED_TEST(ConversionException) {
2130  v8::HandleScope scope;
2131  LocalContext env;
2132  CompileRun(
2133    "function TestClass() { };"
2134    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2135    "var obj = new TestClass();");
2136  Local<Value> obj = env->Global()->Get(v8_str("obj"));
2137
2138  v8::TryCatch try_catch;
2139
2140  Local<Value> to_string_result = obj->ToString();
2141  CHECK(to_string_result.IsEmpty());
2142  CheckUncle(&try_catch);
2143
2144  Local<Value> to_number_result = obj->ToNumber();
2145  CHECK(to_number_result.IsEmpty());
2146  CheckUncle(&try_catch);
2147
2148  Local<Value> to_integer_result = obj->ToInteger();
2149  CHECK(to_integer_result.IsEmpty());
2150  CheckUncle(&try_catch);
2151
2152  Local<Value> to_uint32_result = obj->ToUint32();
2153  CHECK(to_uint32_result.IsEmpty());
2154  CheckUncle(&try_catch);
2155
2156  Local<Value> to_int32_result = obj->ToInt32();
2157  CHECK(to_int32_result.IsEmpty());
2158  CheckUncle(&try_catch);
2159
2160  Local<Value> to_object_result = v8::Undefined()->ToObject();
2161  CHECK(to_object_result.IsEmpty());
2162  CHECK(try_catch.HasCaught());
2163  try_catch.Reset();
2164
2165  int32_t int32_value = obj->Int32Value();
2166  CHECK_EQ(0, int32_value);
2167  CheckUncle(&try_catch);
2168
2169  uint32_t uint32_value = obj->Uint32Value();
2170  CHECK_EQ(0, uint32_value);
2171  CheckUncle(&try_catch);
2172
2173  double number_value = obj->NumberValue();
2174  CHECK_NE(0, IsNaN(number_value));
2175  CheckUncle(&try_catch);
2176
2177  int64_t integer_value = obj->IntegerValue();
2178  CHECK_EQ(0.0, static_cast<double>(integer_value));
2179  CheckUncle(&try_catch);
2180}
2181
2182
2183v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2184  ApiTestFuzzer::Fuzz();
2185  return v8::ThrowException(v8_str("konto"));
2186}
2187
2188
2189v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2190  if (args.Length() < 1) return v8::Boolean::New(false);
2191  v8::HandleScope scope;
2192  v8::TryCatch try_catch;
2193  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2194  CHECK(!try_catch.HasCaught() || result.IsEmpty());
2195  return v8::Boolean::New(try_catch.HasCaught());
2196}
2197
2198
2199THREADED_TEST(APICatch) {
2200  v8::HandleScope scope;
2201  Local<ObjectTemplate> templ = ObjectTemplate::New();
2202  templ->Set(v8_str("ThrowFromC"),
2203             v8::FunctionTemplate::New(ThrowFromC));
2204  LocalContext context(0, templ);
2205  CompileRun(
2206    "var thrown = false;"
2207    "try {"
2208    "  ThrowFromC();"
2209    "} catch (e) {"
2210    "  thrown = true;"
2211    "}");
2212  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2213  CHECK(thrown->BooleanValue());
2214}
2215
2216
2217THREADED_TEST(APIThrowTryCatch) {
2218  v8::HandleScope scope;
2219  Local<ObjectTemplate> templ = ObjectTemplate::New();
2220  templ->Set(v8_str("ThrowFromC"),
2221             v8::FunctionTemplate::New(ThrowFromC));
2222  LocalContext context(0, templ);
2223  v8::TryCatch try_catch;
2224  CompileRun("ThrowFromC();");
2225  CHECK(try_catch.HasCaught());
2226}
2227
2228
2229// Test that a try-finally block doesn't shadow a try-catch block
2230// when setting up an external handler.
2231//
2232// BUG(271): Some of the exception propagation does not work on the
2233// ARM simulator because the simulator separates the C++ stack and the
2234// JS stack.  This test therefore fails on the simulator.  The test is
2235// not threaded to allow the threading tests to run on the simulator.
2236TEST(TryCatchInTryFinally) {
2237  v8::HandleScope scope;
2238  Local<ObjectTemplate> templ = ObjectTemplate::New();
2239  templ->Set(v8_str("CCatcher"),
2240             v8::FunctionTemplate::New(CCatcher));
2241  LocalContext context(0, templ);
2242  Local<Value> result = CompileRun("try {"
2243                                   "  try {"
2244                                   "    CCatcher('throw 7;');"
2245                                   "  } finally {"
2246                                   "  }"
2247                                   "} catch (e) {"
2248                                   "}");
2249  CHECK(result->IsTrue());
2250}
2251
2252
2253static void receive_message(v8::Handle<v8::Message> message,
2254                            v8::Handle<v8::Value> data) {
2255  message->Get();
2256  message_received = true;
2257}
2258
2259
2260TEST(APIThrowMessage) {
2261  message_received = false;
2262  v8::HandleScope scope;
2263  v8::V8::AddMessageListener(receive_message);
2264  Local<ObjectTemplate> templ = ObjectTemplate::New();
2265  templ->Set(v8_str("ThrowFromC"),
2266             v8::FunctionTemplate::New(ThrowFromC));
2267  LocalContext context(0, templ);
2268  CompileRun("ThrowFromC();");
2269  CHECK(message_received);
2270  v8::V8::RemoveMessageListeners(check_message);
2271}
2272
2273
2274TEST(APIThrowMessageAndVerboseTryCatch) {
2275  message_received = false;
2276  v8::HandleScope scope;
2277  v8::V8::AddMessageListener(receive_message);
2278  Local<ObjectTemplate> templ = ObjectTemplate::New();
2279  templ->Set(v8_str("ThrowFromC"),
2280             v8::FunctionTemplate::New(ThrowFromC));
2281  LocalContext context(0, templ);
2282  v8::TryCatch try_catch;
2283  try_catch.SetVerbose(true);
2284  Local<Value> result = CompileRun("ThrowFromC();");
2285  CHECK(try_catch.HasCaught());
2286  CHECK(result.IsEmpty());
2287  CHECK(message_received);
2288  v8::V8::RemoveMessageListeners(check_message);
2289}
2290
2291
2292THREADED_TEST(ExternalScriptException) {
2293  v8::HandleScope scope;
2294  Local<ObjectTemplate> templ = ObjectTemplate::New();
2295  templ->Set(v8_str("ThrowFromC"),
2296             v8::FunctionTemplate::New(ThrowFromC));
2297  LocalContext context(0, templ);
2298
2299  v8::TryCatch try_catch;
2300  Local<Script> script
2301      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2302  Local<Value> result = script->Run();
2303  CHECK(result.IsEmpty());
2304  CHECK(try_catch.HasCaught());
2305  String::AsciiValue exception_value(try_catch.Exception());
2306  CHECK_EQ("konto", *exception_value);
2307}
2308
2309
2310
2311v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2312  ApiTestFuzzer::Fuzz();
2313  CHECK_EQ(4, args.Length());
2314  int count = args[0]->Int32Value();
2315  int cInterval = args[2]->Int32Value();
2316  if (count == 0) {
2317    return v8::ThrowException(v8_str("FromC"));
2318  } else {
2319    Local<v8::Object> global = Context::GetCurrent()->Global();
2320    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2321    v8::Handle<Value> argv[] = { v8_num(count - 1),
2322                                 args[1],
2323                                 args[2],
2324                                 args[3] };
2325    if (count % cInterval == 0) {
2326      v8::TryCatch try_catch;
2327      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
2328      int expected = args[3]->Int32Value();
2329      if (try_catch.HasCaught()) {
2330        CHECK_EQ(expected, count);
2331        CHECK(result.IsEmpty());
2332        CHECK(!i::Top::has_scheduled_exception());
2333      } else {
2334        CHECK_NE(expected, count);
2335      }
2336      return result;
2337    } else {
2338      return fun.As<Function>()->Call(global, 4, argv);
2339    }
2340  }
2341}
2342
2343
2344v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2345  ApiTestFuzzer::Fuzz();
2346  CHECK_EQ(3, args.Length());
2347  bool equality = args[0]->BooleanValue();
2348  int count = args[1]->Int32Value();
2349  int expected = args[2]->Int32Value();
2350  if (equality) {
2351    CHECK_EQ(count, expected);
2352  } else {
2353    CHECK_NE(count, expected);
2354  }
2355  return v8::Undefined();
2356}
2357
2358
2359THREADED_TEST(EvalInTryFinally) {
2360  v8::HandleScope scope;
2361  LocalContext context;
2362  v8::TryCatch try_catch;
2363  CompileRun("(function() {"
2364             "  try {"
2365             "    eval('asldkf (*&^&*^');"
2366             "  } finally {"
2367             "    return;"
2368             "  }"
2369             "})()");
2370  CHECK(!try_catch.HasCaught());
2371}
2372
2373
2374// This test works by making a stack of alternating JavaScript and C
2375// activations.  These activations set up exception handlers with regular
2376// intervals, one interval for C activations and another for JavaScript
2377// activations.  When enough activations have been created an exception is
2378// thrown and we check that the right activation catches the exception and that
2379// no other activations do.  The right activation is always the topmost one with
2380// a handler, regardless of whether it is in JavaScript or C.
2381//
2382// The notation used to describe a test case looks like this:
2383//
2384//    *JS[4] *C[3] @JS[2] C[1] JS[0]
2385//
2386// Each entry is an activation, either JS or C.  The index is the count at that
2387// level.  Stars identify activations with exception handlers, the @ identifies
2388// the exception handler that should catch the exception.
2389//
2390// BUG(271): Some of the exception propagation does not work on the
2391// ARM simulator because the simulator separates the C++ stack and the
2392// JS stack.  This test therefore fails on the simulator.  The test is
2393// not threaded to allow the threading tests to run on the simulator.
2394TEST(ExceptionOrder) {
2395  v8::HandleScope scope;
2396  Local<ObjectTemplate> templ = ObjectTemplate::New();
2397  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2398  templ->Set(v8_str("CThrowCountDown"),
2399             v8::FunctionTemplate::New(CThrowCountDown));
2400  LocalContext context(0, templ);
2401  CompileRun(
2402    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2403    "  if (count == 0) throw 'FromJS';"
2404    "  if (count % jsInterval == 0) {"
2405    "    try {"
2406    "      var value = CThrowCountDown(count - 1,"
2407    "                                  jsInterval,"
2408    "                                  cInterval,"
2409    "                                  expected);"
2410    "      check(false, count, expected);"
2411    "      return value;"
2412    "    } catch (e) {"
2413    "      check(true, count, expected);"
2414    "    }"
2415    "  } else {"
2416    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2417    "  }"
2418    "}");
2419  Local<Function> fun =
2420      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2421
2422  const int argc = 4;
2423  //                             count      jsInterval cInterval  expected
2424
2425  // *JS[4] *C[3] @JS[2] C[1] JS[0]
2426  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2427  fun->Call(fun, argc, a0);
2428
2429  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2430  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2431  fun->Call(fun, argc, a1);
2432
2433  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2434  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2435  fun->Call(fun, argc, a2);
2436
2437  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2438  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2439  fun->Call(fun, argc, a3);
2440
2441  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2442  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2443  fun->Call(fun, argc, a4);
2444
2445  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2446  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2447  fun->Call(fun, argc, a5);
2448}
2449
2450
2451v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2452  ApiTestFuzzer::Fuzz();
2453  CHECK_EQ(1, args.Length());
2454  return v8::ThrowException(args[0]);
2455}
2456
2457
2458THREADED_TEST(ThrowValues) {
2459  v8::HandleScope scope;
2460  Local<ObjectTemplate> templ = ObjectTemplate::New();
2461  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2462  LocalContext context(0, templ);
2463  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2464    "function Run(obj) {"
2465    "  try {"
2466    "    Throw(obj);"
2467    "  } catch (e) {"
2468    "    return e;"
2469    "  }"
2470    "  return 'no exception';"
2471    "}"
2472    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2473  CHECK_EQ(5, result->Length());
2474  CHECK(result->Get(v8::Integer::New(0))->IsString());
2475  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2476  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2477  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2478  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2479  CHECK(result->Get(v8::Integer::New(3))->IsNull());
2480  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2481}
2482
2483
2484THREADED_TEST(CatchZero) {
2485  v8::HandleScope scope;
2486  LocalContext context;
2487  v8::TryCatch try_catch;
2488  CHECK(!try_catch.HasCaught());
2489  Script::Compile(v8_str("throw 10"))->Run();
2490  CHECK(try_catch.HasCaught());
2491  CHECK_EQ(10, try_catch.Exception()->Int32Value());
2492  try_catch.Reset();
2493  CHECK(!try_catch.HasCaught());
2494  Script::Compile(v8_str("throw 0"))->Run();
2495  CHECK(try_catch.HasCaught());
2496  CHECK_EQ(0, try_catch.Exception()->Int32Value());
2497}
2498
2499
2500THREADED_TEST(CatchExceptionFromWith) {
2501  v8::HandleScope scope;
2502  LocalContext context;
2503  v8::TryCatch try_catch;
2504  CHECK(!try_catch.HasCaught());
2505  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2506  CHECK(try_catch.HasCaught());
2507}
2508
2509
2510THREADED_TEST(Equality) {
2511  v8::HandleScope scope;
2512  LocalContext context;
2513  // Check that equality works at all before relying on CHECK_EQ
2514  CHECK(v8_str("a")->Equals(v8_str("a")));
2515  CHECK(!v8_str("a")->Equals(v8_str("b")));
2516
2517  CHECK_EQ(v8_str("a"), v8_str("a"));
2518  CHECK_NE(v8_str("a"), v8_str("b"));
2519  CHECK_EQ(v8_num(1), v8_num(1));
2520  CHECK_EQ(v8_num(1.00), v8_num(1));
2521  CHECK_NE(v8_num(1), v8_num(2));
2522
2523  // Assume String is not symbol.
2524  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2525  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2526  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2527  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2528  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2529  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2530  Local<Value> not_a_number = v8_num(i::OS::nan_value());
2531  CHECK(!not_a_number->StrictEquals(not_a_number));
2532  CHECK(v8::False()->StrictEquals(v8::False()));
2533  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2534
2535  v8::Handle<v8::Object> obj = v8::Object::New();
2536  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2537  CHECK(alias->StrictEquals(obj));
2538  alias.Dispose();
2539}
2540
2541
2542THREADED_TEST(MultiRun) {
2543  v8::HandleScope scope;
2544  LocalContext context;
2545  Local<Script> script = Script::Compile(v8_str("x"));
2546  for (int i = 0; i < 10; i++)
2547    script->Run();
2548}
2549
2550
2551static v8::Handle<Value> GetXValue(Local<String> name,
2552                                   const AccessorInfo& info) {
2553  ApiTestFuzzer::Fuzz();
2554  CHECK_EQ(info.Data(), v8_str("donut"));
2555  CHECK_EQ(name, v8_str("x"));
2556  return name;
2557}
2558
2559
2560THREADED_TEST(SimplePropertyRead) {
2561  v8::HandleScope scope;
2562  Local<ObjectTemplate> templ = ObjectTemplate::New();
2563  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2564  LocalContext context;
2565  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2566  Local<Script> script = Script::Compile(v8_str("obj.x"));
2567  for (int i = 0; i < 10; i++) {
2568    Local<Value> result = script->Run();
2569    CHECK_EQ(result, v8_str("x"));
2570  }
2571}
2572
2573THREADED_TEST(DefinePropertyOnAPIAccessor) {
2574  v8::HandleScope scope;
2575  Local<ObjectTemplate> templ = ObjectTemplate::New();
2576  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2577  LocalContext context;
2578  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2579
2580  // Uses getOwnPropertyDescriptor to check the configurable status
2581  Local<Script> script_desc
2582    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
2583                             "obj, 'x');"
2584                             "prop.configurable;"));
2585  Local<Value> result = script_desc->Run();
2586  CHECK_EQ(result->BooleanValue(), true);
2587
2588  // Redefine get - but still configurable
2589  Local<Script> script_define
2590    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2591                             "            configurable: true };"
2592                             "Object.defineProperty(obj, 'x', desc);"
2593                             "obj.x"));
2594  result = script_define->Run();
2595  CHECK_EQ(result, v8_num(42));
2596
2597  // Check that the accessor is still configurable
2598  result = script_desc->Run();
2599  CHECK_EQ(result->BooleanValue(), true);
2600
2601  // Redefine to a non-configurable
2602  script_define
2603    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2604                             "             configurable: false };"
2605                             "Object.defineProperty(obj, 'x', desc);"
2606                             "obj.x"));
2607  result = script_define->Run();
2608  CHECK_EQ(result, v8_num(43));
2609  result = script_desc->Run();
2610  CHECK_EQ(result->BooleanValue(), false);
2611
2612  // Make sure that it is not possible to redefine again
2613  v8::TryCatch try_catch;
2614  result = script_define->Run();
2615  CHECK(try_catch.HasCaught());
2616  String::AsciiValue exception_value(try_catch.Exception());
2617  CHECK_EQ(*exception_value,
2618           "TypeError: Cannot redefine property: defineProperty");
2619}
2620
2621THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2622  v8::HandleScope scope;
2623  Local<ObjectTemplate> templ = ObjectTemplate::New();
2624  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2625  LocalContext context;
2626  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2627
2628  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2629                                    "Object.getOwnPropertyDescriptor( "
2630                                    "obj, 'x');"
2631                                    "prop.configurable;"));
2632  Local<Value> result = script_desc->Run();
2633  CHECK_EQ(result->BooleanValue(), true);
2634
2635  Local<Script> script_define =
2636    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2637                           "            configurable: true };"
2638                           "Object.defineProperty(obj, 'x', desc);"
2639                           "obj.x"));
2640  result = script_define->Run();
2641  CHECK_EQ(result, v8_num(42));
2642
2643
2644  result = script_desc->Run();
2645  CHECK_EQ(result->BooleanValue(), true);
2646
2647
2648  script_define =
2649    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2650                           "            configurable: false };"
2651                           "Object.defineProperty(obj, 'x', desc);"
2652                           "obj.x"));
2653  result = script_define->Run();
2654  CHECK_EQ(result, v8_num(43));
2655  result = script_desc->Run();
2656
2657  CHECK_EQ(result->BooleanValue(), false);
2658
2659  v8::TryCatch try_catch;
2660  result = script_define->Run();
2661  CHECK(try_catch.HasCaught());
2662  String::AsciiValue exception_value(try_catch.Exception());
2663  CHECK_EQ(*exception_value,
2664           "TypeError: Cannot redefine property: defineProperty");
2665}
2666
2667
2668static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2669                                                char const* name) {
2670  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2671}
2672
2673
2674THREADED_TEST(DefineAPIAccessorOnObject) {
2675  v8::HandleScope scope;
2676  Local<ObjectTemplate> templ = ObjectTemplate::New();
2677  LocalContext context;
2678
2679  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2680  CompileRun("var obj2 = {};");
2681
2682  CHECK(CompileRun("obj1.x")->IsUndefined());
2683  CHECK(CompileRun("obj2.x")->IsUndefined());
2684
2685  CHECK(GetGlobalProperty(&context, "obj1")->
2686      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2687
2688  ExpectString("obj1.x", "x");
2689  CHECK(CompileRun("obj2.x")->IsUndefined());
2690
2691  CHECK(GetGlobalProperty(&context, "obj2")->
2692      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2693
2694  ExpectString("obj1.x", "x");
2695  ExpectString("obj2.x", "x");
2696
2697  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2698  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2699
2700  CompileRun("Object.defineProperty(obj1, 'x',"
2701             "{ get: function() { return 'y'; }, configurable: true })");
2702
2703  ExpectString("obj1.x", "y");
2704  ExpectString("obj2.x", "x");
2705
2706  CompileRun("Object.defineProperty(obj2, 'x',"
2707             "{ get: function() { return 'y'; }, configurable: true })");
2708
2709  ExpectString("obj1.x", "y");
2710  ExpectString("obj2.x", "y");
2711
2712  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2713  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2714
2715  CHECK(GetGlobalProperty(&context, "obj1")->
2716      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2717  CHECK(GetGlobalProperty(&context, "obj2")->
2718      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2719
2720  ExpectString("obj1.x", "x");
2721  ExpectString("obj2.x", "x");
2722
2723  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2724  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2725
2726  // Define getters/setters, but now make them not configurable.
2727  CompileRun("Object.defineProperty(obj1, 'x',"
2728             "{ get: function() { return 'z'; }, configurable: false })");
2729  CompileRun("Object.defineProperty(obj2, 'x',"
2730             "{ get: function() { return 'z'; }, configurable: false })");
2731
2732  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2733  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2734
2735  ExpectString("obj1.x", "z");
2736  ExpectString("obj2.x", "z");
2737
2738  CHECK(!GetGlobalProperty(&context, "obj1")->
2739      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2740  CHECK(!GetGlobalProperty(&context, "obj2")->
2741      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2742
2743  ExpectString("obj1.x", "z");
2744  ExpectString("obj2.x", "z");
2745}
2746
2747
2748THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2749  v8::HandleScope scope;
2750  Local<ObjectTemplate> templ = ObjectTemplate::New();
2751  LocalContext context;
2752
2753  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2754  CompileRun("var obj2 = {};");
2755
2756  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2757        v8_str("x"),
2758        GetXValue, NULL,
2759        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2760  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2761        v8_str("x"),
2762        GetXValue, NULL,
2763        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2764
2765  ExpectString("obj1.x", "x");
2766  ExpectString("obj2.x", "x");
2767
2768  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2769  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2770
2771  CHECK(!GetGlobalProperty(&context, "obj1")->
2772      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2773  CHECK(!GetGlobalProperty(&context, "obj2")->
2774      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2775
2776  {
2777    v8::TryCatch try_catch;
2778    CompileRun("Object.defineProperty(obj1, 'x',"
2779        "{get: function() { return 'func'; }})");
2780    CHECK(try_catch.HasCaught());
2781    String::AsciiValue exception_value(try_catch.Exception());
2782    CHECK_EQ(*exception_value,
2783            "TypeError: Cannot redefine property: defineProperty");
2784  }
2785  {
2786    v8::TryCatch try_catch;
2787    CompileRun("Object.defineProperty(obj2, 'x',"
2788        "{get: function() { return 'func'; }})");
2789    CHECK(try_catch.HasCaught());
2790    String::AsciiValue exception_value(try_catch.Exception());
2791    CHECK_EQ(*exception_value,
2792            "TypeError: Cannot redefine property: defineProperty");
2793  }
2794}
2795
2796
2797static v8::Handle<Value> Get239Value(Local<String> name,
2798                                     const AccessorInfo& info) {
2799  ApiTestFuzzer::Fuzz();
2800  CHECK_EQ(info.Data(), v8_str("donut"));
2801  CHECK_EQ(name, v8_str("239"));
2802  return name;
2803}
2804
2805
2806THREADED_TEST(ElementAPIAccessor) {
2807  v8::HandleScope scope;
2808  Local<ObjectTemplate> templ = ObjectTemplate::New();
2809  LocalContext context;
2810
2811  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2812  CompileRun("var obj2 = {};");
2813
2814  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2815        v8_str("239"),
2816        Get239Value, NULL,
2817        v8_str("donut")));
2818  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2819        v8_str("239"),
2820        Get239Value, NULL,
2821        v8_str("donut")));
2822
2823  ExpectString("obj1[239]", "239");
2824  ExpectString("obj2[239]", "239");
2825  ExpectString("obj1['239']", "239");
2826  ExpectString("obj2['239']", "239");
2827}
2828
2829
2830v8::Persistent<Value> xValue;
2831
2832
2833static void SetXValue(Local<String> name,
2834                      Local<Value> value,
2835                      const AccessorInfo& info) {
2836  CHECK_EQ(value, v8_num(4));
2837  CHECK_EQ(info.Data(), v8_str("donut"));
2838  CHECK_EQ(name, v8_str("x"));
2839  CHECK(xValue.IsEmpty());
2840  xValue = v8::Persistent<Value>::New(value);
2841}
2842
2843
2844THREADED_TEST(SimplePropertyWrite) {
2845  v8::HandleScope scope;
2846  Local<ObjectTemplate> templ = ObjectTemplate::New();
2847  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2848  LocalContext context;
2849  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2850  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2851  for (int i = 0; i < 10; i++) {
2852    CHECK(xValue.IsEmpty());
2853    script->Run();
2854    CHECK_EQ(v8_num(4), xValue);
2855    xValue.Dispose();
2856    xValue = v8::Persistent<Value>();
2857  }
2858}
2859
2860
2861static v8::Handle<Value> XPropertyGetter(Local<String> property,
2862                                         const AccessorInfo& info) {
2863  ApiTestFuzzer::Fuzz();
2864  CHECK(info.Data()->IsUndefined());
2865  return property;
2866}
2867
2868
2869THREADED_TEST(NamedInterceptorPropertyRead) {
2870  v8::HandleScope scope;
2871  Local<ObjectTemplate> templ = ObjectTemplate::New();
2872  templ->SetNamedPropertyHandler(XPropertyGetter);
2873  LocalContext context;
2874  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2875  Local<Script> script = Script::Compile(v8_str("obj.x"));
2876  for (int i = 0; i < 10; i++) {
2877    Local<Value> result = script->Run();
2878    CHECK_EQ(result, v8_str("x"));
2879  }
2880}
2881
2882
2883THREADED_TEST(NamedInterceptorDictionaryIC) {
2884  v8::HandleScope scope;
2885  Local<ObjectTemplate> templ = ObjectTemplate::New();
2886  templ->SetNamedPropertyHandler(XPropertyGetter);
2887  LocalContext context;
2888  // Create an object with a named interceptor.
2889  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2890  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2891  for (int i = 0; i < 10; i++) {
2892    Local<Value> result = script->Run();
2893    CHECK_EQ(result, v8_str("x"));
2894  }
2895  // Create a slow case object and a function accessing a property in
2896  // that slow case object (with dictionary probing in generated
2897  // code). Then force object with a named interceptor into slow-case,
2898  // pass it to the function, and check that the interceptor is called
2899  // instead of accessing the local property.
2900  Local<Value> result =
2901      CompileRun("function get_x(o) { return o.x; };"
2902                 "var obj = { x : 42, y : 0 };"
2903                 "delete obj.y;"
2904                 "for (var i = 0; i < 10; i++) get_x(obj);"
2905                 "interceptor_obj.x = 42;"
2906                 "interceptor_obj.y = 10;"
2907                 "delete interceptor_obj.y;"
2908                 "get_x(interceptor_obj)");
2909  CHECK_EQ(result, v8_str("x"));
2910}
2911
2912
2913static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2914                                               const AccessorInfo& info) {
2915  // Set x on the prototype object and do not handle the get request.
2916  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2917  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
2918  return v8::Handle<Value>();
2919}
2920
2921
2922// This is a regression test for http://crbug.com/20104. Map
2923// transitions should not interfere with post interceptor lookup.
2924THREADED_TEST(NamedInterceptorMapTransitionRead) {
2925  v8::HandleScope scope;
2926  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2927  Local<v8::ObjectTemplate> instance_template
2928      = function_template->InstanceTemplate();
2929  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2930  LocalContext context;
2931  context->Global()->Set(v8_str("F"), function_template->GetFunction());
2932  // Create an instance of F and introduce a map transition for x.
2933  CompileRun("var o = new F(); o.x = 23;");
2934  // Create an instance of F and invoke the getter. The result should be 23.
2935  Local<Value> result = CompileRun("o = new F(); o.x");
2936  CHECK_EQ(result->Int32Value(), 23);
2937}
2938
2939
2940static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2941                                               const AccessorInfo& info) {
2942  ApiTestFuzzer::Fuzz();
2943  if (index == 37) {
2944    return v8::Handle<Value>(v8_num(625));
2945  }
2946  return v8::Handle<Value>();
2947}
2948
2949
2950static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2951                                               Local<Value> value,
2952                                               const AccessorInfo& info) {
2953  ApiTestFuzzer::Fuzz();
2954  if (index == 39) {
2955    return value;
2956  }
2957  return v8::Handle<Value>();
2958}
2959
2960
2961THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2962  v8::HandleScope scope;
2963  Local<ObjectTemplate> templ = ObjectTemplate::New();
2964  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2965                                   IndexedPropertySetter);
2966  LocalContext context;
2967  context->Global()->Set(v8_str("obj"), templ->NewInstance());
2968  Local<Script> getter_script = Script::Compile(v8_str(
2969      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2970  Local<Script> setter_script = Script::Compile(v8_str(
2971      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2972      "obj[17] = 23;"
2973      "obj.foo;"));
2974  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2975      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2976      "obj[39] = 47;"
2977      "obj.foo;"));  // This setter should not run, due to the interceptor.
2978  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2979      "obj[37];"));
2980  Local<Value> result = getter_script->Run();
2981  CHECK_EQ(v8_num(5), result);
2982  result = setter_script->Run();
2983  CHECK_EQ(v8_num(23), result);
2984  result = interceptor_setter_script->Run();
2985  CHECK_EQ(v8_num(23), result);
2986  result = interceptor_getter_script->Run();
2987  CHECK_EQ(v8_num(625), result);
2988}
2989
2990
2991static v8::Handle<Value> IdentityIndexedPropertyGetter(
2992    uint32_t index,
2993    const AccessorInfo& info) {
2994  return v8::Integer::New(index);
2995}
2996
2997
2998THREADED_TEST(IndexedInterceptorWithNoSetter) {
2999  v8::HandleScope scope;
3000  Local<ObjectTemplate> templ = ObjectTemplate::New();
3001  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3002
3003  LocalContext context;
3004  context->Global()->Set(v8_str("obj"), templ->NewInstance());
3005
3006  const char* code =
3007      "try {"
3008      "  obj[0] = 239;"
3009      "  for (var i = 0; i < 100; i++) {"
3010      "    var v = obj[0];"
3011      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3012      "  }"
3013      "  'PASSED'"
3014      "} catch(e) {"
3015      "  e"
3016      "}";
3017  ExpectString(code, "PASSED");
3018}
3019
3020
3021THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3022  v8::HandleScope scope;
3023  Local<ObjectTemplate> templ = ObjectTemplate::New();
3024  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3025
3026  LocalContext context;
3027  Local<v8::Object> obj = templ->NewInstance();
3028  obj->TurnOnAccessCheck();
3029  context->Global()->Set(v8_str("obj"), obj);
3030
3031  const char* code =
3032      "try {"
3033      "  for (var i = 0; i < 100; i++) {"
3034      "    var v = obj[0];"
3035      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3036      "  }"
3037      "  'PASSED'"
3038      "} catch(e) {"
3039      "  e"
3040      "}";
3041  ExpectString(code, "PASSED");
3042}
3043
3044
3045THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3046  i::FLAG_allow_natives_syntax = true;
3047  v8::HandleScope scope;
3048  Local<ObjectTemplate> templ = ObjectTemplate::New();
3049  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3050
3051  LocalContext context;
3052  Local<v8::Object> obj = templ->NewInstance();
3053  context->Global()->Set(v8_str("obj"), obj);
3054
3055  const char* code =
3056      "try {"
3057      "  for (var i = 0; i < 100; i++) {"
3058      "    var expected = i;"
3059      "    if (i == 5) {"
3060      "      %EnableAccessChecks(obj);"
3061      "      expected = undefined;"
3062      "    }"
3063      "    var v = obj[i];"
3064      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3065      "    if (i == 5) %DisableAccessChecks(obj);"
3066      "  }"
3067      "  'PASSED'"
3068      "} catch(e) {"
3069      "  e"
3070      "}";
3071  ExpectString(code, "PASSED");
3072}
3073
3074
3075THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3076  v8::HandleScope scope;
3077  Local<ObjectTemplate> templ = ObjectTemplate::New();
3078  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3079
3080  LocalContext context;
3081  Local<v8::Object> obj = templ->NewInstance();
3082  context->Global()->Set(v8_str("obj"), obj);
3083
3084  const char* code =
3085      "try {"
3086      "  for (var i = 0; i < 100; i++) {"
3087      "    var v = obj[i];"
3088      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3089      "  }"
3090      "  'PASSED'"
3091      "} catch(e) {"
3092      "  e"
3093      "}";
3094  ExpectString(code, "PASSED");
3095}
3096
3097
3098THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3099  v8::HandleScope scope;
3100  Local<ObjectTemplate> templ = ObjectTemplate::New();
3101  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3102
3103  LocalContext context;
3104  Local<v8::Object> obj = templ->NewInstance();
3105  context->Global()->Set(v8_str("obj"), obj);
3106
3107  const char* code =
3108      "try {"
3109      "  for (var i = 0; i < 100; i++) {"
3110      "    var expected = i;"
3111      "    if (i == 50) {"
3112      "       i = 'foobar';"
3113      "       expected = undefined;"
3114      "    }"
3115      "    var v = obj[i];"
3116      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3117      "  }"
3118      "  'PASSED'"
3119      "} catch(e) {"
3120      "  e"
3121      "}";
3122  ExpectString(code, "PASSED");
3123}
3124
3125
3126THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3127  v8::HandleScope scope;
3128  Local<ObjectTemplate> templ = ObjectTemplate::New();
3129  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3130
3131  LocalContext context;
3132  Local<v8::Object> obj = templ->NewInstance();
3133  context->Global()->Set(v8_str("obj"), obj);
3134
3135  const char* code =
3136      "var original = obj;"
3137      "try {"
3138      "  for (var i = 0; i < 100; i++) {"
3139      "    var expected = i;"
3140      "    if (i == 50) {"
3141      "       obj = {50: 'foobar'};"
3142      "       expected = 'foobar';"
3143      "    }"
3144      "    var v = obj[i];"
3145      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3146      "    if (i == 50) obj = original;"
3147      "  }"
3148      "  'PASSED'"
3149      "} catch(e) {"
3150      "  e"
3151      "}";
3152  ExpectString(code, "PASSED");
3153}
3154
3155
3156THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3157  v8::HandleScope scope;
3158  Local<ObjectTemplate> templ = ObjectTemplate::New();
3159  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3160
3161  LocalContext context;
3162  Local<v8::Object> obj = templ->NewInstance();
3163  context->Global()->Set(v8_str("obj"), obj);
3164
3165  const char* code =
3166      "var original = obj;"
3167      "try {"
3168      "  for (var i = 0; i < 100; i++) {"
3169      "    var expected = i;"
3170      "    if (i == 5) {"
3171      "       obj = 239;"
3172      "       expected = undefined;"
3173      "    }"
3174      "    var v = obj[i];"
3175      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3176      "    if (i == 5) obj = original;"
3177      "  }"
3178      "  'PASSED'"
3179      "} catch(e) {"
3180      "  e"
3181      "}";
3182  ExpectString(code, "PASSED");
3183}
3184
3185
3186THREADED_TEST(IndexedInterceptorOnProto) {
3187  v8::HandleScope scope;
3188  Local<ObjectTemplate> templ = ObjectTemplate::New();
3189  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3190
3191  LocalContext context;
3192  Local<v8::Object> obj = templ->NewInstance();
3193  context->Global()->Set(v8_str("obj"), obj);
3194
3195  const char* code =
3196      "var o = {__proto__: obj};"
3197      "try {"
3198      "  for (var i = 0; i < 100; i++) {"
3199      "    var v = o[i];"
3200      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3201      "  }"
3202      "  'PASSED'"
3203      "} catch(e) {"
3204      "  e"
3205      "}";
3206  ExpectString(code, "PASSED");
3207}
3208
3209
3210THREADED_TEST(MultiContexts) {
3211  v8::HandleScope scope;
3212  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3213  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3214
3215  Local<String> password = v8_str("Password");
3216
3217  // Create an environment
3218  LocalContext context0(0, templ);
3219  context0->SetSecurityToken(password);
3220  v8::Handle<v8::Object> global0 = context0->Global();
3221  global0->Set(v8_str("custom"), v8_num(1234));
3222  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3223
3224  // Create an independent environment
3225  LocalContext context1(0, templ);
3226  context1->SetSecurityToken(password);
3227  v8::Handle<v8::Object> global1 = context1->Global();
3228  global1->Set(v8_str("custom"), v8_num(1234));
3229  CHECK_NE(global0, global1);
3230  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3231  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3232
3233  // Now create a new context with the old global
3234  LocalContext context2(0, templ, global1);
3235  context2->SetSecurityToken(password);
3236  v8::Handle<v8::Object> global2 = context2->Global();
3237  CHECK_EQ(global1, global2);
3238  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3239  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3240}
3241
3242
3243THREADED_TEST(FunctionPrototypeAcrossContexts) {
3244  // Make sure that functions created by cloning boilerplates cannot
3245  // communicate through their __proto__ field.
3246
3247  v8::HandleScope scope;
3248
3249  LocalContext env0;
3250  v8::Handle<v8::Object> global0 =
3251      env0->Global();
3252  v8::Handle<v8::Object> object0 =
3253      global0->Get(v8_str("Object")).As<v8::Object>();
3254  v8::Handle<v8::Object> tostring0 =
3255      object0->Get(v8_str("toString")).As<v8::Object>();
3256  v8::Handle<v8::Object> proto0 =
3257      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
3258  proto0->Set(v8_str("custom"), v8_num(1234));
3259
3260  LocalContext env1;
3261  v8::Handle<v8::Object> global1 =
3262      env1->Global();
3263  v8::Handle<v8::Object> object1 =
3264      global1->Get(v8_str("Object")).As<v8::Object>();
3265  v8::Handle<v8::Object> tostring1 =
3266      object1->Get(v8_str("toString")).As<v8::Object>();
3267  v8::Handle<v8::Object> proto1 =
3268      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
3269  CHECK(!proto1->Has(v8_str("custom")));
3270}
3271
3272
3273THREADED_TEST(Regress892105) {
3274  // Make sure that object and array literals created by cloning
3275  // boilerplates cannot communicate through their __proto__
3276  // field. This is rather difficult to check, but we try to add stuff
3277  // to Object.prototype and Array.prototype and create a new
3278  // environment. This should succeed.
3279
3280  v8::HandleScope scope;
3281
3282  Local<String> source = v8_str("Object.prototype.obj = 1234;"
3283                                "Array.prototype.arr = 4567;"
3284                                "8901");
3285
3286  LocalContext env0;
3287  Local<Script> script0 = Script::Compile(source);
3288  CHECK_EQ(8901.0, script0->Run()->NumberValue());
3289
3290  LocalContext env1;
3291  Local<Script> script1 = Script::Compile(source);
3292  CHECK_EQ(8901.0, script1->Run()->NumberValue());
3293}
3294
3295
3296THREADED_TEST(UndetectableObject) {
3297  v8::HandleScope scope;
3298  LocalContext env;
3299
3300  Local<v8::FunctionTemplate> desc =
3301      v8::FunctionTemplate::New(0, v8::Handle<Value>());
3302  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
3303
3304  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3305  env->Global()->Set(v8_str("undetectable"), obj);
3306
3307  ExpectString("undetectable.toString()", "[object Object]");
3308  ExpectString("typeof undetectable", "undefined");
3309  ExpectString("typeof(undetectable)", "undefined");
3310  ExpectBoolean("typeof undetectable == 'undefined'", true);
3311  ExpectBoolean("typeof undetectable == 'object'", false);
3312  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3313  ExpectBoolean("!undetectable", true);
3314
3315  ExpectObject("true&&undetectable", obj);
3316  ExpectBoolean("false&&undetectable", false);
3317  ExpectBoolean("true||undetectable", true);
3318  ExpectObject("false||undetectable", obj);
3319
3320  ExpectObject("undetectable&&true", obj);
3321  ExpectObject("undetectable&&false", obj);
3322  ExpectBoolean("undetectable||true", true);
3323  ExpectBoolean("undetectable||false", false);
3324
3325  ExpectBoolean("undetectable==null", true);
3326  ExpectBoolean("null==undetectable", true);
3327  ExpectBoolean("undetectable==undefined", true);
3328  ExpectBoolean("undefined==undetectable", true);
3329  ExpectBoolean("undetectable==undetectable", true);
3330
3331
3332  ExpectBoolean("undetectable===null", false);
3333  ExpectBoolean("null===undetectable", false);
3334  ExpectBoolean("undetectable===undefined", false);
3335  ExpectBoolean("undefined===undetectable", false);
3336  ExpectBoolean("undetectable===undetectable", true);
3337}
3338
3339
3340THREADED_TEST(UndetectableString) {
3341  v8::HandleScope scope;
3342  LocalContext env;
3343
3344  Local<String> obj = String::NewUndetectable("foo");
3345  env->Global()->Set(v8_str("undetectable"), obj);
3346
3347  ExpectString("undetectable", "foo");
3348  ExpectString("typeof undetectable", "undefined");
3349  ExpectString("typeof(undetectable)", "undefined");
3350  ExpectBoolean("typeof undetectable == 'undefined'", true);
3351  ExpectBoolean("typeof undetectable == 'string'", false);
3352  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3353  ExpectBoolean("!undetectable", true);
3354
3355  ExpectObject("true&&undetectable", obj);
3356  ExpectBoolean("false&&undetectable", false);
3357  ExpectBoolean("true||undetectable", true);
3358  ExpectObject("false||undetectable", obj);
3359
3360  ExpectObject("undetectable&&true", obj);
3361  ExpectObject("undetectable&&false", obj);
3362  ExpectBoolean("undetectable||true", true);
3363  ExpectBoolean("undetectable||false", false);
3364
3365  ExpectBoolean("undetectable==null", true);
3366  ExpectBoolean("null==undetectable", true);
3367  ExpectBoolean("undetectable==undefined", true);
3368  ExpectBoolean("undefined==undetectable", true);
3369  ExpectBoolean("undetectable==undetectable", true);
3370
3371
3372  ExpectBoolean("undetectable===null", false);
3373  ExpectBoolean("null===undetectable", false);
3374  ExpectBoolean("undetectable===undefined", false);
3375  ExpectBoolean("undefined===undetectable", false);
3376  ExpectBoolean("undetectable===undetectable", true);
3377}
3378
3379
3380template <typename T> static void USE(T) { }
3381
3382
3383// This test is not intended to be run, just type checked.
3384static void PersistentHandles() {
3385  USE(PersistentHandles);
3386  Local<String> str = v8_str("foo");
3387  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3388  USE(p_str);
3389  Local<Script> scr = Script::Compile(v8_str(""));
3390  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3391  USE(p_scr);
3392  Local<ObjectTemplate> templ = ObjectTemplate::New();
3393  v8::Persistent<ObjectTemplate> p_templ =
3394    v8::Persistent<ObjectTemplate>::New(templ);
3395  USE(p_templ);
3396}
3397
3398
3399static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3400  ApiTestFuzzer::Fuzz();
3401  return v8::Undefined();
3402}
3403
3404
3405THREADED_TEST(GlobalObjectTemplate) {
3406  v8::HandleScope handle_scope;
3407  Local<ObjectTemplate> global_template = ObjectTemplate::New();
3408  global_template->Set(v8_str("JSNI_Log"),
3409                       v8::FunctionTemplate::New(HandleLogDelegator));
3410  v8::Persistent<Context> context = Context::New(0, global_template);
3411  Context::Scope context_scope(context);
3412  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3413  context.Dispose();
3414}
3415
3416
3417static const char* kSimpleExtensionSource =
3418  "function Foo() {"
3419  "  return 4;"
3420  "}";
3421
3422
3423THREADED_TEST(SimpleExtensions) {
3424  v8::HandleScope handle_scope;
3425  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3426  const char* extension_names[] = { "simpletest" };
3427  v8::ExtensionConfiguration extensions(1, extension_names);
3428  v8::Handle<Context> context = Context::New(&extensions);
3429  Context::Scope lock(context);
3430  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3431  CHECK_EQ(result, v8::Integer::New(4));
3432}
3433
3434
3435static const char* kEvalExtensionSource1 =
3436  "function UseEval1() {"
3437  "  var x = 42;"
3438  "  return eval('x');"
3439  "}";
3440
3441
3442static const char* kEvalExtensionSource2 =
3443  "(function() {"
3444  "  var x = 42;"
3445  "  function e() {"
3446  "    return eval('x');"
3447  "  }"
3448  "  this.UseEval2 = e;"
3449  "})()";
3450
3451
3452THREADED_TEST(UseEvalFromExtension) {
3453  v8::HandleScope handle_scope;
3454  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3455  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3456  const char* extension_names[] = { "evaltest1", "evaltest2" };
3457  v8::ExtensionConfiguration extensions(2, extension_names);
3458  v8::Handle<Context> context = Context::New(&extensions);
3459  Context::Scope lock(context);
3460  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3461  CHECK_EQ(result, v8::Integer::New(42));
3462  result = Script::Compile(v8_str("UseEval2()"))->Run();
3463  CHECK_EQ(result, v8::Integer::New(42));
3464}
3465
3466
3467static const char* kWithExtensionSource1 =
3468  "function UseWith1() {"
3469  "  var x = 42;"
3470  "  with({x:87}) { return x; }"
3471  "}";
3472
3473
3474
3475static const char* kWithExtensionSource2 =
3476  "(function() {"
3477  "  var x = 42;"
3478  "  function e() {"
3479  "    with ({x:87}) { return x; }"
3480  "  }"
3481  "  this.UseWith2 = e;"
3482  "})()";
3483
3484
3485THREADED_TEST(UseWithFromExtension) {
3486  v8::HandleScope handle_scope;
3487  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3488  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3489  const char* extension_names[] = { "withtest1", "withtest2" };
3490  v8::ExtensionConfiguration extensions(2, extension_names);
3491  v8::Handle<Context> context = Context::New(&extensions);
3492  Context::Scope lock(context);
3493  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3494  CHECK_EQ(result, v8::Integer::New(87));
3495  result = Script::Compile(v8_str("UseWith2()"))->Run();
3496  CHECK_EQ(result, v8::Integer::New(87));
3497}
3498
3499
3500THREADED_TEST(AutoExtensions) {
3501  v8::HandleScope handle_scope;
3502  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3503  extension->set_auto_enable(true);
3504  v8::RegisterExtension(extension);
3505  v8::Handle<Context> context = Context::New();
3506  Context::Scope lock(context);
3507  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3508  CHECK_EQ(result, v8::Integer::New(4));
3509}
3510
3511
3512static const char* kSyntaxErrorInExtensionSource =
3513    "[";
3514
3515
3516// Test that a syntax error in an extension does not cause a fatal
3517// error but results in an empty context.
3518THREADED_TEST(SyntaxErrorExtensions) {
3519  v8::HandleScope handle_scope;
3520  v8::RegisterExtension(new Extension("syntaxerror",
3521                                      kSyntaxErrorInExtensionSource));
3522  const char* extension_names[] = { "syntaxerror" };
3523  v8::ExtensionConfiguration extensions(1, extension_names);
3524  v8::Handle<Context> context = Context::New(&extensions);
3525  CHECK(context.IsEmpty());
3526}
3527
3528
3529static const char* kExceptionInExtensionSource =
3530    "throw 42";
3531
3532
3533// Test that an exception when installing an extension does not cause
3534// a fatal error but results in an empty context.
3535THREADED_TEST(ExceptionExtensions) {
3536  v8::HandleScope handle_scope;
3537  v8::RegisterExtension(new Extension("exception",
3538                                      kExceptionInExtensionSource));
3539  const char* extension_names[] = { "exception" };
3540  v8::ExtensionConfiguration extensions(1, extension_names);
3541  v8::Handle<Context> context = Context::New(&extensions);
3542  CHECK(context.IsEmpty());
3543}
3544
3545
3546static void CheckDependencies(const char* name, const char* expected) {
3547  v8::HandleScope handle_scope;
3548  v8::ExtensionConfiguration config(1, &name);
3549  LocalContext context(&config);
3550  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3551}
3552
3553
3554/*
3555 * Configuration:
3556 *
3557 *     /-- B <--\
3558 * A <-          -- D <-- E
3559 *     \-- C <--/
3560 */
3561THREADED_TEST(ExtensionDependency) {
3562  static const char* kEDeps[] = { "D" };
3563  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3564  static const char* kDDeps[] = { "B", "C" };
3565  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3566  static const char* kBCDeps[] = { "A" };
3567  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3568  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3569  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3570  CheckDependencies("A", "undefinedA");
3571  CheckDependencies("B", "undefinedAB");
3572  CheckDependencies("C", "undefinedAC");
3573  CheckDependencies("D", "undefinedABCD");
3574  CheckDependencies("E", "undefinedABCDE");
3575  v8::HandleScope handle_scope;
3576  static const char* exts[2] = { "C", "E" };
3577  v8::ExtensionConfiguration config(2, exts);
3578  LocalContext context(&config);
3579  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3580}
3581
3582
3583static const char* kExtensionTestScript =
3584  "native function A();"
3585  "native function B();"
3586  "native function C();"
3587  "function Foo(i) {"
3588  "  if (i == 0) return A();"
3589  "  if (i == 1) return B();"
3590  "  if (i == 2) return C();"
3591  "}";
3592
3593
3594static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3595  ApiTestFuzzer::Fuzz();
3596  if (args.IsConstructCall()) {
3597    args.This()->Set(v8_str("data"), args.Data());
3598    return v8::Null();
3599  }
3600  return args.Data();
3601}
3602
3603
3604class FunctionExtension : public Extension {
3605 public:
3606  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3607  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3608      v8::Handle<String> name);
3609};
3610
3611
3612static int lookup_count = 0;
3613v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3614      v8::Handle<String> name) {
3615  lookup_count++;
3616  if (name->Equals(v8_str("A"))) {
3617    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3618  } else if (name->Equals(v8_str("B"))) {
3619    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3620  } else if (name->Equals(v8_str("C"))) {
3621    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3622  } else {
3623    return v8::Handle<v8::FunctionTemplate>();
3624  }
3625}
3626
3627
3628THREADED_TEST(FunctionLookup) {
3629  v8::RegisterExtension(new FunctionExtension());
3630  v8::HandleScope handle_scope;
3631  static const char* exts[1] = { "functiontest" };
3632  v8::ExtensionConfiguration config(1, exts);
3633  LocalContext context(&config);
3634  CHECK_EQ(3, lookup_count);
3635  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3636  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3637  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3638}
3639
3640
3641THREADED_TEST(NativeFunctionConstructCall) {
3642  v8::RegisterExtension(new FunctionExtension());
3643  v8::HandleScope handle_scope;
3644  static const char* exts[1] = { "functiontest" };
3645  v8::ExtensionConfiguration config(1, exts);
3646  LocalContext context(&config);
3647  for (int i = 0; i < 10; i++) {
3648    // Run a few times to ensure that allocation of objects doesn't
3649    // change behavior of a constructor function.
3650    CHECK_EQ(v8::Integer::New(8),
3651             Script::Compile(v8_str("(new A()).data"))->Run());
3652    CHECK_EQ(v8::Integer::New(7),
3653             Script::Compile(v8_str("(new B()).data"))->Run());
3654    CHECK_EQ(v8::Integer::New(6),
3655             Script::Compile(v8_str("(new C()).data"))->Run());
3656  }
3657}
3658
3659
3660static const char* last_location;
3661static const char* last_message;
3662void StoringErrorCallback(const char* location, const char* message) {
3663  if (last_location == NULL) {
3664    last_location = location;
3665    last_message = message;
3666  }
3667}
3668
3669
3670// ErrorReporting creates a circular extensions configuration and
3671// tests that the fatal error handler gets called.  This renders V8
3672// unusable and therefore this test cannot be run in parallel.
3673TEST(ErrorReporting) {
3674  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3675  static const char* aDeps[] = { "B" };
3676  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3677  static const char* bDeps[] = { "A" };
3678  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3679  last_location = NULL;
3680  v8::ExtensionConfiguration config(1, bDeps);
3681  v8::Handle<Context> context = Context::New(&config);
3682  CHECK(context.IsEmpty());
3683  CHECK_NE(last_location, NULL);
3684}
3685
3686
3687static const char* js_code_causing_huge_string_flattening =
3688    "var str = 'X';"
3689    "for (var i = 0; i < 30; i++) {"
3690    "  str = str + str;"
3691    "}"
3692    "str.match(/X/);";
3693
3694
3695void OOMCallback(const char* location, const char* message) {
3696  exit(0);
3697}
3698
3699
3700TEST(RegexpOutOfMemory) {
3701  // Execute a script that causes out of memory when flattening a string.
3702  v8::HandleScope scope;
3703  v8::V8::SetFatalErrorHandler(OOMCallback);
3704  LocalContext context;
3705  Local<Script> script =
3706      Script::Compile(String::New(js_code_causing_huge_string_flattening));
3707  last_location = NULL;
3708  Local<Value> result = script->Run();
3709
3710  CHECK(false);  // Should not return.
3711}
3712
3713
3714static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3715                                             v8::Handle<Value> data) {
3716  CHECK_EQ(v8::Undefined(), data);
3717  CHECK(message->GetScriptResourceName()->IsUndefined());
3718  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3719  message->GetLineNumber();
3720  message->GetSourceLine();
3721}
3722
3723
3724THREADED_TEST(ErrorWithMissingScriptInfo) {
3725  v8::HandleScope scope;
3726  LocalContext context;
3727  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3728  Script::Compile(v8_str("throw Error()"))->Run();
3729  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3730}
3731
3732
3733int global_index = 0;
3734
3735class Snorkel {
3736 public:
3737  Snorkel() { index_ = global_index++; }
3738  int index_;
3739};
3740
3741class Whammy {
3742 public:
3743  Whammy() {
3744    cursor_ = 0;
3745  }
3746  ~Whammy() {
3747    script_.Dispose();
3748  }
3749  v8::Handle<Script> getScript() {
3750    if (script_.IsEmpty())
3751      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3752    return Local<Script>(*script_);
3753  }
3754
3755 public:
3756  static const int kObjectCount = 256;
3757  int cursor_;
3758  v8::Persistent<v8::Object> objects_[kObjectCount];
3759  v8::Persistent<Script> script_;
3760};
3761
3762static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3763  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3764  delete snorkel;
3765  obj.ClearWeak();
3766}
3767
3768v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3769                                       const AccessorInfo& info) {
3770  Whammy* whammy =
3771    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3772
3773  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3774
3775  v8::Handle<v8::Object> obj = v8::Object::New();
3776  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3777  if (!prev.IsEmpty()) {
3778    prev->Set(v8_str("next"), obj);
3779    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3780    whammy->objects_[whammy->cursor_].Clear();
3781  }
3782  whammy->objects_[whammy->cursor_] = global;
3783  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3784  return whammy->getScript()->Run();
3785}
3786
3787THREADED_TEST(WeakReference) {
3788  v8::HandleScope handle_scope;
3789  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3790  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3791                                 0, 0, 0, 0,
3792                                 v8::External::New(new Whammy()));
3793  const char* extension_list[] = { "v8/gc" };
3794  v8::ExtensionConfiguration extensions(1, extension_list);
3795  v8::Persistent<Context> context = Context::New(&extensions);
3796  Context::Scope context_scope(context);
3797
3798  v8::Handle<v8::Object> interceptor = templ->NewInstance();
3799  context->Global()->Set(v8_str("whammy"), interceptor);
3800  const char* code =
3801      "var last;"
3802      "for (var i = 0; i < 10000; i++) {"
3803      "  var obj = whammy.length;"
3804      "  if (last) last.next = obj;"
3805      "  last = obj;"
3806      "}"
3807      "gc();"
3808      "4";
3809  v8::Handle<Value> result = CompileRun(code);
3810  CHECK_EQ(4.0, result->NumberValue());
3811
3812  context.Dispose();
3813}
3814
3815
3816static bool in_scavenge = false;
3817static int last = -1;
3818
3819static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3820  CHECK_EQ(-1, last);
3821  last = 0;
3822  obj.Dispose();
3823  obj.Clear();
3824  in_scavenge = true;
3825  i::Heap::PerformScavenge();
3826  in_scavenge = false;
3827  *(reinterpret_cast<bool*>(data)) = true;
3828}
3829
3830static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3831                                        void* data) {
3832  CHECK_EQ(0, last);
3833  last = 1;
3834  *(reinterpret_cast<bool*>(data)) = in_scavenge;
3835  obj.Dispose();
3836  obj.Clear();
3837}
3838
3839THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3840  // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3841  // Calling callbacks from scavenges is unsafe as objects held by those
3842  // handlers might have become strongly reachable, but scavenge doesn't
3843  // check that.
3844  v8::Persistent<Context> context = Context::New();
3845  Context::Scope context_scope(context);
3846
3847  v8::Persistent<v8::Object> object_a;
3848  v8::Persistent<v8::Object> object_b;
3849
3850  {
3851    v8::HandleScope handle_scope;
3852    object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3853    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3854  }
3855
3856  bool object_a_disposed = false;
3857  object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3858  bool released_in_scavenge = false;
3859  object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3860
3861  while (!object_a_disposed) {
3862    i::Heap::CollectAllGarbage(false);
3863  }
3864  CHECK(!released_in_scavenge);
3865}
3866
3867
3868v8::Handle<Function> args_fun;
3869
3870
3871static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3872  ApiTestFuzzer::Fuzz();
3873  CHECK_EQ(args_fun, args.Callee());
3874  CHECK_EQ(3, args.Length());
3875  CHECK_EQ(v8::Integer::New(1), args[0]);
3876  CHECK_EQ(v8::Integer::New(2), args[1]);
3877  CHECK_EQ(v8::Integer::New(3), args[2]);
3878  CHECK_EQ(v8::Undefined(), args[3]);
3879  v8::HandleScope scope;
3880  i::Heap::CollectAllGarbage(false);
3881  return v8::Undefined();
3882}
3883
3884
3885THREADED_TEST(Arguments) {
3886  v8::HandleScope scope;
3887  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3888  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3889  LocalContext context(NULL, global);
3890  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
3891  v8_compile("f(1, 2, 3)")->Run();
3892}
3893
3894
3895static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3896                                        const AccessorInfo&) {
3897  return v8::Handle<Value>();
3898}
3899
3900
3901static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3902                                        const AccessorInfo&) {
3903  return v8::Handle<Value>();
3904}
3905
3906
3907static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3908                                        const AccessorInfo&) {
3909  if (!name->Equals(v8_str("foo"))) {
3910    return v8::Handle<v8::Boolean>();  // not intercepted
3911  }
3912
3913  return v8::False();  // intercepted, and don't delete the property
3914}
3915
3916
3917static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3918  if (index != 2) {
3919    return v8::Handle<v8::Boolean>();  // not intercepted
3920  }
3921
3922  return v8::False();  // intercepted, and don't delete the property
3923}
3924
3925
3926THREADED_TEST(Deleter) {
3927  v8::HandleScope scope;
3928  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3929  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3930  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3931  LocalContext context;
3932  context->Global()->Set(v8_str("k"), obj->NewInstance());
3933  CompileRun(
3934    "k.foo = 'foo';"
3935    "k.bar = 'bar';"
3936    "k[2] = 2;"
3937    "k[4] = 4;");
3938  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3939  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3940
3941  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3942  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3943
3944  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3945  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3946
3947  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3948  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3949}
3950
3951
3952static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3953  ApiTestFuzzer::Fuzz();
3954  if (name->Equals(v8_str("foo")) ||
3955      name->Equals(v8_str("bar")) ||
3956      name->Equals(v8_str("baz"))) {
3957    return v8::Undefined();
3958  }
3959  return v8::Handle<Value>();
3960}
3961
3962
3963static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3964  ApiTestFuzzer::Fuzz();
3965  if (index == 0 || index == 1) return v8::Undefined();
3966  return v8::Handle<Value>();
3967}
3968
3969
3970static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3971  ApiTestFuzzer::Fuzz();
3972  v8::Handle<v8::Array> result = v8::Array::New(3);
3973  result->Set(v8::Integer::New(0), v8_str("foo"));
3974  result->Set(v8::Integer::New(1), v8_str("bar"));
3975  result->Set(v8::Integer::New(2), v8_str("baz"));
3976  return result;
3977}
3978
3979
3980static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3981  ApiTestFuzzer::Fuzz();
3982  v8::Handle<v8::Array> result = v8::Array::New(2);
3983  result->Set(v8::Integer::New(0), v8_str("0"));
3984  result->Set(v8::Integer::New(1), v8_str("1"));
3985  return result;
3986}
3987
3988
3989THREADED_TEST(Enumerators) {
3990  v8::HandleScope scope;
3991  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3992  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3993  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3994  LocalContext context;
3995  context->Global()->Set(v8_str("k"), obj->NewInstance());
3996  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3997    "k[10] = 0;"
3998    "k.a = 0;"
3999    "k[5] = 0;"
4000    "k.b = 0;"
4001    "k[4294967295] = 0;"
4002    "k.c = 0;"
4003    "k[4294967296] = 0;"
4004    "k.d = 0;"
4005    "k[140000] = 0;"
4006    "k.e = 0;"
4007    "k[30000000000] = 0;"
4008    "k.f = 0;"
4009    "var result = [];"
4010    "for (var prop in k) {"
4011    "  result.push(prop);"
4012    "}"
4013    "result"));
4014  // Check that we get all the property names returned including the
4015  // ones from the enumerators in the right order: indexed properties
4016  // in numerical order, indexed interceptor properties, named
4017  // properties in insertion order, named interceptor properties.
4018  // This order is not mandated by the spec, so this test is just
4019  // documenting our behavior.
4020  CHECK_EQ(17, result->Length());
4021  // Indexed properties in numerical order.
4022  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4023  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4024  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4025  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4026  // Indexed interceptor properties in the order they are returned
4027  // from the enumerator interceptor.
4028  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4029  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4030  // Named properties in insertion order.
4031  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4032  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4033  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4034  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4035  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4036  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4037  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4038  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4039  // Named interceptor properties.
4040  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4041  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4042  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4043}
4044
4045
4046int p_getter_count;
4047int p_getter_count2;
4048
4049
4050static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4051  ApiTestFuzzer::Fuzz();
4052  p_getter_count++;
4053  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4054  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4055  if (name->Equals(v8_str("p1"))) {
4056    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4057  } else if (name->Equals(v8_str("p2"))) {
4058    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4059  } else if (name->Equals(v8_str("p3"))) {
4060    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4061  } else if (name->Equals(v8_str("p4"))) {
4062    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4063  }
4064  return v8::Undefined();
4065}
4066
4067
4068static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4069  ApiTestFuzzer::Fuzz();
4070  LocalContext context;
4071  context->Global()->Set(v8_str("o1"), obj->NewInstance());
4072  CompileRun(
4073    "o1.__proto__ = { };"
4074    "var o2 = { __proto__: o1 };"
4075    "var o3 = { __proto__: o2 };"
4076    "var o4 = { __proto__: o3 };"
4077    "for (var i = 0; i < 10; i++) o4.p4;"
4078    "for (var i = 0; i < 10; i++) o3.p3;"
4079    "for (var i = 0; i < 10; i++) o2.p2;"
4080    "for (var i = 0; i < 10; i++) o1.p1;");
4081}
4082
4083
4084static v8::Handle<Value> PGetter2(Local<String> name,
4085                                  const AccessorInfo& info) {
4086  ApiTestFuzzer::Fuzz();
4087  p_getter_count2++;
4088  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4089  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4090  if (name->Equals(v8_str("p1"))) {
4091    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4092  } else if (name->Equals(v8_str("p2"))) {
4093    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4094  } else if (name->Equals(v8_str("p3"))) {
4095    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4096  } else if (name->Equals(v8_str("p4"))) {
4097    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4098  }
4099  return v8::Undefined();
4100}
4101
4102
4103THREADED_TEST(GetterHolders) {
4104  v8::HandleScope scope;
4105  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4106  obj->SetAccessor(v8_str("p1"), PGetter);
4107  obj->SetAccessor(v8_str("p2"), PGetter);
4108  obj->SetAccessor(v8_str("p3"), PGetter);
4109  obj->SetAccessor(v8_str("p4"), PGetter);
4110  p_getter_count = 0;
4111  RunHolderTest(obj);
4112  CHECK_EQ(40, p_getter_count);
4113}
4114
4115
4116THREADED_TEST(PreInterceptorHolders) {
4117  v8::HandleScope scope;
4118  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4119  obj->SetNamedPropertyHandler(PGetter2);
4120  p_getter_count2 = 0;
4121  RunHolderTest(obj);
4122  CHECK_EQ(40, p_getter_count2);
4123}
4124
4125
4126THREADED_TEST(ObjectInstantiation) {
4127  v8::HandleScope scope;
4128  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4129  templ->SetAccessor(v8_str("t"), PGetter2);
4130  LocalContext context;
4131  context->Global()->Set(v8_str("o"), templ->NewInstance());
4132  for (int i = 0; i < 100; i++) {
4133    v8::HandleScope inner_scope;
4134    v8::Handle<v8::Object> obj = templ->NewInstance();
4135    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4136    context->Global()->Set(v8_str("o2"), obj);
4137    v8::Handle<Value> value =
4138        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4139    CHECK_EQ(v8::True(), value);
4140    context->Global()->Set(v8_str("o"), obj);
4141  }
4142}
4143
4144
4145THREADED_TEST(StringWrite) {
4146  v8::HandleScope scope;
4147  v8::Handle<String> str = v8_str("abcde");
4148
4149  char buf[100];
4150  int len;
4151
4152  memset(buf, 0x1, sizeof(buf));
4153  len = str->WriteAscii(buf);
4154  CHECK_EQ(len, 5);
4155  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4156
4157  memset(buf, 0x1, sizeof(buf));
4158  len = str->WriteAscii(buf, 0, 4);
4159  CHECK_EQ(len, 4);
4160  CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
4161
4162  memset(buf, 0x1, sizeof(buf));
4163  len = str->WriteAscii(buf, 0, 5);
4164  CHECK_EQ(len, 5);
4165  CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
4166
4167  memset(buf, 0x1, sizeof(buf));
4168  len = str->WriteAscii(buf, 0, 6);
4169  CHECK_EQ(len, 5);
4170  CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
4171
4172  memset(buf, 0x1, sizeof(buf));
4173  len = str->WriteAscii(buf, 4, -1);
4174  CHECK_EQ(len, 1);
4175  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4176
4177  memset(buf, 0x1, sizeof(buf));
4178  len = str->WriteAscii(buf, 4, 6);
4179  CHECK_EQ(len, 1);
4180  CHECK_EQ(strncmp("e\0", buf, 2), 0);
4181
4182  memset(buf, 0x1, sizeof(buf));
4183  len = str->WriteAscii(buf, 4, 1);
4184  CHECK_EQ(len, 1);
4185  CHECK_EQ(strncmp("e\1", buf, 2), 0);
4186}
4187
4188
4189THREADED_TEST(ToArrayIndex) {
4190  v8::HandleScope scope;
4191  LocalContext context;
4192
4193  v8::Handle<String> str = v8_str("42");
4194  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4195  CHECK(!index.IsEmpty());
4196  CHECK_EQ(42.0, index->Uint32Value());
4197  str = v8_str("42asdf");
4198  index = str->ToArrayIndex();
4199  CHECK(index.IsEmpty());
4200  str = v8_str("-42");
4201  index = str->ToArrayIndex();
4202  CHECK(index.IsEmpty());
4203  str = v8_str("4294967295");
4204  index = str->ToArrayIndex();
4205  CHECK(!index.IsEmpty());
4206  CHECK_EQ(4294967295.0, index->Uint32Value());
4207  v8::Handle<v8::Number> num = v8::Number::New(1);
4208  index = num->ToArrayIndex();
4209  CHECK(!index.IsEmpty());
4210  CHECK_EQ(1.0, index->Uint32Value());
4211  num = v8::Number::New(-1);
4212  index = num->ToArrayIndex();
4213  CHECK(index.IsEmpty());
4214  v8::Handle<v8::Object> obj = v8::Object::New();
4215  index = obj->ToArrayIndex();
4216  CHECK(index.IsEmpty());
4217}
4218
4219
4220THREADED_TEST(ErrorConstruction) {
4221  v8::HandleScope scope;
4222  LocalContext context;
4223
4224  v8::Handle<String> foo = v8_str("foo");
4225  v8::Handle<String> message = v8_str("message");
4226  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4227  CHECK(range_error->IsObject());
4228  v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4229  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
4230  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4231  CHECK(reference_error->IsObject());
4232  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
4233  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4234  CHECK(syntax_error->IsObject());
4235  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
4236  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4237  CHECK(type_error->IsObject());
4238  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
4239  v8::Handle<Value> error = v8::Exception::Error(foo);
4240  CHECK(error->IsObject());
4241  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
4242}
4243
4244
4245static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4246  ApiTestFuzzer::Fuzz();
4247  return v8_num(10);
4248}
4249
4250
4251static void YSetter(Local<String> name,
4252                    Local<Value> value,
4253                    const AccessorInfo& info) {
4254  if (info.This()->Has(name)) {
4255    info.This()->Delete(name);
4256  }
4257  info.This()->Set(name, value);
4258}
4259
4260
4261THREADED_TEST(DeleteAccessor) {
4262  v8::HandleScope scope;
4263  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4264  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4265  LocalContext context;
4266  v8::Handle<v8::Object> holder = obj->NewInstance();
4267  context->Global()->Set(v8_str("holder"), holder);
4268  v8::Handle<Value> result = CompileRun(
4269      "holder.y = 11; holder.y = 12; holder.y");
4270  CHECK_EQ(12, result->Uint32Value());
4271}
4272
4273
4274THREADED_TEST(TypeSwitch) {
4275  v8::HandleScope scope;
4276  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4277  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4278  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4279  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4280  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4281  LocalContext context;
4282  v8::Handle<v8::Object> obj0 = v8::Object::New();
4283  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4284  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4285  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4286  for (int i = 0; i < 10; i++) {
4287    CHECK_EQ(0, type_switch->match(obj0));
4288    CHECK_EQ(1, type_switch->match(obj1));
4289    CHECK_EQ(2, type_switch->match(obj2));
4290    CHECK_EQ(3, type_switch->match(obj3));
4291    CHECK_EQ(3, type_switch->match(obj3));
4292    CHECK_EQ(2, type_switch->match(obj2));
4293    CHECK_EQ(1, type_switch->match(obj1));
4294    CHECK_EQ(0, type_switch->match(obj0));
4295  }
4296}
4297
4298
4299// For use within the TestSecurityHandler() test.
4300static bool g_security_callback_result = false;
4301static bool NamedSecurityTestCallback(Local<v8::Object> global,
4302                                      Local<Value> name,
4303                                      v8::AccessType type,
4304                                      Local<Value> data) {
4305  // Always allow read access.
4306  if (type == v8::ACCESS_GET)
4307    return true;
4308
4309  // Sometimes allow other access.
4310  return g_security_callback_result;
4311}
4312
4313
4314static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4315                                        uint32_t key,
4316                                        v8::AccessType type,
4317                                        Local<Value> data) {
4318  // Always allow read access.
4319  if (type == v8::ACCESS_GET)
4320    return true;
4321
4322  // Sometimes allow other access.
4323  return g_security_callback_result;
4324}
4325
4326
4327static int trouble_nesting = 0;
4328static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4329  ApiTestFuzzer::Fuzz();
4330  trouble_nesting++;
4331
4332  // Call a JS function that throws an uncaught exception.
4333  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4334  Local<Value> trouble_callee = (trouble_nesting == 3) ?
4335    arg_this->Get(v8_str("trouble_callee")) :
4336    arg_this->Get(v8_str("trouble_caller"));
4337  CHECK(trouble_callee->IsFunction());
4338  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4339}
4340
4341
4342static int report_count = 0;
4343static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4344                                             v8::Handle<Value>) {
4345  report_count++;
4346}
4347
4348
4349// Counts uncaught exceptions, but other tests running in parallel
4350// also have uncaught exceptions.
4351TEST(ApiUncaughtException) {
4352  report_count = 0;
4353  v8::HandleScope scope;
4354  LocalContext env;
4355  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4356
4357  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4358  v8::Local<v8::Object> global = env->Global();
4359  global->Set(v8_str("trouble"), fun->GetFunction());
4360
4361  Script::Compile(v8_str("function trouble_callee() {"
4362                         "  var x = null;"
4363                         "  return x.foo;"
4364                         "};"
4365                         "function trouble_caller() {"
4366                         "  trouble();"
4367                         "};"))->Run();
4368  Local<Value> trouble = global->Get(v8_str("trouble"));
4369  CHECK(trouble->IsFunction());
4370  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4371  CHECK(trouble_callee->IsFunction());
4372  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4373  CHECK(trouble_caller->IsFunction());
4374  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4375  CHECK_EQ(1, report_count);
4376  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4377}
4378
4379static const char* script_resource_name = "ExceptionInNativeScript.js";
4380static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4381                                                v8::Handle<Value>) {
4382  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4383  CHECK(!name_val.IsEmpty() && name_val->IsString());
4384  v8::String::AsciiValue name(message->GetScriptResourceName());
4385  CHECK_EQ(script_resource_name, *name);
4386  CHECK_EQ(3, message->GetLineNumber());
4387  v8::String::AsciiValue source_line(message->GetSourceLine());
4388  CHECK_EQ("  new o.foo();", *source_line);
4389}
4390
4391TEST(ExceptionInNativeScript) {
4392  v8::HandleScope scope;
4393  LocalContext env;
4394  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4395
4396  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4397  v8::Local<v8::Object> global = env->Global();
4398  global->Set(v8_str("trouble"), fun->GetFunction());
4399
4400  Script::Compile(v8_str("function trouble() {\n"
4401                         "  var o = {};\n"
4402                         "  new o.foo();\n"
4403                         "};"), v8::String::New(script_resource_name))->Run();
4404  Local<Value> trouble = global->Get(v8_str("trouble"));
4405  CHECK(trouble->IsFunction());
4406  Function::Cast(*trouble)->Call(global, 0, NULL);
4407  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4408}
4409
4410
4411TEST(CompilationErrorUsingTryCatchHandler) {
4412  v8::HandleScope scope;
4413  LocalContext env;
4414  v8::TryCatch try_catch;
4415  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4416  CHECK_NE(NULL, *try_catch.Exception());
4417  CHECK(try_catch.HasCaught());
4418}
4419
4420
4421TEST(TryCatchFinallyUsingTryCatchHandler) {
4422  v8::HandleScope scope;
4423  LocalContext env;
4424  v8::TryCatch try_catch;
4425  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4426  CHECK(!try_catch.HasCaught());
4427  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4428  CHECK(try_catch.HasCaught());
4429  try_catch.Reset();
4430  Script::Compile(v8_str("(function() {"
4431                         "try { throw ''; } finally { return; }"
4432                         "})()"))->Run();
4433  CHECK(!try_catch.HasCaught());
4434  Script::Compile(v8_str("(function()"
4435                         "  { try { throw ''; } finally { throw 0; }"
4436                         "})()"))->Run();
4437  CHECK(try_catch.HasCaught());
4438}
4439
4440
4441// SecurityHandler can't be run twice
4442TEST(SecurityHandler) {
4443  v8::HandleScope scope0;
4444  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4445  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4446                                           IndexedSecurityTestCallback);
4447  // Create an environment
4448  v8::Persistent<Context> context0 =
4449    Context::New(NULL, global_template);
4450  context0->Enter();
4451
4452  v8::Handle<v8::Object> global0 = context0->Global();
4453  v8::Handle<Script> script0 = v8_compile("foo = 111");
4454  script0->Run();
4455  global0->Set(v8_str("0"), v8_num(999));
4456  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4457  CHECK_EQ(111, foo0->Int32Value());
4458  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4459  CHECK_EQ(999, z0->Int32Value());
4460
4461  // Create another environment, should fail security checks.
4462  v8::HandleScope scope1;
4463
4464  v8::Persistent<Context> context1 =
4465    Context::New(NULL, global_template);
4466  context1->Enter();
4467
4468  v8::Handle<v8::Object> global1 = context1->Global();
4469  global1->Set(v8_str("othercontext"), global0);
4470  // This set will fail the security check.
4471  v8::Handle<Script> script1 =
4472    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4473  script1->Run();
4474  // This read will pass the security check.
4475  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4476  CHECK_EQ(111, foo1->Int32Value());
4477  // This read will pass the security check.
4478  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4479  CHECK_EQ(999, z1->Int32Value());
4480
4481  // Create another environment, should pass security checks.
4482  { g_security_callback_result = true;  // allow security handler to pass.
4483    v8::HandleScope scope2;
4484    LocalContext context2;
4485    v8::Handle<v8::Object> global2 = context2->Global();
4486    global2->Set(v8_str("othercontext"), global0);
4487    v8::Handle<Script> script2 =
4488        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4489    script2->Run();
4490    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4491    CHECK_EQ(333, foo2->Int32Value());
4492    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4493    CHECK_EQ(888, z2->Int32Value());
4494  }
4495
4496  context1->Exit();
4497  context1.Dispose();
4498
4499  context0->Exit();
4500  context0.Dispose();
4501}
4502
4503
4504THREADED_TEST(SecurityChecks) {
4505  v8::HandleScope handle_scope;
4506  LocalContext env1;
4507  v8::Persistent<Context> env2 = Context::New();
4508
4509  Local<Value> foo = v8_str("foo");
4510  Local<Value> bar = v8_str("bar");
4511
4512  // Set to the same domain.
4513  env1->SetSecurityToken(foo);
4514
4515  // Create a function in env1.
4516  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4517  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4518  CHECK(spy->IsFunction());
4519
4520  // Create another function accessing global objects.
4521  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4522  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4523  CHECK(spy2->IsFunction());
4524
4525  // Switch to env2 in the same domain and invoke spy on env2.
4526  {
4527    env2->SetSecurityToken(foo);
4528    // Enter env2
4529    Context::Scope scope_env2(env2);
4530    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4531    CHECK(result->IsFunction());
4532  }
4533
4534  {
4535    env2->SetSecurityToken(bar);
4536    Context::Scope scope_env2(env2);
4537
4538    // Call cross_domain_call, it should throw an exception
4539    v8::TryCatch try_catch;
4540    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4541    CHECK(try_catch.HasCaught());
4542  }
4543
4544  env2.Dispose();
4545}
4546
4547
4548// Regression test case for issue 1183439.
4549THREADED_TEST(SecurityChecksForPrototypeChain) {
4550  v8::HandleScope scope;
4551  LocalContext current;
4552  v8::Persistent<Context> other = Context::New();
4553
4554  // Change context to be able to get to the Object function in the
4555  // other context without hitting the security checks.
4556  v8::Local<Value> other_object;
4557  { Context::Scope scope(other);
4558    other_object = other->Global()->Get(v8_str("Object"));
4559    other->Global()->Set(v8_num(42), v8_num(87));
4560  }
4561
4562  current->Global()->Set(v8_str("other"), other->Global());
4563  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4564
4565  // Make sure the security check fails here and we get an undefined
4566  // result instead of getting the Object function. Repeat in a loop
4567  // to make sure to exercise the IC code.
4568  v8::Local<Script> access_other0 = v8_compile("other.Object");
4569  v8::Local<Script> access_other1 = v8_compile("other[42]");
4570  for (int i = 0; i < 5; i++) {
4571    CHECK(!access_other0->Run()->Equals(other_object));
4572    CHECK(access_other0->Run()->IsUndefined());
4573    CHECK(!access_other1->Run()->Equals(v8_num(87)));
4574    CHECK(access_other1->Run()->IsUndefined());
4575  }
4576
4577  // Create an object that has 'other' in its prototype chain and make
4578  // sure we cannot access the Object function indirectly through
4579  // that. Repeat in a loop to make sure to exercise the IC code.
4580  v8_compile("function F() { };"
4581             "F.prototype = other;"
4582             "var f = new F();")->Run();
4583  v8::Local<Script> access_f0 = v8_compile("f.Object");
4584  v8::Local<Script> access_f1 = v8_compile("f[42]");
4585  for (int j = 0; j < 5; j++) {
4586    CHECK(!access_f0->Run()->Equals(other_object));
4587    CHECK(access_f0->Run()->IsUndefined());
4588    CHECK(!access_f1->Run()->Equals(v8_num(87)));
4589    CHECK(access_f1->Run()->IsUndefined());
4590  }
4591
4592  // Now it gets hairy: Set the prototype for the other global object
4593  // to be the current global object. The prototype chain for 'f' now
4594  // goes through 'other' but ends up in the current global object.
4595  { Context::Scope scope(other);
4596    other->Global()->Set(v8_str("__proto__"), current->Global());
4597  }
4598  // Set a named and an index property on the current global
4599  // object. To force the lookup to go through the other global object,
4600  // the properties must not exist in the other global object.
4601  current->Global()->Set(v8_str("foo"), v8_num(100));
4602  current->Global()->Set(v8_num(99), v8_num(101));
4603  // Try to read the properties from f and make sure that the access
4604  // gets stopped by the security checks on the other global object.
4605  Local<Script> access_f2 = v8_compile("f.foo");
4606  Local<Script> access_f3 = v8_compile("f[99]");
4607  for (int k = 0; k < 5; k++) {
4608    CHECK(!access_f2->Run()->Equals(v8_num(100)));
4609    CHECK(access_f2->Run()->IsUndefined());
4610    CHECK(!access_f3->Run()->Equals(v8_num(101)));
4611    CHECK(access_f3->Run()->IsUndefined());
4612  }
4613  other.Dispose();
4614}
4615
4616
4617THREADED_TEST(CrossDomainDelete) {
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 delete env1.prop.
4633  env2->SetSecurityToken(bar);
4634  {
4635    Context::Scope scope_env2(env2);
4636    Local<Value> result =
4637        Script::Compile(v8_str("delete env1.prop"))->Run();
4638    CHECK(result->IsFalse());
4639  }
4640
4641  // Check that env1.prop still exists.
4642  Local<Value> v = env1->Global()->Get(v8_str("prop"));
4643  CHECK(v->IsNumber());
4644  CHECK_EQ(3, v->Int32Value());
4645
4646  env2.Dispose();
4647}
4648
4649
4650THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4651  v8::HandleScope handle_scope;
4652  LocalContext env1;
4653  v8::Persistent<Context> env2 = Context::New();
4654
4655  Local<Value> foo = v8_str("foo");
4656  Local<Value> bar = v8_str("bar");
4657
4658  // Set to the same domain.
4659  env1->SetSecurityToken(foo);
4660  env2->SetSecurityToken(foo);
4661
4662  env1->Global()->Set(v8_str("prop"), v8_num(3));
4663  env2->Global()->Set(v8_str("env1"), env1->Global());
4664
4665  // env1.prop is enumerable in env2.
4666  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4667  {
4668    Context::Scope scope_env2(env2);
4669    Local<Value> result = Script::Compile(test)->Run();
4670    CHECK(result->IsTrue());
4671  }
4672
4673  // Change env2 to a different domain and test again.
4674  env2->SetSecurityToken(bar);
4675  {
4676    Context::Scope scope_env2(env2);
4677    Local<Value> result = Script::Compile(test)->Run();
4678    CHECK(result->IsFalse());
4679  }
4680
4681  env2.Dispose();
4682}
4683
4684
4685THREADED_TEST(CrossDomainForIn) {
4686  v8::HandleScope handle_scope;
4687  LocalContext env1;
4688  v8::Persistent<Context> env2 = Context::New();
4689
4690  Local<Value> foo = v8_str("foo");
4691  Local<Value> bar = v8_str("bar");
4692
4693  // Set to the same domain.
4694  env1->SetSecurityToken(foo);
4695  env2->SetSecurityToken(foo);
4696
4697  env1->Global()->Set(v8_str("prop"), v8_num(3));
4698  env2->Global()->Set(v8_str("env1"), env1->Global());
4699
4700  // Change env2 to a different domain and set env1's global object
4701  // as the __proto__ of an object in env2 and enumerate properties
4702  // in for-in. It shouldn't enumerate properties on env1's global
4703  // object.
4704  env2->SetSecurityToken(bar);
4705  {
4706    Context::Scope scope_env2(env2);
4707    Local<Value> result =
4708        CompileRun("(function(){var obj = {'__proto__':env1};"
4709                   "for (var p in obj)"
4710                   "   if (p == 'prop') return false;"
4711                   "return true;})()");
4712    CHECK(result->IsTrue());
4713  }
4714  env2.Dispose();
4715}
4716
4717
4718TEST(ContextDetachGlobal) {
4719  v8::HandleScope handle_scope;
4720  LocalContext env1;
4721  v8::Persistent<Context> env2 = Context::New();
4722
4723  Local<v8::Object> global1 = env1->Global();
4724
4725  Local<Value> foo = v8_str("foo");
4726
4727  // Set to the same domain.
4728  env1->SetSecurityToken(foo);
4729  env2->SetSecurityToken(foo);
4730
4731  // Enter env2
4732  env2->Enter();
4733
4734  // Create a function in env2 and add a reference to it in env1.
4735  Local<v8::Object> global2 = env2->Global();
4736  global2->Set(v8_str("prop"), v8::Integer::New(1));
4737  CompileRun("function getProp() {return prop;}");
4738
4739  env1->Global()->Set(v8_str("getProp"),
4740                      global2->Get(v8_str("getProp")));
4741
4742  // Detach env2's global, and reuse the global object of env2
4743  env2->Exit();
4744  env2->DetachGlobal();
4745  // env2 has a new global object.
4746  CHECK(!env2->Global()->Equals(global2));
4747
4748  v8::Persistent<Context> env3 =
4749      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4750  env3->SetSecurityToken(v8_str("bar"));
4751  env3->Enter();
4752
4753  Local<v8::Object> global3 = env3->Global();
4754  CHECK_EQ(global2, global3);
4755  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4756  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4757  global3->Set(v8_str("prop"), v8::Integer::New(-1));
4758  global3->Set(v8_str("prop2"), v8::Integer::New(2));
4759  env3->Exit();
4760
4761  // Call getProp in env1, and it should return the value 1
4762  {
4763    Local<Value> get_prop = global1->Get(v8_str("getProp"));
4764    CHECK(get_prop->IsFunction());
4765    v8::TryCatch try_catch;
4766    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4767    CHECK(!try_catch.HasCaught());
4768    CHECK_EQ(1, r->Int32Value());
4769  }
4770
4771  // Check that env3 is not accessible from env1
4772  {
4773    Local<Value> r = global3->Get(v8_str("prop2"));
4774    CHECK(r->IsUndefined());
4775  }
4776
4777  env2.Dispose();
4778  env3.Dispose();
4779}
4780
4781
4782TEST(DetachAndReattachGlobal) {
4783  v8::HandleScope scope;
4784  LocalContext env1;
4785
4786  // Create second environment.
4787  v8::Persistent<Context> env2 = Context::New();
4788
4789  Local<Value> foo = v8_str("foo");
4790
4791  // Set same security token for env1 and env2.
4792  env1->SetSecurityToken(foo);
4793  env2->SetSecurityToken(foo);
4794
4795  // Create a property on the global object in env2.
4796  {
4797    v8::Context::Scope scope(env2);
4798    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4799  }
4800
4801  // Create a reference to env2 global from env1 global.
4802  env1->Global()->Set(v8_str("other"), env2->Global());
4803
4804  // Check that we have access to other.p in env2 from env1.
4805  Local<Value> result = CompileRun("other.p");
4806  CHECK(result->IsInt32());
4807  CHECK_EQ(42, result->Int32Value());
4808
4809  // Hold on to global from env2 and detach global from env2.
4810  Local<v8::Object> global2 = env2->Global();
4811  env2->DetachGlobal();
4812
4813  // Check that the global has been detached. No other.p property can
4814  // be found.
4815  result = CompileRun("other.p");
4816  CHECK(result->IsUndefined());
4817
4818  // Reuse global2 for env3.
4819  v8::Persistent<Context> env3 =
4820      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4821  CHECK_EQ(global2, env3->Global());
4822
4823  // Start by using the same security token for env3 as for env1 and env2.
4824  env3->SetSecurityToken(foo);
4825
4826  // Create a property on the global object in env3.
4827  {
4828    v8::Context::Scope scope(env3);
4829    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4830  }
4831
4832  // Check that other.p is now the property in env3 and that we have access.
4833  result = CompileRun("other.p");
4834  CHECK(result->IsInt32());
4835  CHECK_EQ(24, result->Int32Value());
4836
4837  // Change security token for env3 to something different from env1 and env2.
4838  env3->SetSecurityToken(v8_str("bar"));
4839
4840  // Check that we do not have access to other.p in env1. |other| is now
4841  // the global object for env3 which has a different security token,
4842  // so access should be blocked.
4843  result = CompileRun("other.p");
4844  CHECK(result->IsUndefined());
4845
4846  // Detach the global for env3 and reattach it to env2.
4847  env3->DetachGlobal();
4848  env2->ReattachGlobal(global2);
4849
4850  // Check that we have access to other.p again in env1.  |other| is now
4851  // the global object for env2 which has the same security token as env1.
4852  result = CompileRun("other.p");
4853  CHECK(result->IsInt32());
4854  CHECK_EQ(42, result->Int32Value());
4855
4856  env2.Dispose();
4857  env3.Dispose();
4858}
4859
4860
4861static bool NamedAccessBlocker(Local<v8::Object> global,
4862                               Local<Value> name,
4863                               v8::AccessType type,
4864                               Local<Value> data) {
4865  return Context::GetCurrent()->Global()->Equals(global);
4866}
4867
4868
4869static bool IndexedAccessBlocker(Local<v8::Object> global,
4870                                 uint32_t key,
4871                                 v8::AccessType type,
4872                                 Local<Value> data) {
4873  return Context::GetCurrent()->Global()->Equals(global);
4874}
4875
4876
4877static int g_echo_value = -1;
4878static v8::Handle<Value> EchoGetter(Local<String> name,
4879                                    const AccessorInfo& info) {
4880  return v8_num(g_echo_value);
4881}
4882
4883
4884static void EchoSetter(Local<String> name,
4885                       Local<Value> value,
4886                       const AccessorInfo&) {
4887  if (value->IsNumber())
4888    g_echo_value = value->Int32Value();
4889}
4890
4891
4892static v8::Handle<Value> UnreachableGetter(Local<String> name,
4893                                           const AccessorInfo& info) {
4894  CHECK(false);  // This function should not be called..
4895  return v8::Undefined();
4896}
4897
4898
4899static void UnreachableSetter(Local<String>, Local<Value>,
4900                              const AccessorInfo&) {
4901  CHECK(false);  // This function should nto be called.
4902}
4903
4904
4905THREADED_TEST(AccessControl) {
4906  v8::HandleScope handle_scope;
4907  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4908
4909  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4910                                           IndexedAccessBlocker);
4911
4912  // Add an accessor accessible by cross-domain JS code.
4913  global_template->SetAccessor(
4914      v8_str("accessible_prop"),
4915      EchoGetter, EchoSetter,
4916      v8::Handle<Value>(),
4917      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4918
4919  // Add an accessor that is not accessible by cross-domain JS code.
4920  global_template->SetAccessor(v8_str("blocked_prop"),
4921                               UnreachableGetter, UnreachableSetter,
4922                               v8::Handle<Value>(),
4923                               v8::DEFAULT);
4924
4925  // Create an environment
4926  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4927  context0->Enter();
4928
4929  v8::Handle<v8::Object> global0 = context0->Global();
4930
4931  v8::HandleScope scope1;
4932
4933  v8::Persistent<Context> context1 = Context::New();
4934  context1->Enter();
4935
4936  v8::Handle<v8::Object> global1 = context1->Global();
4937  global1->Set(v8_str("other"), global0);
4938
4939  v8::Handle<Value> value;
4940
4941  // Access blocked property
4942  value = v8_compile("other.blocked_prop = 1")->Run();
4943  value = v8_compile("other.blocked_prop")->Run();
4944  CHECK(value->IsUndefined());
4945
4946  value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4947  CHECK(value->IsFalse());
4948
4949  // Access accessible property
4950  value = v8_compile("other.accessible_prop = 3")->Run();
4951  CHECK(value->IsNumber());
4952  CHECK_EQ(3, value->Int32Value());
4953  CHECK_EQ(3, g_echo_value);
4954
4955  value = v8_compile("other.accessible_prop")->Run();
4956  CHECK(value->IsNumber());
4957  CHECK_EQ(3, value->Int32Value());
4958
4959  value =
4960    v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4961  CHECK(value->IsTrue());
4962
4963  // Enumeration doesn't enumerate accessors from inaccessible objects in
4964  // the prototype chain even if the accessors are in themselves accessible.
4965  Local<Value> result =
4966      CompileRun("(function(){var obj = {'__proto__':other};"
4967                 "for (var p in obj)"
4968                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4969                 "     return false;"
4970                 "   }"
4971                 "return true;})()");
4972  CHECK(result->IsTrue());
4973
4974  context1->Exit();
4975  context0->Exit();
4976  context1.Dispose();
4977  context0.Dispose();
4978}
4979
4980
4981static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4982                                            Local<Value> name,
4983                                            v8::AccessType type,
4984                                            Local<Value> data) {
4985  return false;
4986}
4987
4988
4989static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4990                                              uint32_t key,
4991                                              v8::AccessType type,
4992                                              Local<Value> data) {
4993  return false;
4994}
4995
4996
4997THREADED_TEST(AccessControlGetOwnPropertyNames) {
4998  v8::HandleScope handle_scope;
4999  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5000
5001  obj_template->Set(v8_str("x"), v8::Integer::New(42));
5002  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5003                                        GetOwnPropertyNamesIndexedBlocker);
5004
5005  // Create an environment
5006  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5007  context0->Enter();
5008
5009  v8::Handle<v8::Object> global0 = context0->Global();
5010
5011  v8::HandleScope scope1;
5012
5013  v8::Persistent<Context> context1 = Context::New();
5014  context1->Enter();
5015
5016  v8::Handle<v8::Object> global1 = context1->Global();
5017  global1->Set(v8_str("other"), global0);
5018  global1->Set(v8_str("object"), obj_template->NewInstance());
5019
5020  v8::Handle<Value> value;
5021
5022  // Attempt to get the property names of the other global object and
5023  // of an object that requires access checks.  Accessing the other
5024  // global object should be blocked by access checks on the global
5025  // proxy object.  Accessing the object that requires access checks
5026  // is blocked by the access checks on the object itself.
5027  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5028  CHECK(value->IsTrue());
5029
5030  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5031  CHECK(value->IsTrue());
5032
5033  context1->Exit();
5034  context0->Exit();
5035  context1.Dispose();
5036  context0.Dispose();
5037}
5038
5039
5040static v8::Handle<Value> ConstTenGetter(Local<String> name,
5041                                        const AccessorInfo& info) {
5042  return v8_num(10);
5043}
5044
5045
5046THREADED_TEST(CrossDomainAccessors) {
5047  v8::HandleScope handle_scope;
5048
5049  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5050
5051  v8::Handle<v8::ObjectTemplate> global_template =
5052      func_template->InstanceTemplate();
5053
5054  v8::Handle<v8::ObjectTemplate> proto_template =
5055      func_template->PrototypeTemplate();
5056
5057  // Add an accessor to proto that's accessible by cross-domain JS code.
5058  proto_template->SetAccessor(v8_str("accessible"),
5059                              ConstTenGetter, 0,
5060                              v8::Handle<Value>(),
5061                              v8::ALL_CAN_READ);
5062
5063  // Add an accessor that is not accessible by cross-domain JS code.
5064  global_template->SetAccessor(v8_str("unreachable"),
5065                               UnreachableGetter, 0,
5066                               v8::Handle<Value>(),
5067                               v8::DEFAULT);
5068
5069  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5070  context0->Enter();
5071
5072  Local<v8::Object> global = context0->Global();
5073  // Add a normal property that shadows 'accessible'
5074  global->Set(v8_str("accessible"), v8_num(11));
5075
5076  // Enter a new context.
5077  v8::HandleScope scope1;
5078  v8::Persistent<Context> context1 = Context::New();
5079  context1->Enter();
5080
5081  v8::Handle<v8::Object> global1 = context1->Global();
5082  global1->Set(v8_str("other"), global);
5083
5084  // Should return 10, instead of 11
5085  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5086  CHECK(value->IsNumber());
5087  CHECK_EQ(10, value->Int32Value());
5088
5089  value = v8_compile("other.unreachable")->Run();
5090  CHECK(value->IsUndefined());
5091
5092  context1->Exit();
5093  context0->Exit();
5094  context1.Dispose();
5095  context0.Dispose();
5096}
5097
5098
5099static int named_access_count = 0;
5100static int indexed_access_count = 0;
5101
5102static bool NamedAccessCounter(Local<v8::Object> global,
5103                               Local<Value> name,
5104                               v8::AccessType type,
5105                               Local<Value> data) {
5106  named_access_count++;
5107  return true;
5108}
5109
5110
5111static bool IndexedAccessCounter(Local<v8::Object> global,
5112                                 uint32_t key,
5113                                 v8::AccessType type,
5114                                 Local<Value> data) {
5115  indexed_access_count++;
5116  return true;
5117}
5118
5119
5120// This one is too easily disturbed by other tests.
5121TEST(AccessControlIC) {
5122  named_access_count = 0;
5123  indexed_access_count = 0;
5124
5125  v8::HandleScope handle_scope;
5126
5127  // Create an environment.
5128  v8::Persistent<Context> context0 = Context::New();
5129  context0->Enter();
5130
5131  // Create an object that requires access-check functions to be
5132  // called for cross-domain access.
5133  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5134  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5135                                           IndexedAccessCounter);
5136  Local<v8::Object> object = object_template->NewInstance();
5137
5138  v8::HandleScope scope1;
5139
5140  // Create another environment.
5141  v8::Persistent<Context> context1 = Context::New();
5142  context1->Enter();
5143
5144  // Make easy access to the object from the other environment.
5145  v8::Handle<v8::Object> global1 = context1->Global();
5146  global1->Set(v8_str("obj"), object);
5147
5148  v8::Handle<Value> value;
5149
5150  // Check that the named access-control function is called every time.
5151  CompileRun("function testProp(obj) {"
5152             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
5153             "  for (var j = 0; j < 10; j++) obj.prop;"
5154             "  return obj.prop"
5155             "}");
5156  value = CompileRun("testProp(obj)");
5157  CHECK(value->IsNumber());
5158  CHECK_EQ(1, value->Int32Value());
5159  CHECK_EQ(21, named_access_count);
5160
5161  // Check that the named access-control function is called every time.
5162  CompileRun("var p = 'prop';"
5163             "function testKeyed(obj) {"
5164             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
5165             "  for (var j = 0; j < 10; j++) obj[p];"
5166             "  return obj[p];"
5167             "}");
5168  // Use obj which requires access checks.  No inline caching is used
5169  // in that case.
5170  value = CompileRun("testKeyed(obj)");
5171  CHECK(value->IsNumber());
5172  CHECK_EQ(1, value->Int32Value());
5173  CHECK_EQ(42, named_access_count);
5174  // Force the inline caches into generic state and try again.
5175  CompileRun("testKeyed({ a: 0 })");
5176  CompileRun("testKeyed({ b: 0 })");
5177  value = CompileRun("testKeyed(obj)");
5178  CHECK(value->IsNumber());
5179  CHECK_EQ(1, value->Int32Value());
5180  CHECK_EQ(63, named_access_count);
5181
5182  // Check that the indexed access-control function is called every time.
5183  CompileRun("function testIndexed(obj) {"
5184             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
5185             "  for (var j = 0; j < 10; j++) obj[0];"
5186             "  return obj[0]"
5187             "}");
5188  value = CompileRun("testIndexed(obj)");
5189  CHECK(value->IsNumber());
5190  CHECK_EQ(1, value->Int32Value());
5191  CHECK_EQ(21, indexed_access_count);
5192  // Force the inline caches into generic state.
5193  CompileRun("testIndexed(new Array(1))");
5194  // Test that the indexed access check is called.
5195  value = CompileRun("testIndexed(obj)");
5196  CHECK(value->IsNumber());
5197  CHECK_EQ(1, value->Int32Value());
5198  CHECK_EQ(42, indexed_access_count);
5199
5200  // Check that the named access check is called when invoking
5201  // functions on an object that requires access checks.
5202  CompileRun("obj.f = function() {}");
5203  CompileRun("function testCallNormal(obj) {"
5204             "  for (var i = 0; i < 10; i++) obj.f();"
5205             "}");
5206  CompileRun("testCallNormal(obj)");
5207  CHECK_EQ(74, named_access_count);
5208
5209  // Force obj into slow case.
5210  value = CompileRun("delete obj.prop");
5211  CHECK(value->BooleanValue());
5212  // Force inline caches into dictionary probing mode.
5213  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5214  // Test that the named access check is called.
5215  value = CompileRun("testProp(obj);");
5216  CHECK(value->IsNumber());
5217  CHECK_EQ(1, value->Int32Value());
5218  CHECK_EQ(96, named_access_count);
5219
5220  // Force the call inline cache into dictionary probing mode.
5221  CompileRun("o.f = function() {}; testCallNormal(o)");
5222  // Test that the named access check is still called for each
5223  // invocation of the function.
5224  value = CompileRun("testCallNormal(obj)");
5225  CHECK_EQ(106, named_access_count);
5226
5227  context1->Exit();
5228  context0->Exit();
5229  context1.Dispose();
5230  context0.Dispose();
5231}
5232
5233
5234static bool NamedAccessFlatten(Local<v8::Object> global,
5235                               Local<Value> name,
5236                               v8::AccessType type,
5237                               Local<Value> data) {
5238  char buf[100];
5239  int len;
5240
5241  CHECK(name->IsString());
5242
5243  memset(buf, 0x1, sizeof(buf));
5244  len = name.As<String>()->WriteAscii(buf);
5245  CHECK_EQ(4, len);
5246
5247  uint16_t buf2[100];
5248
5249  memset(buf, 0x1, sizeof(buf));
5250  len = name.As<String>()->Write(buf2);
5251  CHECK_EQ(4, len);
5252
5253  return true;
5254}
5255
5256
5257static bool IndexedAccessFlatten(Local<v8::Object> global,
5258                                 uint32_t key,
5259                                 v8::AccessType type,
5260                                 Local<Value> data) {
5261  return true;
5262}
5263
5264
5265// Regression test.  In access checks, operations that may cause
5266// garbage collection are not allowed.  It used to be the case that
5267// using the Write operation on a string could cause a garbage
5268// collection due to flattening of the string.  This is no longer the
5269// case.
5270THREADED_TEST(AccessControlFlatten) {
5271  named_access_count = 0;
5272  indexed_access_count = 0;
5273
5274  v8::HandleScope handle_scope;
5275
5276  // Create an environment.
5277  v8::Persistent<Context> context0 = Context::New();
5278  context0->Enter();
5279
5280  // Create an object that requires access-check functions to be
5281  // called for cross-domain access.
5282  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5283  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5284                                           IndexedAccessFlatten);
5285  Local<v8::Object> object = object_template->NewInstance();
5286
5287  v8::HandleScope scope1;
5288
5289  // Create another environment.
5290  v8::Persistent<Context> context1 = Context::New();
5291  context1->Enter();
5292
5293  // Make easy access to the object from the other environment.
5294  v8::Handle<v8::Object> global1 = context1->Global();
5295  global1->Set(v8_str("obj"), object);
5296
5297  v8::Handle<Value> value;
5298
5299  value = v8_compile("var p = 'as' + 'df';")->Run();
5300  value = v8_compile("obj[p];")->Run();
5301
5302  context1->Exit();
5303  context0->Exit();
5304  context1.Dispose();
5305  context0.Dispose();
5306}
5307
5308
5309static v8::Handle<Value> AccessControlNamedGetter(
5310    Local<String>, const AccessorInfo&) {
5311  return v8::Integer::New(42);
5312}
5313
5314
5315static v8::Handle<Value> AccessControlNamedSetter(
5316    Local<String>, Local<Value> value, const AccessorInfo&) {
5317  return value;
5318}
5319
5320
5321static v8::Handle<Value> AccessControlIndexedGetter(
5322      uint32_t index,
5323      const AccessorInfo& info) {
5324  return v8_num(42);
5325}
5326
5327
5328static v8::Handle<Value> AccessControlIndexedSetter(
5329    uint32_t, Local<Value> value, const AccessorInfo&) {
5330  return value;
5331}
5332
5333
5334THREADED_TEST(AccessControlInterceptorIC) {
5335  named_access_count = 0;
5336  indexed_access_count = 0;
5337
5338  v8::HandleScope handle_scope;
5339
5340  // Create an environment.
5341  v8::Persistent<Context> context0 = Context::New();
5342  context0->Enter();
5343
5344  // Create an object that requires access-check functions to be
5345  // called for cross-domain access.  The object also has interceptors
5346  // interceptor.
5347  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5348  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5349                                           IndexedAccessCounter);
5350  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5351                                           AccessControlNamedSetter);
5352  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5353                                             AccessControlIndexedSetter);
5354  Local<v8::Object> object = object_template->NewInstance();
5355
5356  v8::HandleScope scope1;
5357
5358  // Create another environment.
5359  v8::Persistent<Context> context1 = Context::New();
5360  context1->Enter();
5361
5362  // Make easy access to the object from the other environment.
5363  v8::Handle<v8::Object> global1 = context1->Global();
5364  global1->Set(v8_str("obj"), object);
5365
5366  v8::Handle<Value> value;
5367
5368  // Check that the named access-control function is called every time
5369  // eventhough there is an interceptor on the object.
5370  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5371  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5372                     "obj.x")->Run();
5373  CHECK(value->IsNumber());
5374  CHECK_EQ(42, value->Int32Value());
5375  CHECK_EQ(21, named_access_count);
5376
5377  value = v8_compile("var p = 'x';")->Run();
5378  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5379  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5380                     "obj[p]")->Run();
5381  CHECK(value->IsNumber());
5382  CHECK_EQ(42, value->Int32Value());
5383  CHECK_EQ(42, named_access_count);
5384
5385  // Check that the indexed access-control function is called every
5386  // time eventhough there is an interceptor on the object.
5387  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5388  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5389                     "obj[0]")->Run();
5390  CHECK(value->IsNumber());
5391  CHECK_EQ(42, value->Int32Value());
5392  CHECK_EQ(21, indexed_access_count);
5393
5394  context1->Exit();
5395  context0->Exit();
5396  context1.Dispose();
5397  context0.Dispose();
5398}
5399
5400
5401THREADED_TEST(Version) {
5402  v8::V8::GetVersion();
5403}
5404
5405
5406static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5407  ApiTestFuzzer::Fuzz();
5408  return v8_num(12);
5409}
5410
5411
5412THREADED_TEST(InstanceProperties) {
5413  v8::HandleScope handle_scope;
5414  LocalContext context;
5415
5416  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5417  Local<ObjectTemplate> instance = t->InstanceTemplate();
5418
5419  instance->Set(v8_str("x"), v8_num(42));
5420  instance->Set(v8_str("f"),
5421                v8::FunctionTemplate::New(InstanceFunctionCallback));
5422
5423  Local<Value> o = t->GetFunction()->NewInstance();
5424
5425  context->Global()->Set(v8_str("i"), o);
5426  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5427  CHECK_EQ(42, value->Int32Value());
5428
5429  value = Script::Compile(v8_str("i.f()"))->Run();
5430  CHECK_EQ(12, value->Int32Value());
5431}
5432
5433
5434static v8::Handle<Value>
5435GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5436  ApiTestFuzzer::Fuzz();
5437  return v8::Handle<Value>();
5438}
5439
5440
5441THREADED_TEST(GlobalObjectInstanceProperties) {
5442  v8::HandleScope handle_scope;
5443
5444  Local<Value> global_object;
5445
5446  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5447  t->InstanceTemplate()->SetNamedPropertyHandler(
5448      GlobalObjectInstancePropertiesGet);
5449  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5450  instance_template->Set(v8_str("x"), v8_num(42));
5451  instance_template->Set(v8_str("f"),
5452                         v8::FunctionTemplate::New(InstanceFunctionCallback));
5453
5454  {
5455    LocalContext env(NULL, instance_template);
5456    // Hold on to the global object so it can be used again in another
5457    // environment initialization.
5458    global_object = env->Global();
5459
5460    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5461    CHECK_EQ(42, value->Int32Value());
5462    value = Script::Compile(v8_str("f()"))->Run();
5463    CHECK_EQ(12, value->Int32Value());
5464  }
5465
5466  {
5467    // Create new environment reusing the global object.
5468    LocalContext env(NULL, instance_template, global_object);
5469    Local<Value> value = Script::Compile(v8_str("x"))->Run();
5470    CHECK_EQ(42, value->Int32Value());
5471    value = Script::Compile(v8_str("f()"))->Run();
5472    CHECK_EQ(12, value->Int32Value());
5473  }
5474}
5475
5476
5477static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5478  ApiTestFuzzer::Fuzz();
5479  return v8_num(42);
5480}
5481
5482
5483static int shadow_y;
5484static int shadow_y_setter_call_count;
5485static int shadow_y_getter_call_count;
5486
5487
5488static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5489  shadow_y_setter_call_count++;
5490  shadow_y = 42;
5491}
5492
5493
5494static v8::Handle<Value> ShadowYGetter(Local<String> name,
5495                                       const AccessorInfo& info) {
5496  ApiTestFuzzer::Fuzz();
5497  shadow_y_getter_call_count++;
5498  return v8_num(shadow_y);
5499}
5500
5501
5502static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5503                                          const AccessorInfo& info) {
5504  return v8::Handle<Value>();
5505}
5506
5507
5508static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5509                                        const AccessorInfo&) {
5510  return v8::Handle<Value>();
5511}
5512
5513
5514THREADED_TEST(ShadowObject) {
5515  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5516  v8::HandleScope handle_scope;
5517
5518  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5519  LocalContext context(NULL, global_template);
5520
5521  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5522  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5523  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5524  Local<ObjectTemplate> proto = t->PrototypeTemplate();
5525  Local<ObjectTemplate> instance = t->InstanceTemplate();
5526
5527  // Only allow calls of f on instances of t.
5528  Local<v8::Signature> signature = v8::Signature::New(t);
5529  proto->Set(v8_str("f"),
5530             v8::FunctionTemplate::New(ShadowFunctionCallback,
5531                                       Local<Value>(),
5532                                       signature));
5533  proto->Set(v8_str("x"), v8_num(12));
5534
5535  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5536
5537  Local<Value> o = t->GetFunction()->NewInstance();
5538  context->Global()->Set(v8_str("__proto__"), o);
5539
5540  Local<Value> value =
5541      Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5542  CHECK(value->IsBoolean());
5543  CHECK(!value->BooleanValue());
5544
5545  value = Script::Compile(v8_str("x"))->Run();
5546  CHECK_EQ(12, value->Int32Value());
5547
5548  value = Script::Compile(v8_str("f()"))->Run();
5549  CHECK_EQ(42, value->Int32Value());
5550
5551  Script::Compile(v8_str("y = 42"))->Run();
5552  CHECK_EQ(1, shadow_y_setter_call_count);
5553  value = Script::Compile(v8_str("y"))->Run();
5554  CHECK_EQ(1, shadow_y_getter_call_count);
5555  CHECK_EQ(42, value->Int32Value());
5556}
5557
5558
5559THREADED_TEST(HiddenPrototype) {
5560  v8::HandleScope handle_scope;
5561  LocalContext context;
5562
5563  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5564  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5565  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5566  t1->SetHiddenPrototype(true);
5567  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5568  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5569  t2->SetHiddenPrototype(true);
5570  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5571  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5572  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5573
5574  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5575  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5576  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5577  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5578
5579  // Setting the prototype on an object skips hidden prototypes.
5580  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5581  o0->Set(v8_str("__proto__"), o1);
5582  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5583  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5584  o0->Set(v8_str("__proto__"), o2);
5585  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5586  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5587  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5588  o0->Set(v8_str("__proto__"), o3);
5589  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5590  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5591  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5592  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5593
5594  // Getting the prototype of o0 should get the first visible one
5595  // which is o3.  Therefore, z should not be defined on the prototype
5596  // object.
5597  Local<Value> proto = o0->Get(v8_str("__proto__"));
5598  CHECK(proto->IsObject());
5599  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
5600}
5601
5602
5603THREADED_TEST(SetPrototype) {
5604  v8::HandleScope handle_scope;
5605  LocalContext context;
5606
5607  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5608  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5609  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5610  t1->SetHiddenPrototype(true);
5611  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5612  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5613  t2->SetHiddenPrototype(true);
5614  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5615  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5616  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5617
5618  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5619  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5620  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5621  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5622
5623  // Setting the prototype on an object does not skip hidden prototypes.
5624  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5625  CHECK(o0->SetPrototype(o1));
5626  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5627  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5628  CHECK(o1->SetPrototype(o2));
5629  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5630  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5631  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5632  CHECK(o2->SetPrototype(o3));
5633  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5634  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5635  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5636  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5637
5638  // Getting the prototype of o0 should get the first visible one
5639  // which is o3.  Therefore, z should not be defined on the prototype
5640  // object.
5641  Local<Value> proto = o0->Get(v8_str("__proto__"));
5642  CHECK(proto->IsObject());
5643  CHECK_EQ(proto.As<v8::Object>(), o3);
5644
5645  // However, Object::GetPrototype ignores hidden prototype.
5646  Local<Value> proto0 = o0->GetPrototype();
5647  CHECK(proto0->IsObject());
5648  CHECK_EQ(proto0.As<v8::Object>(), o1);
5649
5650  Local<Value> proto1 = o1->GetPrototype();
5651  CHECK(proto1->IsObject());
5652  CHECK_EQ(proto1.As<v8::Object>(), o2);
5653
5654  Local<Value> proto2 = o2->GetPrototype();
5655  CHECK(proto2->IsObject());
5656  CHECK_EQ(proto2.As<v8::Object>(), o3);
5657}
5658
5659
5660THREADED_TEST(SetPrototypeThrows) {
5661  v8::HandleScope handle_scope;
5662  LocalContext context;
5663
5664  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5665
5666  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5667  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5668
5669  CHECK(o0->SetPrototype(o1));
5670  // If setting the prototype leads to the cycle, SetPrototype should
5671  // return false and keep VM in sane state.
5672  v8::TryCatch try_catch;
5673  CHECK(!o1->SetPrototype(o0));
5674  CHECK(!try_catch.HasCaught());
5675  ASSERT(!i::Top::has_pending_exception());
5676
5677  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5678}
5679
5680
5681THREADED_TEST(GetterSetterExceptions) {
5682  v8::HandleScope handle_scope;
5683  LocalContext context;
5684  CompileRun(
5685    "function Foo() { };"
5686    "function Throw() { throw 5; };"
5687    "var x = { };"
5688    "x.__defineSetter__('set', Throw);"
5689    "x.__defineGetter__('get', Throw);");
5690  Local<v8::Object> x =
5691      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5692  v8::TryCatch try_catch;
5693  x->Set(v8_str("set"), v8::Integer::New(8));
5694  x->Get(v8_str("get"));
5695  x->Set(v8_str("set"), v8::Integer::New(8));
5696  x->Get(v8_str("get"));
5697  x->Set(v8_str("set"), v8::Integer::New(8));
5698  x->Get(v8_str("get"));
5699  x->Set(v8_str("set"), v8::Integer::New(8));
5700  x->Get(v8_str("get"));
5701}
5702
5703
5704THREADED_TEST(Constructor) {
5705  v8::HandleScope handle_scope;
5706  LocalContext context;
5707  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5708  templ->SetClassName(v8_str("Fun"));
5709  Local<Function> cons = templ->GetFunction();
5710  context->Global()->Set(v8_str("Fun"), cons);
5711  Local<v8::Object> inst = cons->NewInstance();
5712  i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5713  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5714  CHECK(value->BooleanValue());
5715}
5716
5717THREADED_TEST(FunctionDescriptorException) {
5718  v8::HandleScope handle_scope;
5719  LocalContext context;
5720  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5721  templ->SetClassName(v8_str("Fun"));
5722  Local<Function> cons = templ->GetFunction();
5723  context->Global()->Set(v8_str("Fun"), cons);
5724  Local<Value> value = CompileRun(
5725    "function test() {"
5726    "  try {"
5727    "    (new Fun()).blah()"
5728    "  } catch (e) {"
5729    "    var str = String(e);"
5730    "    if (str.indexOf('TypeError') == -1) return 1;"
5731    "    if (str.indexOf('[object Fun]') != -1) return 2;"
5732    "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5733    "    return 0;"
5734    "  }"
5735    "  return 4;"
5736    "}"
5737    "test();");
5738  CHECK_EQ(0, value->Int32Value());
5739}
5740
5741
5742THREADED_TEST(EvalAliasedDynamic) {
5743  v8::HandleScope scope;
5744  LocalContext current;
5745
5746  // Tests where aliased eval can only be resolved dynamically.
5747  Local<Script> script =
5748      Script::Compile(v8_str("function f(x) { "
5749                             "  var foo = 2;"
5750                             "  with (x) { return eval('foo'); }"
5751                             "}"
5752                             "foo = 0;"
5753                             "result1 = f(new Object());"
5754                             "result2 = f(this);"
5755                             "var x = new Object();"
5756                             "x.eval = function(x) { return 1; };"
5757                             "result3 = f(x);"));
5758  script->Run();
5759  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5760  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5761  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5762
5763  v8::TryCatch try_catch;
5764  script =
5765    Script::Compile(v8_str("function f(x) { "
5766                           "  var bar = 2;"
5767                           "  with (x) { return eval('bar'); }"
5768                           "}"
5769                           "f(this)"));
5770  script->Run();
5771  CHECK(try_catch.HasCaught());
5772  try_catch.Reset();
5773}
5774
5775
5776THREADED_TEST(CrossEval) {
5777  v8::HandleScope scope;
5778  LocalContext other;
5779  LocalContext current;
5780
5781  Local<String> token = v8_str("<security token>");
5782  other->SetSecurityToken(token);
5783  current->SetSecurityToken(token);
5784
5785  // Setup reference from current to other.
5786  current->Global()->Set(v8_str("other"), other->Global());
5787
5788  // Check that new variables are introduced in other context.
5789  Local<Script> script =
5790      Script::Compile(v8_str("other.eval('var foo = 1234')"));
5791  script->Run();
5792  Local<Value> foo = other->Global()->Get(v8_str("foo"));
5793  CHECK_EQ(1234, foo->Int32Value());
5794  CHECK(!current->Global()->Has(v8_str("foo")));
5795
5796  // Check that writing to non-existing properties introduces them in
5797  // the other context.
5798  script =
5799      Script::Compile(v8_str("other.eval('na = 1234')"));
5800  script->Run();
5801  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5802  CHECK(!current->Global()->Has(v8_str("na")));
5803
5804  // Check that global variables in current context are not visible in other
5805  // context.
5806  v8::TryCatch try_catch;
5807  script =
5808      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5809  Local<Value> result = script->Run();
5810  CHECK(try_catch.HasCaught());
5811  try_catch.Reset();
5812
5813  // Check that local variables in current context are not visible in other
5814  // context.
5815  script =
5816      Script::Compile(v8_str("(function() { "
5817                             "  var baz = 87;"
5818                             "  return other.eval('baz');"
5819                             "})();"));
5820  result = script->Run();
5821  CHECK(try_catch.HasCaught());
5822  try_catch.Reset();
5823
5824  // Check that global variables in the other environment are visible
5825  // when evaluting code.
5826  other->Global()->Set(v8_str("bis"), v8_num(1234));
5827  script = Script::Compile(v8_str("other.eval('bis')"));
5828  CHECK_EQ(1234, script->Run()->Int32Value());
5829  CHECK(!try_catch.HasCaught());
5830
5831  // Check that the 'this' pointer points to the global object evaluating
5832  // code.
5833  other->Global()->Set(v8_str("t"), other->Global());
5834  script = Script::Compile(v8_str("other.eval('this == t')"));
5835  result = script->Run();
5836  CHECK(result->IsTrue());
5837  CHECK(!try_catch.HasCaught());
5838
5839  // Check that variables introduced in with-statement are not visible in
5840  // other context.
5841  script =
5842      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5843  result = script->Run();
5844  CHECK(try_catch.HasCaught());
5845  try_catch.Reset();
5846
5847  // Check that you cannot use 'eval.call' with another object than the
5848  // current global object.
5849  script =
5850      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5851  result = script->Run();
5852  CHECK(try_catch.HasCaught());
5853}
5854
5855
5856// Test that calling eval in a context which has been detached from
5857// its global throws an exception.  This behavior is consistent with
5858// other JavaScript implementations.
5859THREADED_TEST(EvalInDetachedGlobal) {
5860  v8::HandleScope scope;
5861
5862  v8::Persistent<Context> context0 = Context::New();
5863  v8::Persistent<Context> context1 = Context::New();
5864
5865  // Setup function in context0 that uses eval from context0.
5866  context0->Enter();
5867  v8::Handle<v8::Value> fun =
5868      CompileRun("var x = 42;"
5869                 "(function() {"
5870                 "  var e = eval;"
5871                 "  return function(s) { return e(s); }"
5872                 "})()");
5873  context0->Exit();
5874
5875  // Put the function into context1 and call it before and after
5876  // detaching the global.  Before detaching, the call succeeds and
5877  // after detaching and exception is thrown.
5878  context1->Enter();
5879  context1->Global()->Set(v8_str("fun"), fun);
5880  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5881  CHECK_EQ(42, x_value->Int32Value());
5882  context0->DetachGlobal();
5883  v8::TryCatch catcher;
5884  x_value = CompileRun("fun('x')");
5885  CHECK(x_value.IsEmpty());
5886  CHECK(catcher.HasCaught());
5887  context1->Exit();
5888
5889  context1.Dispose();
5890  context0.Dispose();
5891}
5892
5893
5894THREADED_TEST(CrossLazyLoad) {
5895  v8::HandleScope scope;
5896  LocalContext other;
5897  LocalContext current;
5898
5899  Local<String> token = v8_str("<security token>");
5900  other->SetSecurityToken(token);
5901  current->SetSecurityToken(token);
5902
5903  // Setup reference from current to other.
5904  current->Global()->Set(v8_str("other"), other->Global());
5905
5906  // Trigger lazy loading in other context.
5907  Local<Script> script =
5908      Script::Compile(v8_str("other.eval('new Date(42)')"));
5909  Local<Value> value = script->Run();
5910  CHECK_EQ(42.0, value->NumberValue());
5911}
5912
5913
5914static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
5915  ApiTestFuzzer::Fuzz();
5916  if (args.IsConstructCall()) {
5917    if (args[0]->IsInt32()) {
5918       return v8_num(-args[0]->Int32Value());
5919    }
5920  }
5921
5922  return args[0];
5923}
5924
5925
5926// Test that a call handler can be set for objects which will allow
5927// non-function objects created through the API to be called as
5928// functions.
5929THREADED_TEST(CallAsFunction) {
5930  v8::HandleScope scope;
5931  LocalContext context;
5932
5933  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5934  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5935  instance_template->SetCallAsFunctionHandler(call_as_function);
5936  Local<v8::Object> instance = t->GetFunction()->NewInstance();
5937  context->Global()->Set(v8_str("obj"), instance);
5938  v8::TryCatch try_catch;
5939  Local<Value> value;
5940  CHECK(!try_catch.HasCaught());
5941
5942  value = CompileRun("obj(42)");
5943  CHECK(!try_catch.HasCaught());
5944  CHECK_EQ(42, value->Int32Value());
5945
5946  value = CompileRun("(function(o){return o(49)})(obj)");
5947  CHECK(!try_catch.HasCaught());
5948  CHECK_EQ(49, value->Int32Value());
5949
5950  // test special case of call as function
5951  value = CompileRun("[obj]['0'](45)");
5952  CHECK(!try_catch.HasCaught());
5953  CHECK_EQ(45, value->Int32Value());
5954
5955  value = CompileRun("obj.call = Function.prototype.call;"
5956                     "obj.call(null, 87)");
5957  CHECK(!try_catch.HasCaught());
5958  CHECK_EQ(87, value->Int32Value());
5959
5960  // Regression tests for bug #1116356: Calling call through call/apply
5961  // must work for non-function receivers.
5962  const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5963  value = CompileRun(apply_99);
5964  CHECK(!try_catch.HasCaught());
5965  CHECK_EQ(99, value->Int32Value());
5966
5967  const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5968  value = CompileRun(call_17);
5969  CHECK(!try_catch.HasCaught());
5970  CHECK_EQ(17, value->Int32Value());
5971
5972  // Check that the call-as-function handler can be called through
5973  // new.
5974  value = CompileRun("new obj(43)");
5975  CHECK(!try_catch.HasCaught());
5976  CHECK_EQ(-43, value->Int32Value());
5977}
5978
5979
5980static int CountHandles() {
5981  return v8::HandleScope::NumberOfHandles();
5982}
5983
5984
5985static int Recurse(int depth, int iterations) {
5986  v8::HandleScope scope;
5987  if (depth == 0) return CountHandles();
5988  for (int i = 0; i < iterations; i++) {
5989    Local<v8::Number> n = v8::Integer::New(42);
5990  }
5991  return Recurse(depth - 1, iterations);
5992}
5993
5994
5995THREADED_TEST(HandleIteration) {
5996  static const int kIterations = 500;
5997  static const int kNesting = 200;
5998  CHECK_EQ(0, CountHandles());
5999  {
6000    v8::HandleScope scope1;
6001    CHECK_EQ(0, CountHandles());
6002    for (int i = 0; i < kIterations; i++) {
6003      Local<v8::Number> n = v8::Integer::New(42);
6004      CHECK_EQ(i + 1, CountHandles());
6005    }
6006
6007    CHECK_EQ(kIterations, CountHandles());
6008    {
6009      v8::HandleScope scope2;
6010      for (int j = 0; j < kIterations; j++) {
6011        Local<v8::Number> n = v8::Integer::New(42);
6012        CHECK_EQ(j + 1 + kIterations, CountHandles());
6013      }
6014    }
6015    CHECK_EQ(kIterations, CountHandles());
6016  }
6017  CHECK_EQ(0, CountHandles());
6018  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6019}
6020
6021
6022static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6023    Local<String> name,
6024    const AccessorInfo& info) {
6025  ApiTestFuzzer::Fuzz();
6026  return v8::Handle<Value>();
6027}
6028
6029
6030THREADED_TEST(InterceptorHasOwnProperty) {
6031  v8::HandleScope scope;
6032  LocalContext context;
6033  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6034  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6035  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6036  Local<Function> function = fun_templ->GetFunction();
6037  context->Global()->Set(v8_str("constructor"), function);
6038  v8::Handle<Value> value = CompileRun(
6039      "var o = new constructor();"
6040      "o.hasOwnProperty('ostehaps');");
6041  CHECK_EQ(false, value->BooleanValue());
6042  value = CompileRun(
6043      "o.ostehaps = 42;"
6044      "o.hasOwnProperty('ostehaps');");
6045  CHECK_EQ(true, value->BooleanValue());
6046  value = CompileRun(
6047      "var p = new constructor();"
6048      "p.hasOwnProperty('ostehaps');");
6049  CHECK_EQ(false, value->BooleanValue());
6050}
6051
6052
6053static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6054    Local<String> name,
6055    const AccessorInfo& info) {
6056  ApiTestFuzzer::Fuzz();
6057  i::Heap::CollectAllGarbage(false);
6058  return v8::Handle<Value>();
6059}
6060
6061
6062THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6063  v8::HandleScope scope;
6064  LocalContext context;
6065  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6066  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6067  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6068  Local<Function> function = fun_templ->GetFunction();
6069  context->Global()->Set(v8_str("constructor"), function);
6070  // Let's first make some stuff so we can be sure to get a good GC.
6071  CompileRun(
6072      "function makestr(size) {"
6073      "  switch (size) {"
6074      "    case 1: return 'f';"
6075      "    case 2: return 'fo';"
6076      "    case 3: return 'foo';"
6077      "  }"
6078      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
6079      "}"
6080      "var x = makestr(12345);"
6081      "x = makestr(31415);"
6082      "x = makestr(23456);");
6083  v8::Handle<Value> value = CompileRun(
6084      "var o = new constructor();"
6085      "o.__proto__ = new String(x);"
6086      "o.hasOwnProperty('ostehaps');");
6087  CHECK_EQ(false, value->BooleanValue());
6088}
6089
6090
6091typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6092                                                 const AccessorInfo& info);
6093
6094
6095static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6096                                   const char* source,
6097                                   int expected) {
6098  v8::HandleScope scope;
6099  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6100  templ->SetNamedPropertyHandler(getter);
6101  LocalContext context;
6102  context->Global()->Set(v8_str("o"), templ->NewInstance());
6103  v8::Handle<Value> value = CompileRun(source);
6104  CHECK_EQ(expected, value->Int32Value());
6105}
6106
6107
6108static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6109                                                 const AccessorInfo& info) {
6110  ApiTestFuzzer::Fuzz();
6111  CHECK(v8_str("x")->Equals(name));
6112  return v8::Integer::New(42);
6113}
6114
6115
6116// This test should hit the load IC for the interceptor case.
6117THREADED_TEST(InterceptorLoadIC) {
6118  CheckInterceptorLoadIC(InterceptorLoadICGetter,
6119    "var result = 0;"
6120    "for (var i = 0; i < 1000; i++) {"
6121    "  result = o.x;"
6122    "}",
6123    42);
6124}
6125
6126
6127// Below go several tests which verify that JITing for various
6128// configurations of interceptor and explicit fields works fine
6129// (those cases are special cased to get better performance).
6130
6131static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6132                                                 const AccessorInfo& info) {
6133  ApiTestFuzzer::Fuzz();
6134  return v8_str("x")->Equals(name)
6135      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6136}
6137
6138
6139THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6140  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6141    "var result = 0;"
6142    "o.y = 239;"
6143    "for (var i = 0; i < 1000; i++) {"
6144    "  result = o.y;"
6145    "}",
6146    239);
6147}
6148
6149
6150THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6151  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6152    "var result = 0;"
6153    "o.__proto__ = { 'y': 239 };"
6154    "for (var i = 0; i < 1000; i++) {"
6155    "  result = o.y + o.x;"
6156    "}",
6157    239 + 42);
6158}
6159
6160
6161THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6162  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6163    "var result = 0;"
6164    "o.__proto__.y = 239;"
6165    "for (var i = 0; i < 1000; i++) {"
6166    "  result = o.y + o.x;"
6167    "}",
6168    239 + 42);
6169}
6170
6171
6172THREADED_TEST(InterceptorLoadICUndefined) {
6173  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6174    "var result = 0;"
6175    "for (var i = 0; i < 1000; i++) {"
6176    "  result = (o.y == undefined) ? 239 : 42;"
6177    "}",
6178    239);
6179}
6180
6181
6182THREADED_TEST(InterceptorLoadICWithOverride) {
6183  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6184    "fst = new Object();  fst.__proto__ = o;"
6185    "snd = new Object();  snd.__proto__ = fst;"
6186    "var result1 = 0;"
6187    "for (var i = 0; i < 1000;  i++) {"
6188    "  result1 = snd.x;"
6189    "}"
6190    "fst.x = 239;"
6191    "var result = 0;"
6192    "for (var i = 0; i < 1000; i++) {"
6193    "  result = snd.x;"
6194    "}"
6195    "result + result1",
6196    239 + 42);
6197}
6198
6199
6200// Test the case when we stored field into
6201// a stub, but interceptor produced value on its own.
6202THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6203  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6204    "proto = new Object();"
6205    "o.__proto__ = proto;"
6206    "proto.x = 239;"
6207    "for (var i = 0; i < 1000; i++) {"
6208    "  o.x;"
6209    // Now it should be ICed and keep a reference to x defined on proto
6210    "}"
6211    "var result = 0;"
6212    "for (var i = 0; i < 1000; i++) {"
6213    "  result += o.x;"
6214    "}"
6215    "result;",
6216    42 * 1000);
6217}
6218
6219
6220// Test the case when we stored field into
6221// a stub, but it got invalidated later on.
6222THREADED_TEST(InterceptorLoadICInvalidatedField) {
6223  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6224    "proto1 = new Object();"
6225    "proto2 = new Object();"
6226    "o.__proto__ = proto1;"
6227    "proto1.__proto__ = proto2;"
6228    "proto2.y = 239;"
6229    "for (var i = 0; i < 1000; i++) {"
6230    "  o.y;"
6231    // Now it should be ICed and keep a reference to y defined on proto2
6232    "}"
6233    "proto1.y = 42;"
6234    "var result = 0;"
6235    "for (var i = 0; i < 1000; i++) {"
6236    "  result += o.y;"
6237    "}"
6238    "result;",
6239    42 * 1000);
6240}
6241
6242
6243static int interceptor_load_not_handled_calls = 0;
6244static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6245                                                   const AccessorInfo& info) {
6246  ++interceptor_load_not_handled_calls;
6247  return v8::Handle<v8::Value>();
6248}
6249
6250
6251// Test how post-interceptor lookups are done in the non-cacheable
6252// case: the interceptor should not be invoked during this lookup.
6253THREADED_TEST(InterceptorLoadICPostInterceptor) {
6254  interceptor_load_not_handled_calls = 0;
6255  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6256    "receiver = new Object();"
6257    "receiver.__proto__ = o;"
6258    "proto = new Object();"
6259    "/* Make proto a slow-case object. */"
6260    "for (var i = 0; i < 1000; i++) {"
6261    "  proto[\"xxxxxxxx\" + i] = [];"
6262    "}"
6263    "proto.x = 17;"
6264    "o.__proto__ = proto;"
6265    "var result = 0;"
6266    "for (var i = 0; i < 1000; i++) {"
6267    "  result += receiver.x;"
6268    "}"
6269    "result;",
6270    17 * 1000);
6271  CHECK_EQ(1000, interceptor_load_not_handled_calls);
6272}
6273
6274
6275// Test the case when we stored field into
6276// a stub, but it got invalidated later on due to override on
6277// global object which is between interceptor and fields' holders.
6278THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6279  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6280    "o.__proto__ = this;"  // set a global to be a proto of o.
6281    "this.__proto__.y = 239;"
6282    "for (var i = 0; i < 10; i++) {"
6283    "  if (o.y != 239) throw 'oops: ' + o.y;"
6284    // Now it should be ICed and keep a reference to y defined on field_holder.
6285    "}"
6286    "this.y = 42;"  // Assign on a global.
6287    "var result = 0;"
6288    "for (var i = 0; i < 10; i++) {"
6289    "  result += o.y;"
6290    "}"
6291    "result;",
6292    42 * 10);
6293}
6294
6295
6296static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6297  ApiTestFuzzer::Fuzz();
6298  return v8_num(239);
6299}
6300
6301
6302static void SetOnThis(Local<String> name,
6303                      Local<Value> value,
6304                      const AccessorInfo& info) {
6305  info.This()->ForceSet(name, value);
6306}
6307
6308
6309THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6310  v8::HandleScope scope;
6311  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6312  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6313  templ->SetAccessor(v8_str("y"), Return239);
6314  LocalContext context;
6315  context->Global()->Set(v8_str("o"), templ->NewInstance());
6316
6317  // Check the case when receiver and interceptor's holder
6318  // are the same objects.
6319  v8::Handle<Value> value = CompileRun(
6320      "var result = 0;"
6321      "for (var i = 0; i < 7; i++) {"
6322      "  result = o.y;"
6323      "}");
6324  CHECK_EQ(239, value->Int32Value());
6325
6326  // Check the case when interceptor's holder is in proto chain
6327  // of receiver.
6328  value = CompileRun(
6329      "r = { __proto__: o };"
6330      "var result = 0;"
6331      "for (var i = 0; i < 7; i++) {"
6332      "  result = r.y;"
6333      "}");
6334  CHECK_EQ(239, value->Int32Value());
6335}
6336
6337
6338THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6339  v8::HandleScope scope;
6340  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6341  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6342  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6343  templ_p->SetAccessor(v8_str("y"), Return239);
6344
6345  LocalContext context;
6346  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6347  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6348
6349  // Check the case when receiver and interceptor's holder
6350  // are the same objects.
6351  v8::Handle<Value> value = CompileRun(
6352      "o.__proto__ = p;"
6353      "var result = 0;"
6354      "for (var i = 0; i < 7; i++) {"
6355      "  result = o.x + o.y;"
6356      "}");
6357  CHECK_EQ(239 + 42, value->Int32Value());
6358
6359  // Check the case when interceptor's holder is in proto chain
6360  // of receiver.
6361  value = CompileRun(
6362      "r = { __proto__: o };"
6363      "var result = 0;"
6364      "for (var i = 0; i < 7; i++) {"
6365      "  result = r.x + r.y;"
6366      "}");
6367  CHECK_EQ(239 + 42, value->Int32Value());
6368}
6369
6370
6371THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6372  v8::HandleScope scope;
6373  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6374  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6375  templ->SetAccessor(v8_str("y"), Return239);
6376
6377  LocalContext context;
6378  context->Global()->Set(v8_str("o"), templ->NewInstance());
6379
6380  v8::Handle<Value> value = CompileRun(
6381    "fst = new Object();  fst.__proto__ = o;"
6382    "snd = new Object();  snd.__proto__ = fst;"
6383    "var result1 = 0;"
6384    "for (var i = 0; i < 7;  i++) {"
6385    "  result1 = snd.x;"
6386    "}"
6387    "fst.x = 239;"
6388    "var result = 0;"
6389    "for (var i = 0; i < 7; i++) {"
6390    "  result = snd.x;"
6391    "}"
6392    "result + result1");
6393  CHECK_EQ(239 + 42, value->Int32Value());
6394}
6395
6396
6397// Test the case when we stored callback into
6398// a stub, but interceptor produced value on its own.
6399THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6400  v8::HandleScope scope;
6401  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6402  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6403  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6404  templ_p->SetAccessor(v8_str("y"), Return239);
6405
6406  LocalContext context;
6407  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6408  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6409
6410  v8::Handle<Value> value = CompileRun(
6411    "o.__proto__ = p;"
6412    "for (var i = 0; i < 7; i++) {"
6413    "  o.x;"
6414    // Now it should be ICed and keep a reference to x defined on p
6415    "}"
6416    "var result = 0;"
6417    "for (var i = 0; i < 7; i++) {"
6418    "  result += o.x;"
6419    "}"
6420    "result");
6421  CHECK_EQ(42 * 7, value->Int32Value());
6422}
6423
6424
6425// Test the case when we stored callback into
6426// a stub, but it got invalidated later on.
6427THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6428  v8::HandleScope scope;
6429  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6430  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6431  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6432  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6433
6434  LocalContext context;
6435  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6436  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6437
6438  v8::Handle<Value> value = CompileRun(
6439    "inbetween = new Object();"
6440    "o.__proto__ = inbetween;"
6441    "inbetween.__proto__ = p;"
6442    "for (var i = 0; i < 10; i++) {"
6443    "  o.y;"
6444    // Now it should be ICed and keep a reference to y defined on p
6445    "}"
6446    "inbetween.y = 42;"
6447    "var result = 0;"
6448    "for (var i = 0; i < 10; i++) {"
6449    "  result += o.y;"
6450    "}"
6451    "result");
6452  CHECK_EQ(42 * 10, value->Int32Value());
6453}
6454
6455
6456// Test the case when we stored callback into
6457// a stub, but it got invalidated later on due to override on
6458// global object which is between interceptor and callbacks' holders.
6459THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6460  v8::HandleScope scope;
6461  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6462  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6463  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6464  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6465
6466  LocalContext context;
6467  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6468  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6469
6470  v8::Handle<Value> value = CompileRun(
6471    "o.__proto__ = this;"
6472    "this.__proto__ = p;"
6473    "for (var i = 0; i < 10; i++) {"
6474    "  if (o.y != 239) throw 'oops: ' + o.y;"
6475    // Now it should be ICed and keep a reference to y defined on p
6476    "}"
6477    "this.y = 42;"
6478    "var result = 0;"
6479    "for (var i = 0; i < 10; i++) {"
6480    "  result += o.y;"
6481    "}"
6482    "result");
6483  CHECK_EQ(42 * 10, value->Int32Value());
6484}
6485
6486
6487static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6488                                                  const AccessorInfo& info) {
6489  ApiTestFuzzer::Fuzz();
6490  CHECK(v8_str("x")->Equals(name));
6491  return v8::Integer::New(0);
6492}
6493
6494
6495THREADED_TEST(InterceptorReturningZero) {
6496  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6497     "o.x == undefined ? 1 : 0",
6498     0);
6499}
6500
6501
6502static v8::Handle<Value> InterceptorStoreICSetter(
6503    Local<String> key, Local<Value> value, const AccessorInfo&) {
6504  CHECK(v8_str("x")->Equals(key));
6505  CHECK_EQ(42, value->Int32Value());
6506  return value;
6507}
6508
6509
6510// This test should hit the store IC for the interceptor case.
6511THREADED_TEST(InterceptorStoreIC) {
6512  v8::HandleScope scope;
6513  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6514  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6515                                 InterceptorStoreICSetter);
6516  LocalContext context;
6517  context->Global()->Set(v8_str("o"), templ->NewInstance());
6518  v8::Handle<Value> value = CompileRun(
6519    "for (var i = 0; i < 1000; i++) {"
6520    "  o.x = 42;"
6521    "}");
6522}
6523
6524
6525THREADED_TEST(InterceptorStoreICWithNoSetter) {
6526  v8::HandleScope scope;
6527  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6528  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6529  LocalContext context;
6530  context->Global()->Set(v8_str("o"), templ->NewInstance());
6531  v8::Handle<Value> value = CompileRun(
6532    "for (var i = 0; i < 1000; i++) {"
6533    "  o.y = 239;"
6534    "}"
6535    "42 + o.y");
6536  CHECK_EQ(239 + 42, value->Int32Value());
6537}
6538
6539
6540
6541
6542v8::Handle<Value> call_ic_function;
6543v8::Handle<Value> call_ic_function2;
6544v8::Handle<Value> call_ic_function3;
6545
6546static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6547                                                 const AccessorInfo& info) {
6548  ApiTestFuzzer::Fuzz();
6549  CHECK(v8_str("x")->Equals(name));
6550  return call_ic_function;
6551}
6552
6553
6554// This test should hit the call IC for the interceptor case.
6555THREADED_TEST(InterceptorCallIC) {
6556  v8::HandleScope scope;
6557  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6558  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6559  LocalContext context;
6560  context->Global()->Set(v8_str("o"), templ->NewInstance());
6561  call_ic_function =
6562      v8_compile("function f(x) { return x + 1; }; f")->Run();
6563  v8::Handle<Value> value = CompileRun(
6564    "var result = 0;"
6565    "for (var i = 0; i < 1000; i++) {"
6566    "  result = o.x(41);"
6567    "}");
6568  CHECK_EQ(42, value->Int32Value());
6569}
6570
6571
6572// This test checks that if interceptor doesn't provide
6573// a value, we can fetch regular value.
6574THREADED_TEST(InterceptorCallICSeesOthers) {
6575  v8::HandleScope scope;
6576  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6577  templ->SetNamedPropertyHandler(NoBlockGetterX);
6578  LocalContext context;
6579  context->Global()->Set(v8_str("o"), templ->NewInstance());
6580  v8::Handle<Value> value = CompileRun(
6581    "o.x = function f(x) { return x + 1; };"
6582    "var result = 0;"
6583    "for (var i = 0; i < 7; i++) {"
6584    "  result = o.x(41);"
6585    "}");
6586  CHECK_EQ(42, value->Int32Value());
6587}
6588
6589
6590static v8::Handle<Value> call_ic_function4;
6591static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6592                                                  const AccessorInfo& info) {
6593  ApiTestFuzzer::Fuzz();
6594  CHECK(v8_str("x")->Equals(name));
6595  return call_ic_function4;
6596}
6597
6598
6599// This test checks that if interceptor provides a function,
6600// even if we cached shadowed variant, interceptor's function
6601// is invoked
6602THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6603  v8::HandleScope scope;
6604  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6605  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6606  LocalContext context;
6607  context->Global()->Set(v8_str("o"), templ->NewInstance());
6608  call_ic_function4 =
6609      v8_compile("function f(x) { return x - 1; }; f")->Run();
6610  v8::Handle<Value> value = CompileRun(
6611    "o.__proto__.x = function(x) { return x + 1; };"
6612    "var result = 0;"
6613    "for (var i = 0; i < 1000; i++) {"
6614    "  result = o.x(42);"
6615    "}");
6616  CHECK_EQ(41, value->Int32Value());
6617}
6618
6619
6620// Test the case when we stored cacheable lookup into
6621// a stub, but it got invalidated later on
6622THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6623  v8::HandleScope scope;
6624  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6625  templ->SetNamedPropertyHandler(NoBlockGetterX);
6626  LocalContext context;
6627  context->Global()->Set(v8_str("o"), templ->NewInstance());
6628  v8::Handle<Value> value = CompileRun(
6629    "proto1 = new Object();"
6630    "proto2 = new Object();"
6631    "o.__proto__ = proto1;"
6632    "proto1.__proto__ = proto2;"
6633    "proto2.y = function(x) { return x + 1; };"
6634    // Invoke it many times to compile a stub
6635    "for (var i = 0; i < 7; i++) {"
6636    "  o.y(42);"
6637    "}"
6638    "proto1.y = function(x) { return x - 1; };"
6639    "var result = 0;"
6640    "for (var i = 0; i < 7; i++) {"
6641    "  result += o.y(42);"
6642    "}");
6643  CHECK_EQ(41 * 7, value->Int32Value());
6644}
6645
6646
6647static v8::Handle<Value> call_ic_function5;
6648static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6649                                                  const AccessorInfo& info) {
6650  ApiTestFuzzer::Fuzz();
6651  if (v8_str("x")->Equals(name))
6652    return call_ic_function5;
6653  else
6654    return Local<Value>();
6655}
6656
6657
6658// This test checks that if interceptor doesn't provide a function,
6659// cached constant function is used
6660THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6661  v8::HandleScope scope;
6662  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6663  templ->SetNamedPropertyHandler(NoBlockGetterX);
6664  LocalContext context;
6665  context->Global()->Set(v8_str("o"), templ->NewInstance());
6666  v8::Handle<Value> value = CompileRun(
6667    "function inc(x) { return x + 1; };"
6668    "inc(1);"
6669    "o.x = inc;"
6670    "var result = 0;"
6671    "for (var i = 0; i < 1000; i++) {"
6672    "  result = o.x(42);"
6673    "}");
6674  CHECK_EQ(43, value->Int32Value());
6675}
6676
6677
6678// This test checks that if interceptor provides a function,
6679// even if we cached constant function, interceptor's function
6680// is invoked
6681THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6682  v8::HandleScope scope;
6683  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6684  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6685  LocalContext context;
6686  context->Global()->Set(v8_str("o"), templ->NewInstance());
6687  call_ic_function5 =
6688      v8_compile("function f(x) { return x - 1; }; f")->Run();
6689  v8::Handle<Value> value = CompileRun(
6690    "function inc(x) { return x + 1; };"
6691    "inc(1);"
6692    "o.x = inc;"
6693    "var result = 0;"
6694    "for (var i = 0; i < 1000; i++) {"
6695    "  result = o.x(42);"
6696    "}");
6697  CHECK_EQ(41, value->Int32Value());
6698}
6699
6700
6701// Test the case when we stored constant function into
6702// a stub, but it got invalidated later on
6703THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6704  v8::HandleScope scope;
6705  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6706  templ->SetNamedPropertyHandler(NoBlockGetterX);
6707  LocalContext context;
6708  context->Global()->Set(v8_str("o"), templ->NewInstance());
6709  v8::Handle<Value> value = CompileRun(
6710    "function inc(x) { return x + 1; };"
6711    "inc(1);"
6712    "proto1 = new Object();"
6713    "proto2 = new Object();"
6714    "o.__proto__ = proto1;"
6715    "proto1.__proto__ = proto2;"
6716    "proto2.y = inc;"
6717    // Invoke it many times to compile a stub
6718    "for (var i = 0; i < 7; i++) {"
6719    "  o.y(42);"
6720    "}"
6721    "proto1.y = function(x) { return x - 1; };"
6722    "var result = 0;"
6723    "for (var i = 0; i < 7; i++) {"
6724    "  result += o.y(42);"
6725    "}");
6726  CHECK_EQ(41 * 7, value->Int32Value());
6727}
6728
6729
6730// Test the case when we stored constant function into
6731// a stub, but it got invalidated later on due to override on
6732// global object which is between interceptor and constant function' holders.
6733THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6734  v8::HandleScope scope;
6735  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6736  templ->SetNamedPropertyHandler(NoBlockGetterX);
6737  LocalContext context;
6738  context->Global()->Set(v8_str("o"), templ->NewInstance());
6739  v8::Handle<Value> value = CompileRun(
6740    "function inc(x) { return x + 1; };"
6741    "inc(1);"
6742    "o.__proto__ = this;"
6743    "this.__proto__.y = inc;"
6744    // Invoke it many times to compile a stub
6745    "for (var i = 0; i < 7; i++) {"
6746    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6747    "}"
6748    "this.y = function(x) { return x - 1; };"
6749    "var result = 0;"
6750    "for (var i = 0; i < 7; i++) {"
6751    "  result += o.y(42);"
6752    "}");
6753  CHECK_EQ(41 * 7, value->Int32Value());
6754}
6755
6756
6757// Test the case when actual function to call sits on global object.
6758THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6759  v8::HandleScope scope;
6760  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6761  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6762
6763  LocalContext context;
6764  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6765
6766  v8::Handle<Value> value = CompileRun(
6767    "try {"
6768    "  o.__proto__ = this;"
6769    "  for (var i = 0; i < 10; i++) {"
6770    "    var v = o.parseFloat('239');"
6771    "    if (v != 239) throw v;"
6772      // Now it should be ICed and keep a reference to parseFloat.
6773    "  }"
6774    "  var result = 0;"
6775    "  for (var i = 0; i < 10; i++) {"
6776    "    result += o.parseFloat('239');"
6777    "  }"
6778    "  result"
6779    "} catch(e) {"
6780    "  e"
6781    "};");
6782  CHECK_EQ(239 * 10, value->Int32Value());
6783}
6784
6785static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6786                                                  const AccessorInfo& info) {
6787  ApiTestFuzzer::Fuzz();
6788  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6789  ++(*call_count);
6790  if ((*call_count) % 20 == 0) {
6791    v8::internal::Heap::CollectAllGarbage(true);
6792  }
6793  return v8::Handle<Value>();
6794}
6795
6796static v8::Handle<Value> FastApiCallback_TrivialSignature(
6797    const v8::Arguments& args) {
6798  ApiTestFuzzer::Fuzz();
6799  CHECK_EQ(args.This(), args.Holder());
6800  CHECK(args.Data()->Equals(v8_str("method_data")));
6801  return v8::Integer::New(args[0]->Int32Value() + 1);
6802}
6803
6804static v8::Handle<Value> FastApiCallback_SimpleSignature(
6805    const v8::Arguments& args) {
6806  ApiTestFuzzer::Fuzz();
6807  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6808  CHECK(args.Data()->Equals(v8_str("method_data")));
6809  // Note, we're using HasRealNamedProperty instead of Has to avoid
6810  // invoking the interceptor again.
6811  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6812  return v8::Integer::New(args[0]->Int32Value() + 1);
6813}
6814
6815// Helper to maximize the odds of object moving.
6816static void GenerateSomeGarbage() {
6817  CompileRun(
6818      "var garbage;"
6819      "for (var i = 0; i < 1000; i++) {"
6820      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6821      "}"
6822      "garbage = undefined;");
6823}
6824
6825THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
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_TrivialSignature,
6831                                v8_str("method_data"),
6832                                v8::Handle<v8::Signature>());
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      "var result = 0;"
6845      "for (var i = 0; i < 100; i++) {"
6846      "  result = o.method(41);"
6847      "}");
6848  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6849  CHECK_EQ(100, interceptor_call_count);
6850}
6851
6852THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6853  int interceptor_call_count = 0;
6854  v8::HandleScope scope;
6855  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6856  v8::Handle<v8::FunctionTemplate> method_templ =
6857      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6858                                v8_str("method_data"),
6859                                v8::Signature::New(fun_templ));
6860  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6861  proto_templ->Set(v8_str("method"), method_templ);
6862  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6863  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6864                                 NULL, NULL, NULL, NULL,
6865                                 v8::External::Wrap(&interceptor_call_count));
6866  LocalContext context;
6867  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6868  GenerateSomeGarbage();
6869  context->Global()->Set(v8_str("o"), fun->NewInstance());
6870  v8::Handle<Value> value = CompileRun(
6871      "o.foo = 17;"
6872      "var receiver = {};"
6873      "receiver.__proto__ = o;"
6874      "var result = 0;"
6875      "for (var i = 0; i < 100; i++) {"
6876      "  result = receiver.method(41);"
6877      "}");
6878  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6879  CHECK_EQ(100, interceptor_call_count);
6880}
6881
6882THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6883  int interceptor_call_count = 0;
6884  v8::HandleScope scope;
6885  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6886  v8::Handle<v8::FunctionTemplate> method_templ =
6887      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6888                                v8_str("method_data"),
6889                                v8::Signature::New(fun_templ));
6890  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6891  proto_templ->Set(v8_str("method"), method_templ);
6892  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6893  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6894                                 NULL, NULL, NULL, NULL,
6895                                 v8::External::Wrap(&interceptor_call_count));
6896  LocalContext context;
6897  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6898  GenerateSomeGarbage();
6899  context->Global()->Set(v8_str("o"), fun->NewInstance());
6900  v8::Handle<Value> value = CompileRun(
6901      "o.foo = 17;"
6902      "var receiver = {};"
6903      "receiver.__proto__ = o;"
6904      "var result = 0;"
6905      "var saved_result = 0;"
6906      "for (var i = 0; i < 100; i++) {"
6907      "  result = receiver.method(41);"
6908      "  if (i == 50) {"
6909      "    saved_result = result;"
6910      "    receiver = {method: function(x) { return x - 1 }};"
6911      "  }"
6912      "}");
6913  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6914  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6915  CHECK_GE(interceptor_call_count, 50);
6916}
6917
6918THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6919  int interceptor_call_count = 0;
6920  v8::HandleScope scope;
6921  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6922  v8::Handle<v8::FunctionTemplate> method_templ =
6923      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6924                                v8_str("method_data"),
6925                                v8::Signature::New(fun_templ));
6926  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6927  proto_templ->Set(v8_str("method"), method_templ);
6928  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6929  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6930                                 NULL, NULL, NULL, NULL,
6931                                 v8::External::Wrap(&interceptor_call_count));
6932  LocalContext context;
6933  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6934  GenerateSomeGarbage();
6935  context->Global()->Set(v8_str("o"), fun->NewInstance());
6936  v8::Handle<Value> value = CompileRun(
6937      "o.foo = 17;"
6938      "var receiver = {};"
6939      "receiver.__proto__ = o;"
6940      "var result = 0;"
6941      "var saved_result = 0;"
6942      "for (var i = 0; i < 100; i++) {"
6943      "  result = receiver.method(41);"
6944      "  if (i == 50) {"
6945      "    saved_result = result;"
6946      "    o.method = function(x) { return x - 1 };"
6947      "  }"
6948      "}");
6949  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6950  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6951  CHECK_GE(interceptor_call_count, 50);
6952}
6953
6954THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
6955  int interceptor_call_count = 0;
6956  v8::HandleScope scope;
6957  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6958  v8::Handle<v8::FunctionTemplate> method_templ =
6959      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6960                                v8_str("method_data"),
6961                                v8::Signature::New(fun_templ));
6962  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6963  proto_templ->Set(v8_str("method"), method_templ);
6964  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6965  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6966                                 NULL, NULL, NULL, NULL,
6967                                 v8::External::Wrap(&interceptor_call_count));
6968  LocalContext context;
6969  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6970  GenerateSomeGarbage();
6971  context->Global()->Set(v8_str("o"), fun->NewInstance());
6972  v8::TryCatch try_catch;
6973  v8::Handle<Value> value = CompileRun(
6974      "o.foo = 17;"
6975      "var receiver = {};"
6976      "receiver.__proto__ = o;"
6977      "var result = 0;"
6978      "var saved_result = 0;"
6979      "for (var i = 0; i < 100; i++) {"
6980      "  result = receiver.method(41);"
6981      "  if (i == 50) {"
6982      "    saved_result = result;"
6983      "    receiver = 333;"
6984      "  }"
6985      "}");
6986  CHECK(try_catch.HasCaught());
6987  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6988           try_catch.Exception()->ToString());
6989  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6990  CHECK_GE(interceptor_call_count, 50);
6991}
6992
6993THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6994  int interceptor_call_count = 0;
6995  v8::HandleScope scope;
6996  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6997  v8::Handle<v8::FunctionTemplate> method_templ =
6998      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6999                                v8_str("method_data"),
7000                                v8::Signature::New(fun_templ));
7001  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7002  proto_templ->Set(v8_str("method"), method_templ);
7003  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7004  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7005                                 NULL, NULL, NULL, NULL,
7006                                 v8::External::Wrap(&interceptor_call_count));
7007  LocalContext context;
7008  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7009  GenerateSomeGarbage();
7010  context->Global()->Set(v8_str("o"), fun->NewInstance());
7011  v8::TryCatch try_catch;
7012  v8::Handle<Value> value = CompileRun(
7013      "o.foo = 17;"
7014      "var receiver = {};"
7015      "receiver.__proto__ = o;"
7016      "var result = 0;"
7017      "var saved_result = 0;"
7018      "for (var i = 0; i < 100; i++) {"
7019      "  result = receiver.method(41);"
7020      "  if (i == 50) {"
7021      "    saved_result = result;"
7022      "    receiver = {method: receiver.method};"
7023      "  }"
7024      "}");
7025  CHECK(try_catch.HasCaught());
7026  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7027           try_catch.Exception()->ToString());
7028  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7029  CHECK_GE(interceptor_call_count, 50);
7030}
7031
7032THREADED_TEST(CallICFastApi_TrivialSignature) {
7033  v8::HandleScope scope;
7034  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7035  v8::Handle<v8::FunctionTemplate> method_templ =
7036      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7037                                v8_str("method_data"),
7038                                v8::Handle<v8::Signature>());
7039  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7040  proto_templ->Set(v8_str("method"), method_templ);
7041  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7042  LocalContext context;
7043  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7044  GenerateSomeGarbage();
7045  context->Global()->Set(v8_str("o"), fun->NewInstance());
7046  v8::Handle<Value> value = CompileRun(
7047      "var result = 0;"
7048      "for (var i = 0; i < 100; i++) {"
7049      "  result = o.method(41);"
7050      "}");
7051
7052  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7053}
7054
7055THREADED_TEST(CallICFastApi_SimpleSignature) {
7056  v8::HandleScope scope;
7057  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7058  v8::Handle<v8::FunctionTemplate> method_templ =
7059      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7060                                v8_str("method_data"),
7061                                v8::Signature::New(fun_templ));
7062  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7063  proto_templ->Set(v8_str("method"), method_templ);
7064  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7065  LocalContext context;
7066  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7067  GenerateSomeGarbage();
7068  context->Global()->Set(v8_str("o"), fun->NewInstance());
7069  v8::Handle<Value> value = CompileRun(
7070      "o.foo = 17;"
7071      "var receiver = {};"
7072      "receiver.__proto__ = o;"
7073      "var result = 0;"
7074      "for (var i = 0; i < 100; i++) {"
7075      "  result = receiver.method(41);"
7076      "}");
7077
7078  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7079}
7080
7081THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
7082  v8::HandleScope scope;
7083  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7084  v8::Handle<v8::FunctionTemplate> method_templ =
7085      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7086                                v8_str("method_data"),
7087                                v8::Signature::New(fun_templ));
7088  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7089  proto_templ->Set(v8_str("method"), method_templ);
7090  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7091  LocalContext context;
7092  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7093  GenerateSomeGarbage();
7094  context->Global()->Set(v8_str("o"), fun->NewInstance());
7095  v8::Handle<Value> value = CompileRun(
7096      "o.foo = 17;"
7097      "var receiver = {};"
7098      "receiver.__proto__ = o;"
7099      "var result = 0;"
7100      "var saved_result = 0;"
7101      "for (var i = 0; i < 100; i++) {"
7102      "  result = receiver.method(41);"
7103      "  if (i == 50) {"
7104      "    saved_result = result;"
7105      "    receiver = {method: function(x) { return x - 1 }};"
7106      "  }"
7107      "}");
7108  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7109  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7110}
7111
7112THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7113  v8::HandleScope scope;
7114  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7115  v8::Handle<v8::FunctionTemplate> method_templ =
7116      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7117                                v8_str("method_data"),
7118                                v8::Signature::New(fun_templ));
7119  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7120  proto_templ->Set(v8_str("method"), method_templ);
7121  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7122  LocalContext context;
7123  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7124  GenerateSomeGarbage();
7125  context->Global()->Set(v8_str("o"), fun->NewInstance());
7126  v8::TryCatch try_catch;
7127  v8::Handle<Value> value = CompileRun(
7128      "o.foo = 17;"
7129      "var receiver = {};"
7130      "receiver.__proto__ = o;"
7131      "var result = 0;"
7132      "var saved_result = 0;"
7133      "for (var i = 0; i < 100; i++) {"
7134      "  result = receiver.method(41);"
7135      "  if (i == 50) {"
7136      "    saved_result = result;"
7137      "    receiver = 333;"
7138      "  }"
7139      "}");
7140  CHECK(try_catch.HasCaught());
7141  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7142           try_catch.Exception()->ToString());
7143  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7144}
7145
7146
7147v8::Handle<Value> keyed_call_ic_function;
7148
7149static v8::Handle<Value> InterceptorKeyedCallICGetter(
7150    Local<String> name, const AccessorInfo& info) {
7151  ApiTestFuzzer::Fuzz();
7152  if (v8_str("x")->Equals(name)) {
7153    return keyed_call_ic_function;
7154  }
7155  return v8::Handle<Value>();
7156}
7157
7158
7159// Test the case when we stored cacheable lookup into
7160// a stub, but the function name changed (to another cacheable function).
7161THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7162  v8::HandleScope scope;
7163  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7164  templ->SetNamedPropertyHandler(NoBlockGetterX);
7165  LocalContext context;
7166  context->Global()->Set(v8_str("o"), templ->NewInstance());
7167  v8::Handle<Value> value = CompileRun(
7168    "proto = new Object();"
7169    "proto.y = function(x) { return x + 1; };"
7170    "proto.z = function(x) { return x - 1; };"
7171    "o.__proto__ = proto;"
7172    "var result = 0;"
7173    "var method = 'y';"
7174    "for (var i = 0; i < 10; i++) {"
7175    "  if (i == 5) { method = 'z'; };"
7176    "  result += o[method](41);"
7177    "}");
7178  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7179}
7180
7181
7182// Test the case when we stored cacheable lookup into
7183// a stub, but the function name changed (and the new function is present
7184// both before and after the interceptor in the prototype chain).
7185THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7186  v8::HandleScope scope;
7187  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7188  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7189  LocalContext context;
7190  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7191  keyed_call_ic_function =
7192      v8_compile("function f(x) { return x - 1; }; f")->Run();
7193  v8::Handle<Value> value = CompileRun(
7194    "o = new Object();"
7195    "proto2 = new Object();"
7196    "o.y = function(x) { return x + 1; };"
7197    "proto2.y = function(x) { return x + 2; };"
7198    "o.__proto__ = proto1;"
7199    "proto1.__proto__ = proto2;"
7200    "var result = 0;"
7201    "var method = 'x';"
7202    "for (var i = 0; i < 10; i++) {"
7203    "  if (i == 5) { method = 'y'; };"
7204    "  result += o[method](41);"
7205    "}");
7206  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7207}
7208
7209
7210// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7211// on the global object.
7212THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7213  v8::HandleScope scope;
7214  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7215  templ->SetNamedPropertyHandler(NoBlockGetterX);
7216  LocalContext context;
7217  context->Global()->Set(v8_str("o"), templ->NewInstance());
7218  v8::Handle<Value> value = CompileRun(
7219    "function inc(x) { return x + 1; };"
7220    "inc(1);"
7221    "function dec(x) { return x - 1; };"
7222    "dec(1);"
7223    "o.__proto__ = this;"
7224    "this.__proto__.x = inc;"
7225    "this.__proto__.y = dec;"
7226    "var result = 0;"
7227    "var method = 'x';"
7228    "for (var i = 0; i < 10; i++) {"
7229    "  if (i == 5) { method = 'y'; };"
7230    "  result += o[method](41);"
7231    "}");
7232  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7233}
7234
7235
7236// Test the case when actual function to call sits on global object.
7237THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7238  v8::HandleScope scope;
7239  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7240  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7241  LocalContext context;
7242  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7243
7244  v8::Handle<Value> value = CompileRun(
7245    "function len(x) { return x.length; };"
7246    "o.__proto__ = this;"
7247    "var m = 'parseFloat';"
7248    "var result = 0;"
7249    "for (var i = 0; i < 10; i++) {"
7250    "  if (i == 5) {"
7251    "    m = 'len';"
7252    "    saved_result = result;"
7253    "  };"
7254    "  result = o[m]('239');"
7255    "}");
7256  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7257  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7258}
7259
7260// Test the map transition before the interceptor.
7261THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7262  v8::HandleScope scope;
7263  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7264  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7265  LocalContext context;
7266  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7267
7268  v8::Handle<Value> value = CompileRun(
7269    "var o = new Object();"
7270    "o.__proto__ = proto;"
7271    "o.method = function(x) { return x + 1; };"
7272    "var m = 'method';"
7273    "var result = 0;"
7274    "for (var i = 0; i < 10; i++) {"
7275    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
7276    "  result += o[m](41);"
7277    "}");
7278  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7279}
7280
7281
7282// Test the map transition after the interceptor.
7283THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7284  v8::HandleScope scope;
7285  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7286  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7287  LocalContext context;
7288  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7289
7290  v8::Handle<Value> value = CompileRun(
7291    "var proto = new Object();"
7292    "o.__proto__ = proto;"
7293    "proto.method = function(x) { return x + 1; };"
7294    "var m = 'method';"
7295    "var result = 0;"
7296    "for (var i = 0; i < 10; i++) {"
7297    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7298    "  result += o[m](41);"
7299    "}");
7300  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7301}
7302
7303
7304static int interceptor_call_count = 0;
7305
7306static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7307                                                     const AccessorInfo& info) {
7308  ApiTestFuzzer::Fuzz();
7309  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7310    return call_ic_function2;
7311  }
7312  return v8::Handle<Value>();
7313}
7314
7315
7316// This test should hit load and call ICs for the interceptor case.
7317// Once in a while, the interceptor will reply that a property was not
7318// found in which case we should get a reference error.
7319THREADED_TEST(InterceptorICReferenceErrors) {
7320  v8::HandleScope scope;
7321  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7322  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7323  LocalContext context(0, templ, v8::Handle<Value>());
7324  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7325  v8::Handle<Value> value = CompileRun(
7326    "function f() {"
7327    "  for (var i = 0; i < 1000; i++) {"
7328    "    try { x; } catch(e) { return true; }"
7329    "  }"
7330    "  return false;"
7331    "};"
7332    "f();");
7333  CHECK_EQ(true, value->BooleanValue());
7334  interceptor_call_count = 0;
7335  value = CompileRun(
7336    "function g() {"
7337    "  for (var i = 0; i < 1000; i++) {"
7338    "    try { x(42); } catch(e) { return true; }"
7339    "  }"
7340    "  return false;"
7341    "};"
7342    "g();");
7343  CHECK_EQ(true, value->BooleanValue());
7344}
7345
7346
7347static int interceptor_ic_exception_get_count = 0;
7348
7349static v8::Handle<Value> InterceptorICExceptionGetter(
7350    Local<String> name,
7351    const AccessorInfo& info) {
7352  ApiTestFuzzer::Fuzz();
7353  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7354    return call_ic_function3;
7355  }
7356  if (interceptor_ic_exception_get_count == 20) {
7357    return v8::ThrowException(v8_num(42));
7358  }
7359  // Do not handle get for properties other than x.
7360  return v8::Handle<Value>();
7361}
7362
7363// Test interceptor load/call IC where the interceptor throws an
7364// exception once in a while.
7365THREADED_TEST(InterceptorICGetterExceptions) {
7366  interceptor_ic_exception_get_count = 0;
7367  v8::HandleScope scope;
7368  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7369  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7370  LocalContext context(0, templ, v8::Handle<Value>());
7371  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7372  v8::Handle<Value> value = CompileRun(
7373    "function f() {"
7374    "  for (var i = 0; i < 100; i++) {"
7375    "    try { x; } catch(e) { return true; }"
7376    "  }"
7377    "  return false;"
7378    "};"
7379    "f();");
7380  CHECK_EQ(true, value->BooleanValue());
7381  interceptor_ic_exception_get_count = 0;
7382  value = CompileRun(
7383    "function f() {"
7384    "  for (var i = 0; i < 100; i++) {"
7385    "    try { x(42); } catch(e) { return true; }"
7386    "  }"
7387    "  return false;"
7388    "};"
7389    "f();");
7390  CHECK_EQ(true, value->BooleanValue());
7391}
7392
7393
7394static int interceptor_ic_exception_set_count = 0;
7395
7396static v8::Handle<Value> InterceptorICExceptionSetter(
7397      Local<String> key, Local<Value> value, const AccessorInfo&) {
7398  ApiTestFuzzer::Fuzz();
7399  if (++interceptor_ic_exception_set_count > 20) {
7400    return v8::ThrowException(v8_num(42));
7401  }
7402  // Do not actually handle setting.
7403  return v8::Handle<Value>();
7404}
7405
7406// Test interceptor store IC where the interceptor throws an exception
7407// once in a while.
7408THREADED_TEST(InterceptorICSetterExceptions) {
7409  interceptor_ic_exception_set_count = 0;
7410  v8::HandleScope scope;
7411  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7412  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7413  LocalContext context(0, templ, v8::Handle<Value>());
7414  v8::Handle<Value> value = CompileRun(
7415    "function f() {"
7416    "  for (var i = 0; i < 100; i++) {"
7417    "    try { x = 42; } catch(e) { return true; }"
7418    "  }"
7419    "  return false;"
7420    "};"
7421    "f();");
7422  CHECK_EQ(true, value->BooleanValue());
7423}
7424
7425
7426// Test that we ignore null interceptors.
7427THREADED_TEST(NullNamedInterceptor) {
7428  v8::HandleScope scope;
7429  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7430  templ->SetNamedPropertyHandler(0);
7431  LocalContext context;
7432  templ->Set("x", v8_num(42));
7433  v8::Handle<v8::Object> obj = templ->NewInstance();
7434  context->Global()->Set(v8_str("obj"), obj);
7435  v8::Handle<Value> value = CompileRun("obj.x");
7436  CHECK(value->IsInt32());
7437  CHECK_EQ(42, value->Int32Value());
7438}
7439
7440
7441// Test that we ignore null interceptors.
7442THREADED_TEST(NullIndexedInterceptor) {
7443  v8::HandleScope scope;
7444  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7445  templ->SetIndexedPropertyHandler(0);
7446  LocalContext context;
7447  templ->Set("42", v8_num(42));
7448  v8::Handle<v8::Object> obj = templ->NewInstance();
7449  context->Global()->Set(v8_str("obj"), obj);
7450  v8::Handle<Value> value = CompileRun("obj[42]");
7451  CHECK(value->IsInt32());
7452  CHECK_EQ(42, value->Int32Value());
7453}
7454
7455
7456THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7457  v8::HandleScope scope;
7458  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7459  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7460  LocalContext env;
7461  env->Global()->Set(v8_str("obj"),
7462                     templ->GetFunction()->NewInstance());
7463  ExpectTrue("obj.x === 42");
7464  ExpectTrue("!obj.propertyIsEnumerable('x')");
7465}
7466
7467
7468static v8::Handle<Value> ParentGetter(Local<String> name,
7469                                      const AccessorInfo& info) {
7470  ApiTestFuzzer::Fuzz();
7471  return v8_num(1);
7472}
7473
7474
7475static v8::Handle<Value> ChildGetter(Local<String> name,
7476                                     const AccessorInfo& info) {
7477  ApiTestFuzzer::Fuzz();
7478  return v8_num(42);
7479}
7480
7481
7482THREADED_TEST(Overriding) {
7483  v8::HandleScope scope;
7484  LocalContext context;
7485
7486  // Parent template.
7487  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7488  Local<ObjectTemplate> parent_instance_templ =
7489      parent_templ->InstanceTemplate();
7490  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7491
7492  // Template that inherits from the parent template.
7493  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7494  Local<ObjectTemplate> child_instance_templ =
7495      child_templ->InstanceTemplate();
7496  child_templ->Inherit(parent_templ);
7497  // Override 'f'.  The child version of 'f' should get called for child
7498  // instances.
7499  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7500  // Add 'g' twice.  The 'g' added last should get called for instances.
7501  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7502  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7503
7504  // Add 'h' as an accessor to the proto template with ReadOnly attributes
7505  // so 'h' can be shadowed on the instance object.
7506  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7507  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7508      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7509
7510  // Add 'i' as an accessor to the instance template with ReadOnly attributes
7511  // but the attribute does not have effect because it is duplicated with
7512  // NULL setter.
7513  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7514      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7515
7516
7517
7518  // Instantiate the child template.
7519  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7520
7521  // Check that the child function overrides the parent one.
7522  context->Global()->Set(v8_str("o"), instance);
7523  Local<Value> value = v8_compile("o.f")->Run();
7524  // Check that the 'g' that was added last is hit.
7525  CHECK_EQ(42, value->Int32Value());
7526  value = v8_compile("o.g")->Run();
7527  CHECK_EQ(42, value->Int32Value());
7528
7529  // Check 'h' can be shadowed.
7530  value = v8_compile("o.h = 3; o.h")->Run();
7531  CHECK_EQ(3, value->Int32Value());
7532
7533  // Check 'i' is cannot be shadowed or changed.
7534  value = v8_compile("o.i = 3; o.i")->Run();
7535  CHECK_EQ(42, value->Int32Value());
7536}
7537
7538
7539static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7540  ApiTestFuzzer::Fuzz();
7541  if (args.IsConstructCall()) {
7542    return v8::Boolean::New(true);
7543  }
7544  return v8::Boolean::New(false);
7545}
7546
7547
7548THREADED_TEST(IsConstructCall) {
7549  v8::HandleScope scope;
7550
7551  // Function template with call handler.
7552  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7553  templ->SetCallHandler(IsConstructHandler);
7554
7555  LocalContext context;
7556
7557  context->Global()->Set(v8_str("f"), templ->GetFunction());
7558  Local<Value> value = v8_compile("f()")->Run();
7559  CHECK(!value->BooleanValue());
7560  value = v8_compile("new f()")->Run();
7561  CHECK(value->BooleanValue());
7562}
7563
7564
7565THREADED_TEST(ObjectProtoToString) {
7566  v8::HandleScope scope;
7567  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7568  templ->SetClassName(v8_str("MyClass"));
7569
7570  LocalContext context;
7571
7572  Local<String> customized_tostring = v8_str("customized toString");
7573
7574  // Replace Object.prototype.toString
7575  v8_compile("Object.prototype.toString = function() {"
7576                  "  return 'customized toString';"
7577                  "}")->Run();
7578
7579  // Normal ToString call should call replaced Object.prototype.toString
7580  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7581  Local<String> value = instance->ToString();
7582  CHECK(value->IsString() && value->Equals(customized_tostring));
7583
7584  // ObjectProtoToString should not call replace toString function.
7585  value = instance->ObjectProtoToString();
7586  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7587
7588  // Check global
7589  value = context->Global()->ObjectProtoToString();
7590  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7591
7592  // Check ordinary object
7593  Local<Value> object = v8_compile("new Object()")->Run();
7594  value = object.As<v8::Object>()->ObjectProtoToString();
7595  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7596}
7597
7598
7599bool ApiTestFuzzer::fuzzing_ = false;
7600v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
7601  v8::internal::OS::CreateSemaphore(0);
7602int ApiTestFuzzer::active_tests_;
7603int ApiTestFuzzer::tests_being_run_;
7604int ApiTestFuzzer::current_;
7605
7606
7607// We are in a callback and want to switch to another thread (if we
7608// are currently running the thread fuzzing test).
7609void ApiTestFuzzer::Fuzz() {
7610  if (!fuzzing_) return;
7611  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7612  test->ContextSwitch();
7613}
7614
7615
7616// Let the next thread go.  Since it is also waiting on the V8 lock it may
7617// not start immediately.
7618bool ApiTestFuzzer::NextThread() {
7619  int test_position = GetNextTestNumber();
7620  const char* test_name = RegisterThreadedTest::nth(current_)->name();
7621  if (test_position == current_) {
7622    if (kLogThreading)
7623      printf("Stay with %s\n", test_name);
7624    return false;
7625  }
7626  if (kLogThreading) {
7627    printf("Switch from %s to %s\n",
7628           test_name,
7629           RegisterThreadedTest::nth(test_position)->name());
7630  }
7631  current_ = test_position;
7632  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7633  return true;
7634}
7635
7636
7637void ApiTestFuzzer::Run() {
7638  // When it is our turn...
7639  gate_->Wait();
7640  {
7641    // ... get the V8 lock and start running the test.
7642    v8::Locker locker;
7643    CallTest();
7644  }
7645  // This test finished.
7646  active_ = false;
7647  active_tests_--;
7648  // If it was the last then signal that fact.
7649  if (active_tests_ == 0) {
7650    all_tests_done_->Signal();
7651  } else {
7652    // Otherwise select a new test and start that.
7653    NextThread();
7654  }
7655}
7656
7657
7658static unsigned linear_congruential_generator;
7659
7660
7661void ApiTestFuzzer::Setup(PartOfTest part) {
7662  linear_congruential_generator = i::FLAG_testing_prng_seed;
7663  fuzzing_ = true;
7664  int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7665  int end = (part == FIRST_PART)
7666      ? (RegisterThreadedTest::count() >> 1)
7667      : RegisterThreadedTest::count();
7668  active_tests_ = tests_being_run_ = end - start;
7669  for (int i = 0; i < tests_being_run_; i++) {
7670    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7671  }
7672  for (int i = 0; i < active_tests_; i++) {
7673    RegisterThreadedTest::nth(i)->fuzzer_->Start();
7674  }
7675}
7676
7677
7678static void CallTestNumber(int test_number) {
7679  (RegisterThreadedTest::nth(test_number)->callback())();
7680}
7681
7682
7683void ApiTestFuzzer::RunAllTests() {
7684  // Set off the first test.
7685  current_ = -1;
7686  NextThread();
7687  // Wait till they are all done.
7688  all_tests_done_->Wait();
7689}
7690
7691
7692int ApiTestFuzzer::GetNextTestNumber() {
7693  int next_test;
7694  do {
7695    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7696    linear_congruential_generator *= 1664525u;
7697    linear_congruential_generator += 1013904223u;
7698  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7699  return next_test;
7700}
7701
7702
7703void ApiTestFuzzer::ContextSwitch() {
7704  // If the new thread is the same as the current thread there is nothing to do.
7705  if (NextThread()) {
7706    // Now it can start.
7707    v8::Unlocker unlocker;
7708    // Wait till someone starts us again.
7709    gate_->Wait();
7710    // And we're off.
7711  }
7712}
7713
7714
7715void ApiTestFuzzer::TearDown() {
7716  fuzzing_ = false;
7717  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7718    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7719    if (fuzzer != NULL) fuzzer->Join();
7720  }
7721}
7722
7723
7724// Lets not be needlessly self-referential.
7725TEST(Threading) {
7726  ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7727  ApiTestFuzzer::RunAllTests();
7728  ApiTestFuzzer::TearDown();
7729}
7730
7731TEST(Threading2) {
7732  ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7733  ApiTestFuzzer::RunAllTests();
7734  ApiTestFuzzer::TearDown();
7735}
7736
7737
7738void ApiTestFuzzer::CallTest() {
7739  if (kLogThreading)
7740    printf("Start test %d\n", test_number_);
7741  CallTestNumber(test_number_);
7742  if (kLogThreading)
7743    printf("End test %d\n", test_number_);
7744}
7745
7746
7747static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7748  CHECK(v8::Locker::IsLocked());
7749  ApiTestFuzzer::Fuzz();
7750  v8::Unlocker unlocker;
7751  const char* code = "throw 7;";
7752  {
7753    v8::Locker nested_locker;
7754    v8::HandleScope scope;
7755    v8::Handle<Value> exception;
7756    { v8::TryCatch try_catch;
7757      v8::Handle<Value> value = CompileRun(code);
7758      CHECK(value.IsEmpty());
7759      CHECK(try_catch.HasCaught());
7760      // Make sure to wrap the exception in a new handle because
7761      // the handle returned from the TryCatch is destroyed
7762      // when the TryCatch is destroyed.
7763      exception = Local<Value>::New(try_catch.Exception());
7764    }
7765    return v8::ThrowException(exception);
7766  }
7767}
7768
7769
7770static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7771  CHECK(v8::Locker::IsLocked());
7772  ApiTestFuzzer::Fuzz();
7773  v8::Unlocker unlocker;
7774  const char* code = "throw 7;";
7775  {
7776    v8::Locker nested_locker;
7777    v8::HandleScope scope;
7778    v8::Handle<Value> value = CompileRun(code);
7779    CHECK(value.IsEmpty());
7780    return v8_str("foo");
7781  }
7782}
7783
7784
7785// These are locking tests that don't need to be run again
7786// as part of the locking aggregation tests.
7787TEST(NestedLockers) {
7788  v8::Locker locker;
7789  CHECK(v8::Locker::IsLocked());
7790  v8::HandleScope scope;
7791  LocalContext env;
7792  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7793  Local<Function> fun = fun_templ->GetFunction();
7794  env->Global()->Set(v8_str("throw_in_js"), fun);
7795  Local<Script> script = v8_compile("(function () {"
7796                                    "  try {"
7797                                    "    throw_in_js();"
7798                                    "    return 42;"
7799                                    "  } catch (e) {"
7800                                    "    return e * 13;"
7801                                    "  }"
7802                                    "})();");
7803  CHECK_EQ(91, script->Run()->Int32Value());
7804}
7805
7806
7807// These are locking tests that don't need to be run again
7808// as part of the locking aggregation tests.
7809TEST(NestedLockersNoTryCatch) {
7810  v8::Locker locker;
7811  v8::HandleScope scope;
7812  LocalContext env;
7813  Local<v8::FunctionTemplate> fun_templ =
7814      v8::FunctionTemplate::New(ThrowInJSNoCatch);
7815  Local<Function> fun = fun_templ->GetFunction();
7816  env->Global()->Set(v8_str("throw_in_js"), fun);
7817  Local<Script> script = v8_compile("(function () {"
7818                                    "  try {"
7819                                    "    throw_in_js();"
7820                                    "    return 42;"
7821                                    "  } catch (e) {"
7822                                    "    return e * 13;"
7823                                    "  }"
7824                                    "})();");
7825  CHECK_EQ(91, script->Run()->Int32Value());
7826}
7827
7828
7829THREADED_TEST(RecursiveLocking) {
7830  v8::Locker locker;
7831  {
7832    v8::Locker locker2;
7833    CHECK(v8::Locker::IsLocked());
7834  }
7835}
7836
7837
7838static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7839  ApiTestFuzzer::Fuzz();
7840  v8::Unlocker unlocker;
7841  return v8::Undefined();
7842}
7843
7844
7845THREADED_TEST(LockUnlockLock) {
7846  {
7847    v8::Locker locker;
7848    v8::HandleScope scope;
7849    LocalContext env;
7850    Local<v8::FunctionTemplate> fun_templ =
7851        v8::FunctionTemplate::New(UnlockForAMoment);
7852    Local<Function> fun = fun_templ->GetFunction();
7853    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7854    Local<Script> script = v8_compile("(function () {"
7855                                      "  unlock_for_a_moment();"
7856                                      "  return 42;"
7857                                      "})();");
7858    CHECK_EQ(42, script->Run()->Int32Value());
7859  }
7860  {
7861    v8::Locker locker;
7862    v8::HandleScope scope;
7863    LocalContext env;
7864    Local<v8::FunctionTemplate> fun_templ =
7865        v8::FunctionTemplate::New(UnlockForAMoment);
7866    Local<Function> fun = fun_templ->GetFunction();
7867    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7868    Local<Script> script = v8_compile("(function () {"
7869                                      "  unlock_for_a_moment();"
7870                                      "  return 42;"
7871                                      "})();");
7872    CHECK_EQ(42, script->Run()->Int32Value());
7873  }
7874}
7875
7876
7877static int GetGlobalObjectsCount() {
7878  int count = 0;
7879  v8::internal::HeapIterator it;
7880  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7881    if (object->IsJSGlobalObject()) count++;
7882  return count;
7883}
7884
7885
7886static int GetSurvivingGlobalObjectsCount() {
7887  // We need to collect all garbage twice to be sure that everything
7888  // has been collected.  This is because inline caches are cleared in
7889  // the first garbage collection but some of the maps have already
7890  // been marked at that point.  Therefore some of the maps are not
7891  // collected until the second garbage collection.
7892  v8::internal::Heap::CollectAllGarbage(false);
7893  v8::internal::Heap::CollectAllGarbage(false);
7894  int count = GetGlobalObjectsCount();
7895#ifdef DEBUG
7896  if (count > 0) v8::internal::Heap::TracePathToGlobal();
7897#endif
7898  return count;
7899}
7900
7901
7902TEST(DontLeakGlobalObjects) {
7903  // Regression test for issues 1139850 and 1174891.
7904
7905  v8::V8::Initialize();
7906
7907  int count = GetSurvivingGlobalObjectsCount();
7908
7909  for (int i = 0; i < 5; i++) {
7910    { v8::HandleScope scope;
7911      LocalContext context;
7912    }
7913    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7914
7915    { v8::HandleScope scope;
7916      LocalContext context;
7917      v8_compile("Date")->Run();
7918    }
7919    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7920
7921    { v8::HandleScope scope;
7922      LocalContext context;
7923      v8_compile("/aaa/")->Run();
7924    }
7925    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7926
7927    { v8::HandleScope scope;
7928      const char* extension_list[] = { "v8/gc" };
7929      v8::ExtensionConfiguration extensions(1, extension_list);
7930      LocalContext context(&extensions);
7931      v8_compile("gc();")->Run();
7932    }
7933    CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7934  }
7935}
7936
7937
7938v8::Persistent<v8::Object> some_object;
7939v8::Persistent<v8::Object> bad_handle;
7940
7941void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7942  v8::HandleScope scope;
7943  bad_handle = v8::Persistent<v8::Object>::New(some_object);
7944}
7945
7946
7947THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7948  LocalContext context;
7949
7950  v8::Persistent<v8::Object> handle1, handle2;
7951  {
7952    v8::HandleScope scope;
7953    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7954    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7955    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7956  }
7957  // Note: order is implementation dependent alas: currently
7958  // global handle nodes are processed by PostGarbageCollectionProcessing
7959  // in reverse allocation order, so if second allocated handle is deleted,
7960  // weak callback of the first handle would be able to 'reallocate' it.
7961  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7962  handle2.Dispose();
7963  i::Heap::CollectAllGarbage(false);
7964}
7965
7966
7967v8::Persistent<v8::Object> to_be_disposed;
7968
7969void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7970  to_be_disposed.Dispose();
7971  i::Heap::CollectAllGarbage(false);
7972}
7973
7974
7975THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7976  LocalContext context;
7977
7978  v8::Persistent<v8::Object> handle1, handle2;
7979  {
7980    v8::HandleScope scope;
7981    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7982    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7983  }
7984  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7985  to_be_disposed = handle2;
7986  i::Heap::CollectAllGarbage(false);
7987}
7988
7989void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7990  handle.Dispose();
7991}
7992
7993void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7994  v8::HandleScope scope;
7995  v8::Persistent<v8::Object>::New(v8::Object::New());
7996}
7997
7998
7999THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8000  LocalContext context;
8001
8002  v8::Persistent<v8::Object> handle1, handle2, handle3;
8003  {
8004    v8::HandleScope scope;
8005    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8006    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8007    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8008  }
8009  handle2.MakeWeak(NULL, DisposingCallback);
8010  handle3.MakeWeak(NULL, HandleCreatingCallback);
8011  i::Heap::CollectAllGarbage(false);
8012}
8013
8014
8015THREADED_TEST(CheckForCrossContextObjectLiterals) {
8016  v8::V8::Initialize();
8017
8018  const int nof = 2;
8019  const char* sources[nof] = {
8020    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8021    "Object()"
8022  };
8023
8024  for (int i = 0; i < nof; i++) {
8025    const char* source = sources[i];
8026    { v8::HandleScope scope;
8027      LocalContext context;
8028      CompileRun(source);
8029    }
8030    { v8::HandleScope scope;
8031      LocalContext context;
8032      CompileRun(source);
8033    }
8034  }
8035}
8036
8037
8038static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8039  v8::HandleScope inner;
8040  env->Enter();
8041  v8::Handle<Value> three = v8_num(3);
8042  v8::Handle<Value> value = inner.Close(three);
8043  env->Exit();
8044  return value;
8045}
8046
8047
8048THREADED_TEST(NestedHandleScopeAndContexts) {
8049  v8::HandleScope outer;
8050  v8::Persistent<Context> env = Context::New();
8051  env->Enter();
8052  v8::Handle<Value> value = NestedScope(env);
8053  v8::Handle<String> str = value->ToString();
8054  env->Exit();
8055  env.Dispose();
8056}
8057
8058
8059THREADED_TEST(ExternalAllocatedMemory) {
8060  v8::HandleScope outer;
8061  v8::Persistent<Context> env = Context::New();
8062  const int kSize = 1024*1024;
8063  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8064  CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8065}
8066
8067
8068THREADED_TEST(DisposeEnteredContext) {
8069  v8::HandleScope scope;
8070  LocalContext outer;
8071  { v8::Persistent<v8::Context> inner = v8::Context::New();
8072    inner->Enter();
8073    inner.Dispose();
8074    inner.Clear();
8075    inner->Exit();
8076  }
8077}
8078
8079
8080// Regression test for issue 54, object templates with internal fields
8081// but no accessors or interceptors did not get their internal field
8082// count set on instances.
8083THREADED_TEST(Regress54) {
8084  v8::HandleScope outer;
8085  LocalContext context;
8086  static v8::Persistent<v8::ObjectTemplate> templ;
8087  if (templ.IsEmpty()) {
8088    v8::HandleScope inner;
8089    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8090    local->SetInternalFieldCount(1);
8091    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8092  }
8093  v8::Handle<v8::Object> result = templ->NewInstance();
8094  CHECK_EQ(1, result->InternalFieldCount());
8095}
8096
8097
8098// If part of the threaded tests, this test makes ThreadingTest fail
8099// on mac.
8100TEST(CatchStackOverflow) {
8101  v8::HandleScope scope;
8102  LocalContext context;
8103  v8::TryCatch try_catch;
8104  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8105    "function f() {"
8106    "  return f();"
8107    "}"
8108    ""
8109    "f();"));
8110  v8::Handle<v8::Value> result = script->Run();
8111  CHECK(result.IsEmpty());
8112}
8113
8114
8115static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8116                                    const char* resource_name,
8117                                    int line_offset) {
8118  v8::HandleScope scope;
8119  v8::TryCatch try_catch;
8120  v8::Handle<v8::Value> result = script->Run();
8121  CHECK(result.IsEmpty());
8122  CHECK(try_catch.HasCaught());
8123  v8::Handle<v8::Message> message = try_catch.Message();
8124  CHECK(!message.IsEmpty());
8125  CHECK_EQ(10 + line_offset, message->GetLineNumber());
8126  CHECK_EQ(91, message->GetStartPosition());
8127  CHECK_EQ(92, message->GetEndPosition());
8128  CHECK_EQ(2, message->GetStartColumn());
8129  CHECK_EQ(3, message->GetEndColumn());
8130  v8::String::AsciiValue line(message->GetSourceLine());
8131  CHECK_EQ("  throw 'nirk';", *line);
8132  v8::String::AsciiValue name(message->GetScriptResourceName());
8133  CHECK_EQ(resource_name, *name);
8134}
8135
8136
8137THREADED_TEST(TryCatchSourceInfo) {
8138  v8::HandleScope scope;
8139  LocalContext context;
8140  v8::Handle<v8::String> source = v8::String::New(
8141      "function Foo() {\n"
8142      "  return Bar();\n"
8143      "}\n"
8144      "\n"
8145      "function Bar() {\n"
8146      "  return Baz();\n"
8147      "}\n"
8148      "\n"
8149      "function Baz() {\n"
8150      "  throw 'nirk';\n"
8151      "}\n"
8152      "\n"
8153      "Foo();\n");
8154
8155  const char* resource_name;
8156  v8::Handle<v8::Script> script;
8157  resource_name = "test.js";
8158  script = v8::Script::Compile(source, v8::String::New(resource_name));
8159  CheckTryCatchSourceInfo(script, resource_name, 0);
8160
8161  resource_name = "test1.js";
8162  v8::ScriptOrigin origin1(v8::String::New(resource_name));
8163  script = v8::Script::Compile(source, &origin1);
8164  CheckTryCatchSourceInfo(script, resource_name, 0);
8165
8166  resource_name = "test2.js";
8167  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8168  script = v8::Script::Compile(source, &origin2);
8169  CheckTryCatchSourceInfo(script, resource_name, 7);
8170}
8171
8172
8173THREADED_TEST(CompilationCache) {
8174  v8::HandleScope scope;
8175  LocalContext context;
8176  v8::Handle<v8::String> source0 = v8::String::New("1234");
8177  v8::Handle<v8::String> source1 = v8::String::New("1234");
8178  v8::Handle<v8::Script> script0 =
8179      v8::Script::Compile(source0, v8::String::New("test.js"));
8180  v8::Handle<v8::Script> script1 =
8181      v8::Script::Compile(source1, v8::String::New("test.js"));
8182  v8::Handle<v8::Script> script2 =
8183      v8::Script::Compile(source0);  // different origin
8184  CHECK_EQ(1234, script0->Run()->Int32Value());
8185  CHECK_EQ(1234, script1->Run()->Int32Value());
8186  CHECK_EQ(1234, script2->Run()->Int32Value());
8187}
8188
8189
8190static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8191  ApiTestFuzzer::Fuzz();
8192  return v8_num(42);
8193}
8194
8195
8196THREADED_TEST(CallbackFunctionName) {
8197  v8::HandleScope scope;
8198  LocalContext context;
8199  Local<ObjectTemplate> t = ObjectTemplate::New();
8200  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8201  context->Global()->Set(v8_str("obj"), t->NewInstance());
8202  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8203  CHECK(value->IsString());
8204  v8::String::AsciiValue name(value);
8205  CHECK_EQ("asdf", *name);
8206}
8207
8208
8209THREADED_TEST(DateAccess) {
8210  v8::HandleScope scope;
8211  LocalContext context;
8212  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8213  CHECK(date->IsDate());
8214  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
8215}
8216
8217
8218void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
8219  v8::Handle<v8::Object> obj = val.As<v8::Object>();
8220  v8::Handle<v8::Array> props = obj->GetPropertyNames();
8221  CHECK_EQ(elmc, props->Length());
8222  for (int i = 0; i < elmc; i++) {
8223    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8224    CHECK_EQ(elmv[i], *elm);
8225  }
8226}
8227
8228
8229THREADED_TEST(PropertyEnumeration) {
8230  v8::HandleScope scope;
8231  LocalContext context;
8232  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8233      "var result = [];"
8234      "result[0] = {};"
8235      "result[1] = {a: 1, b: 2};"
8236      "result[2] = [1, 2, 3];"
8237      "var proto = {x: 1, y: 2, z: 3};"
8238      "var x = { __proto__: proto, w: 0, z: 1 };"
8239      "result[3] = x;"
8240      "result;"))->Run();
8241  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
8242  CHECK_EQ(4, elms->Length());
8243  int elmc0 = 0;
8244  const char** elmv0 = NULL;
8245  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8246  int elmc1 = 2;
8247  const char* elmv1[] = {"a", "b"};
8248  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8249  int elmc2 = 3;
8250  const char* elmv2[] = {"0", "1", "2"};
8251  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8252  int elmc3 = 4;
8253  const char* elmv3[] = {"w", "z", "x", "y"};
8254  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8255}
8256
8257
8258static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8259                                  Local<Value> name,
8260                                  v8::AccessType type,
8261                                  Local<Value> data) {
8262  return type != v8::ACCESS_SET;
8263}
8264
8265
8266static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8267                                    uint32_t key,
8268                                    v8::AccessType type,
8269                                    Local<Value> data) {
8270  return type != v8::ACCESS_SET;
8271}
8272
8273
8274THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8275  v8::HandleScope scope;
8276  LocalContext context;
8277  Local<ObjectTemplate> templ = ObjectTemplate::New();
8278  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8279                                 IndexedSetAccessBlocker);
8280  templ->Set(v8_str("x"), v8::True());
8281  Local<v8::Object> instance = templ->NewInstance();
8282  context->Global()->Set(v8_str("obj"), instance);
8283  Local<Value> value = CompileRun("obj.x");
8284  CHECK(value->BooleanValue());
8285}
8286
8287
8288static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8289                                  Local<Value> name,
8290                                  v8::AccessType type,
8291                                  Local<Value> data) {
8292  return false;
8293}
8294
8295
8296static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8297                                    uint32_t key,
8298                                    v8::AccessType type,
8299                                    Local<Value> data) {
8300  return false;
8301}
8302
8303
8304
8305THREADED_TEST(AccessChecksReenabledCorrectly) {
8306  v8::HandleScope scope;
8307  LocalContext context;
8308  Local<ObjectTemplate> templ = ObjectTemplate::New();
8309  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8310                                 IndexedGetAccessBlocker);
8311  templ->Set(v8_str("a"), v8_str("a"));
8312  // Add more than 8 (see kMaxFastProperties) properties
8313  // so that the constructor will force copying map.
8314  // Cannot sprintf, gcc complains unsafety.
8315  char buf[4];
8316  for (char i = '0'; i <= '9' ; i++) {
8317    buf[0] = i;
8318    for (char j = '0'; j <= '9'; j++) {
8319      buf[1] = j;
8320      for (char k = '0'; k <= '9'; k++) {
8321        buf[2] = k;
8322        buf[3] = 0;
8323        templ->Set(v8_str(buf), v8::Number::New(k));
8324      }
8325    }
8326  }
8327
8328  Local<v8::Object> instance_1 = templ->NewInstance();
8329  context->Global()->Set(v8_str("obj_1"), instance_1);
8330
8331  Local<Value> value_1 = CompileRun("obj_1.a");
8332  CHECK(value_1->IsUndefined());
8333
8334  Local<v8::Object> instance_2 = templ->NewInstance();
8335  context->Global()->Set(v8_str("obj_2"), instance_2);
8336
8337  Local<Value> value_2 = CompileRun("obj_2.a");
8338  CHECK(value_2->IsUndefined());
8339}
8340
8341
8342// This tests that access check information remains on the global
8343// object template when creating contexts.
8344THREADED_TEST(AccessControlRepeatedContextCreation) {
8345  v8::HandleScope handle_scope;
8346  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8347  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8348                                           IndexedSetAccessBlocker);
8349  i::Handle<i::ObjectTemplateInfo> internal_template =
8350      v8::Utils::OpenHandle(*global_template);
8351  CHECK(!internal_template->constructor()->IsUndefined());
8352  i::Handle<i::FunctionTemplateInfo> constructor(
8353      i::FunctionTemplateInfo::cast(internal_template->constructor()));
8354  CHECK(!constructor->access_check_info()->IsUndefined());
8355  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8356  CHECK(!constructor->access_check_info()->IsUndefined());
8357}
8358
8359
8360THREADED_TEST(TurnOnAccessCheck) {
8361  v8::HandleScope handle_scope;
8362
8363  // Create an environment with access check to the global object disabled by
8364  // default.
8365  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8366  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8367                                           IndexedGetAccessBlocker,
8368                                           v8::Handle<v8::Value>(),
8369                                           false);
8370  v8::Persistent<Context> context = Context::New(NULL, global_template);
8371  Context::Scope context_scope(context);
8372
8373  // Set up a property and a number of functions.
8374  context->Global()->Set(v8_str("a"), v8_num(1));
8375  CompileRun("function f1() {return a;}"
8376             "function f2() {return a;}"
8377             "function g1() {return h();}"
8378             "function g2() {return h();}"
8379             "function h() {return 1;}");
8380  Local<Function> f1 =
8381      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8382  Local<Function> f2 =
8383      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8384  Local<Function> g1 =
8385      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8386  Local<Function> g2 =
8387      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8388  Local<Function> h =
8389      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8390
8391  // Get the global object.
8392  v8::Handle<v8::Object> global = context->Global();
8393
8394  // Call f1 one time and f2 a number of times. This will ensure that f1 still
8395  // uses the runtime system to retreive property a whereas f2 uses global load
8396  // inline cache.
8397  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8398  for (int i = 0; i < 4; i++) {
8399    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8400  }
8401
8402  // Same for g1 and g2.
8403  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8404  for (int i = 0; i < 4; i++) {
8405    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8406  }
8407
8408  // Detach the global and turn on access check.
8409  context->DetachGlobal();
8410  context->Global()->TurnOnAccessCheck();
8411
8412  // Failing access check to property get results in undefined.
8413  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8414  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8415
8416  // Failing access check to function call results in exception.
8417  CHECK(g1->Call(global, 0, NULL).IsEmpty());
8418  CHECK(g2->Call(global, 0, NULL).IsEmpty());
8419
8420  // No failing access check when just returning a constant.
8421  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8422}
8423
8424
8425// This test verifies that pre-compilation (aka preparsing) can be called
8426// without initializing the whole VM. Thus we cannot run this test in a
8427// multi-threaded setup.
8428TEST(PreCompile) {
8429  // TODO(155): This test would break without the initialization of V8. This is
8430  // a workaround for now to make this test not fail.
8431  v8::V8::Initialize();
8432  const char* script = "function foo(a) { return a+1; }";
8433  v8::ScriptData* sd =
8434      v8::ScriptData::PreCompile(script, i::StrLength(script));
8435  CHECK_NE(sd->Length(), 0);
8436  CHECK_NE(sd->Data(), NULL);
8437  CHECK(!sd->HasError());
8438  delete sd;
8439}
8440
8441
8442TEST(PreCompileWithError) {
8443  v8::V8::Initialize();
8444  const char* script = "function foo(a) { return 1 * * 2; }";
8445  v8::ScriptData* sd =
8446      v8::ScriptData::PreCompile(script, i::StrLength(script));
8447  CHECK(sd->HasError());
8448  delete sd;
8449}
8450
8451
8452TEST(Regress31661) {
8453  v8::V8::Initialize();
8454  const char* script = " The Definintive Guide";
8455  v8::ScriptData* sd =
8456      v8::ScriptData::PreCompile(script, i::StrLength(script));
8457  CHECK(sd->HasError());
8458  delete sd;
8459}
8460
8461
8462// Tests that ScriptData can be serialized and deserialized.
8463TEST(PreCompileSerialization) {
8464  v8::V8::Initialize();
8465  const char* script = "function foo(a) { return a+1; }";
8466  v8::ScriptData* sd =
8467      v8::ScriptData::PreCompile(script, i::StrLength(script));
8468
8469  // Serialize.
8470  int serialized_data_length = sd->Length();
8471  char* serialized_data = i::NewArray<char>(serialized_data_length);
8472  memcpy(serialized_data, sd->Data(), serialized_data_length);
8473
8474  // Deserialize.
8475  v8::ScriptData* deserialized_sd =
8476      v8::ScriptData::New(serialized_data, serialized_data_length);
8477
8478  // Verify that the original is the same as the deserialized.
8479  CHECK_EQ(sd->Length(), deserialized_sd->Length());
8480  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
8481  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
8482
8483  delete sd;
8484  delete deserialized_sd;
8485}
8486
8487
8488// Attempts to deserialize bad data.
8489TEST(PreCompileDeserializationError) {
8490  v8::V8::Initialize();
8491  const char* data = "DONT CARE";
8492  int invalid_size = 3;
8493  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
8494
8495  CHECK_EQ(0, sd->Length());
8496
8497  delete sd;
8498}
8499
8500
8501// Verifies that the Handle<String> and const char* versions of the API produce
8502// the same results (at least for one trivial case).
8503TEST(PreCompileAPIVariationsAreSame) {
8504  v8::V8::Initialize();
8505  v8::HandleScope scope;
8506
8507  const char* cstring = "function foo(a) { return a+1; }";
8508  v8::ScriptData* sd_from_cstring =
8509      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
8510
8511  TestAsciiResource* resource = new TestAsciiResource(cstring);
8512  v8::ScriptData* sd_from_istring = v8::ScriptData::PreCompile(
8513      v8::String::NewExternal(resource));
8514
8515  CHECK_EQ(sd_from_cstring->Length(), sd_from_istring->Length());
8516  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
8517                     sd_from_istring->Data(),
8518                     sd_from_cstring->Length()));
8519
8520  delete sd_from_cstring;
8521  delete sd_from_istring;
8522}
8523
8524
8525// This tests that we do not allow dictionary load/call inline caches
8526// to use functions that have not yet been compiled.  The potential
8527// problem of loading a function that has not yet been compiled can
8528// arise because we share code between contexts via the compilation
8529// cache.
8530THREADED_TEST(DictionaryICLoadedFunction) {
8531  v8::HandleScope scope;
8532  // Test LoadIC.
8533  for (int i = 0; i < 2; i++) {
8534    LocalContext context;
8535    context->Global()->Set(v8_str("tmp"), v8::True());
8536    context->Global()->Delete(v8_str("tmp"));
8537    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8538  }
8539  // Test CallIC.
8540  for (int i = 0; i < 2; i++) {
8541    LocalContext context;
8542    context->Global()->Set(v8_str("tmp"), v8::True());
8543    context->Global()->Delete(v8_str("tmp"));
8544    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8545  }
8546}
8547
8548
8549// Test that cross-context new calls use the context of the callee to
8550// create the new JavaScript object.
8551THREADED_TEST(CrossContextNew) {
8552  v8::HandleScope scope;
8553  v8::Persistent<Context> context0 = Context::New();
8554  v8::Persistent<Context> context1 = Context::New();
8555
8556  // Allow cross-domain access.
8557  Local<String> token = v8_str("<security token>");
8558  context0->SetSecurityToken(token);
8559  context1->SetSecurityToken(token);
8560
8561  // Set an 'x' property on the Object prototype and define a
8562  // constructor function in context0.
8563  context0->Enter();
8564  CompileRun("Object.prototype.x = 42; function C() {};");
8565  context0->Exit();
8566
8567  // Call the constructor function from context0 and check that the
8568  // result has the 'x' property.
8569  context1->Enter();
8570  context1->Global()->Set(v8_str("other"), context0->Global());
8571  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8572  CHECK(value->IsInt32());
8573  CHECK_EQ(42, value->Int32Value());
8574  context1->Exit();
8575
8576  // Dispose the contexts to allow them to be garbage collected.
8577  context0.Dispose();
8578  context1.Dispose();
8579}
8580
8581
8582class RegExpInterruptTest {
8583 public:
8584  RegExpInterruptTest() : block_(NULL) {}
8585  ~RegExpInterruptTest() { delete block_; }
8586  void RunTest() {
8587    block_ = i::OS::CreateSemaphore(0);
8588    gc_count_ = 0;
8589    gc_during_regexp_ = 0;
8590    regexp_success_ = false;
8591    gc_success_ = false;
8592    GCThread gc_thread(this);
8593    gc_thread.Start();
8594    v8::Locker::StartPreemption(1);
8595
8596    LongRunningRegExp();
8597    {
8598      v8::Unlocker unlock;
8599      gc_thread.Join();
8600    }
8601    v8::Locker::StopPreemption();
8602    CHECK(regexp_success_);
8603    CHECK(gc_success_);
8604  }
8605 private:
8606  // Number of garbage collections required.
8607  static const int kRequiredGCs = 5;
8608
8609  class GCThread : public i::Thread {
8610   public:
8611    explicit GCThread(RegExpInterruptTest* test)
8612        : test_(test) {}
8613    virtual void Run() {
8614      test_->CollectGarbage();
8615    }
8616   private:
8617     RegExpInterruptTest* test_;
8618  };
8619
8620  void CollectGarbage() {
8621    block_->Wait();
8622    while (gc_during_regexp_ < kRequiredGCs) {
8623      {
8624        v8::Locker lock;
8625        // TODO(lrn): Perhaps create some garbage before collecting.
8626        i::Heap::CollectAllGarbage(false);
8627        gc_count_++;
8628      }
8629      i::OS::Sleep(1);
8630    }
8631    gc_success_ = true;
8632  }
8633
8634  void LongRunningRegExp() {
8635    block_->Signal();  // Enable garbage collection thread on next preemption.
8636    int rounds = 0;
8637    while (gc_during_regexp_ < kRequiredGCs) {
8638      int gc_before = gc_count_;
8639      {
8640        // Match 15-30 "a"'s against 14 and a "b".
8641        const char* c_source =
8642            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8643            ".exec('aaaaaaaaaaaaaaab') === null";
8644        Local<String> source = String::New(c_source);
8645        Local<Script> script = Script::Compile(source);
8646        Local<Value> result = script->Run();
8647        if (!result->BooleanValue()) {
8648          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
8649          return;
8650        }
8651      }
8652      {
8653        // Match 15-30 "a"'s against 15 and a "b".
8654        const char* c_source =
8655            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8656            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8657        Local<String> source = String::New(c_source);
8658        Local<Script> script = Script::Compile(source);
8659        Local<Value> result = script->Run();
8660        if (!result->BooleanValue()) {
8661          gc_during_regexp_ = kRequiredGCs;
8662          return;
8663        }
8664      }
8665      int gc_after = gc_count_;
8666      gc_during_regexp_ += gc_after - gc_before;
8667      rounds++;
8668      i::OS::Sleep(1);
8669    }
8670    regexp_success_ = true;
8671  }
8672
8673  i::Semaphore* block_;
8674  int gc_count_;
8675  int gc_during_regexp_;
8676  bool regexp_success_;
8677  bool gc_success_;
8678};
8679
8680
8681// Test that a regular expression execution can be interrupted and
8682// survive a garbage collection.
8683TEST(RegExpInterruption) {
8684  v8::Locker lock;
8685  v8::V8::Initialize();
8686  v8::HandleScope scope;
8687  Local<Context> local_env;
8688  {
8689    LocalContext env;
8690    local_env = env.local();
8691  }
8692
8693  // Local context should still be live.
8694  CHECK(!local_env.IsEmpty());
8695  local_env->Enter();
8696
8697  // Should complete without problems.
8698  RegExpInterruptTest().RunTest();
8699
8700  local_env->Exit();
8701}
8702
8703
8704class ApplyInterruptTest {
8705 public:
8706  ApplyInterruptTest() : block_(NULL) {}
8707  ~ApplyInterruptTest() { delete block_; }
8708  void RunTest() {
8709    block_ = i::OS::CreateSemaphore(0);
8710    gc_count_ = 0;
8711    gc_during_apply_ = 0;
8712    apply_success_ = false;
8713    gc_success_ = false;
8714    GCThread gc_thread(this);
8715    gc_thread.Start();
8716    v8::Locker::StartPreemption(1);
8717
8718    LongRunningApply();
8719    {
8720      v8::Unlocker unlock;
8721      gc_thread.Join();
8722    }
8723    v8::Locker::StopPreemption();
8724    CHECK(apply_success_);
8725    CHECK(gc_success_);
8726  }
8727 private:
8728  // Number of garbage collections required.
8729  static const int kRequiredGCs = 2;
8730
8731  class GCThread : public i::Thread {
8732   public:
8733    explicit GCThread(ApplyInterruptTest* test)
8734        : test_(test) {}
8735    virtual void Run() {
8736      test_->CollectGarbage();
8737    }
8738   private:
8739     ApplyInterruptTest* test_;
8740  };
8741
8742  void CollectGarbage() {
8743    block_->Wait();
8744    while (gc_during_apply_ < kRequiredGCs) {
8745      {
8746        v8::Locker lock;
8747        i::Heap::CollectAllGarbage(false);
8748        gc_count_++;
8749      }
8750      i::OS::Sleep(1);
8751    }
8752    gc_success_ = true;
8753  }
8754
8755  void LongRunningApply() {
8756    block_->Signal();
8757    int rounds = 0;
8758    while (gc_during_apply_ < kRequiredGCs) {
8759      int gc_before = gc_count_;
8760      {
8761        const char* c_source =
8762            "function do_very_little(bar) {"
8763            "  this.foo = bar;"
8764            "}"
8765            "for (var i = 0; i < 100000; i++) {"
8766            "  do_very_little.apply(this, ['bar']);"
8767            "}";
8768        Local<String> source = String::New(c_source);
8769        Local<Script> script = Script::Compile(source);
8770        Local<Value> result = script->Run();
8771        // Check that no exception was thrown.
8772        CHECK(!result.IsEmpty());
8773      }
8774      int gc_after = gc_count_;
8775      gc_during_apply_ += gc_after - gc_before;
8776      rounds++;
8777    }
8778    apply_success_ = true;
8779  }
8780
8781  i::Semaphore* block_;
8782  int gc_count_;
8783  int gc_during_apply_;
8784  bool apply_success_;
8785  bool gc_success_;
8786};
8787
8788
8789// Test that nothing bad happens if we get a preemption just when we were
8790// about to do an apply().
8791TEST(ApplyInterruption) {
8792  v8::Locker lock;
8793  v8::V8::Initialize();
8794  v8::HandleScope scope;
8795  Local<Context> local_env;
8796  {
8797    LocalContext env;
8798    local_env = env.local();
8799  }
8800
8801  // Local context should still be live.
8802  CHECK(!local_env.IsEmpty());
8803  local_env->Enter();
8804
8805  // Should complete without problems.
8806  ApplyInterruptTest().RunTest();
8807
8808  local_env->Exit();
8809}
8810
8811
8812// Verify that we can clone an object
8813TEST(ObjectClone) {
8814  v8::HandleScope scope;
8815  LocalContext env;
8816
8817  const char* sample =
8818    "var rv = {};"      \
8819    "rv.alpha = 'hello';" \
8820    "rv.beta = 123;"     \
8821    "rv;";
8822
8823  // Create an object, verify basics.
8824  Local<Value> val = CompileRun(sample);
8825  CHECK(val->IsObject());
8826  Local<v8::Object> obj = val.As<v8::Object>();
8827  obj->Set(v8_str("gamma"), v8_str("cloneme"));
8828
8829  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8830  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8831  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8832
8833  // Clone it.
8834  Local<v8::Object> clone = obj->Clone();
8835  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8836  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8837  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8838
8839  // Set a property on the clone, verify each object.
8840  clone->Set(v8_str("beta"), v8::Integer::New(456));
8841  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8842  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8843}
8844
8845
8846class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8847 public:
8848  explicit AsciiVectorResource(i::Vector<const char> vector)
8849      : data_(vector) {}
8850  virtual ~AsciiVectorResource() {}
8851  virtual size_t length() const { return data_.length(); }
8852  virtual const char* data() const { return data_.start(); }
8853 private:
8854  i::Vector<const char> data_;
8855};
8856
8857
8858class UC16VectorResource : public v8::String::ExternalStringResource {
8859 public:
8860  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8861      : data_(vector) {}
8862  virtual ~UC16VectorResource() {}
8863  virtual size_t length() const { return data_.length(); }
8864  virtual const i::uc16* data() const { return data_.start(); }
8865 private:
8866  i::Vector<const i::uc16> data_;
8867};
8868
8869
8870static void MorphAString(i::String* string,
8871                         AsciiVectorResource* ascii_resource,
8872                         UC16VectorResource* uc16_resource) {
8873  CHECK(i::StringShape(string).IsExternal());
8874  if (string->IsAsciiRepresentation()) {
8875    // Check old map is not symbol or long.
8876    CHECK(string->map() == i::Heap::external_ascii_string_map());
8877    // Morph external string to be TwoByte string.
8878    string->set_map(i::Heap::external_string_map());
8879    i::ExternalTwoByteString* morphed =
8880         i::ExternalTwoByteString::cast(string);
8881    morphed->set_resource(uc16_resource);
8882  } else {
8883    // Check old map is not symbol or long.
8884    CHECK(string->map() == i::Heap::external_string_map());
8885    // Morph external string to be ASCII string.
8886    string->set_map(i::Heap::external_ascii_string_map());
8887    i::ExternalAsciiString* morphed =
8888         i::ExternalAsciiString::cast(string);
8889    morphed->set_resource(ascii_resource);
8890  }
8891}
8892
8893
8894// Test that we can still flatten a string if the components it is built up
8895// from have been turned into 16 bit strings in the mean time.
8896THREADED_TEST(MorphCompositeStringTest) {
8897  const char* c_string = "Now is the time for all good men"
8898                         " to come to the aid of the party";
8899  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8900  {
8901    v8::HandleScope scope;
8902    LocalContext env;
8903    AsciiVectorResource ascii_resource(
8904        i::Vector<const char>(c_string, i::StrLength(c_string)));
8905    UC16VectorResource uc16_resource(
8906        i::Vector<const uint16_t>(two_byte_string,
8907                                  i::StrLength(c_string)));
8908
8909    Local<String> lhs(v8::Utils::ToLocal(
8910        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8911    Local<String> rhs(v8::Utils::ToLocal(
8912        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8913
8914    env->Global()->Set(v8_str("lhs"), lhs);
8915    env->Global()->Set(v8_str("rhs"), rhs);
8916
8917    CompileRun(
8918        "var cons = lhs + rhs;"
8919        "var slice = lhs.substring(1, lhs.length - 1);"
8920        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8921
8922    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8923    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8924
8925    // Now do some stuff to make sure the strings are flattened, etc.
8926    CompileRun(
8927        "/[^a-z]/.test(cons);"
8928        "/[^a-z]/.test(slice);"
8929        "/[^a-z]/.test(slice_on_cons);");
8930    const char* expected_cons =
8931        "Now is the time for all good men to come to the aid of the party"
8932        "Now is the time for all good men to come to the aid of the party";
8933    const char* expected_slice =
8934        "ow is the time for all good men to come to the aid of the part";
8935    const char* expected_slice_on_cons =
8936        "ow is the time for all good men to come to the aid of the party"
8937        "Now is the time for all good men to come to the aid of the part";
8938    CHECK_EQ(String::New(expected_cons),
8939             env->Global()->Get(v8_str("cons")));
8940    CHECK_EQ(String::New(expected_slice),
8941             env->Global()->Get(v8_str("slice")));
8942    CHECK_EQ(String::New(expected_slice_on_cons),
8943             env->Global()->Get(v8_str("slice_on_cons")));
8944  }
8945}
8946
8947
8948TEST(CompileExternalTwoByteSource) {
8949  v8::HandleScope scope;
8950  LocalContext context;
8951
8952  // This is a very short list of sources, which currently is to check for a
8953  // regression caused by r2703.
8954  const char* ascii_sources[] = {
8955    "0.5",
8956    "-0.5",   // This mainly testes PushBack in the Scanner.
8957    "--0.5",  // This mainly testes PushBack in the Scanner.
8958    NULL
8959  };
8960
8961  // Compile the sources as external two byte strings.
8962  for (int i = 0; ascii_sources[i] != NULL; i++) {
8963    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8964    UC16VectorResource uc16_resource(
8965        i::Vector<const uint16_t>(two_byte_string,
8966                                  i::StrLength(ascii_sources[i])));
8967    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8968    v8::Script::Compile(source);
8969  }
8970}
8971
8972
8973class RegExpStringModificationTest {
8974 public:
8975  RegExpStringModificationTest()
8976      : block_(i::OS::CreateSemaphore(0)),
8977        morphs_(0),
8978        morphs_during_regexp_(0),
8979        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8980        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
8981  ~RegExpStringModificationTest() { delete block_; }
8982  void RunTest() {
8983    regexp_success_ = false;
8984    morph_success_ = false;
8985
8986    // Initialize the contents of two_byte_content_ to be a uc16 representation
8987    // of "aaaaaaaaaaaaaab".
8988    for (int i = 0; i < 14; i++) {
8989      two_byte_content_[i] = 'a';
8990    }
8991    two_byte_content_[14] = 'b';
8992
8993    // Create the input string for the regexp - the one we are going to change
8994    // properties of.
8995    input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8996
8997    // Inject the input as a global variable.
8998    i::Handle<i::String> input_name =
8999        i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
9000    i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
9001
9002
9003    MorphThread morph_thread(this);
9004    morph_thread.Start();
9005    v8::Locker::StartPreemption(1);
9006    LongRunningRegExp();
9007    {
9008      v8::Unlocker unlock;
9009      morph_thread.Join();
9010    }
9011    v8::Locker::StopPreemption();
9012    CHECK(regexp_success_);
9013    CHECK(morph_success_);
9014  }
9015 private:
9016
9017  // Number of string modifications required.
9018  static const int kRequiredModifications = 5;
9019  static const int kMaxModifications = 100;
9020
9021  class MorphThread : public i::Thread {
9022   public:
9023    explicit MorphThread(RegExpStringModificationTest* test)
9024        : test_(test) {}
9025    virtual void Run() {
9026      test_->MorphString();
9027    }
9028   private:
9029     RegExpStringModificationTest* test_;
9030  };
9031
9032  void MorphString() {
9033    block_->Wait();
9034    while (morphs_during_regexp_ < kRequiredModifications &&
9035           morphs_ < kMaxModifications) {
9036      {
9037        v8::Locker lock;
9038        // Swap string between ascii and two-byte representation.
9039        i::String* string = *input_;
9040        MorphAString(string, &ascii_resource_, &uc16_resource_);
9041        morphs_++;
9042      }
9043      i::OS::Sleep(1);
9044    }
9045    morph_success_ = true;
9046  }
9047
9048  void LongRunningRegExp() {
9049    block_->Signal();  // Enable morphing thread on next preemption.
9050    while (morphs_during_regexp_ < kRequiredModifications &&
9051           morphs_ < kMaxModifications) {
9052      int morphs_before = morphs_;
9053      {
9054        // Match 15-30 "a"'s against 14 and a "b".
9055        const char* c_source =
9056            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9057            ".exec(input) === null";
9058        Local<String> source = String::New(c_source);
9059        Local<Script> script = Script::Compile(source);
9060        Local<Value> result = script->Run();
9061        CHECK(result->IsTrue());
9062      }
9063      int morphs_after = morphs_;
9064      morphs_during_regexp_ += morphs_after - morphs_before;
9065    }
9066    regexp_success_ = true;
9067  }
9068
9069  i::uc16 two_byte_content_[15];
9070  i::Semaphore* block_;
9071  int morphs_;
9072  int morphs_during_regexp_;
9073  bool regexp_success_;
9074  bool morph_success_;
9075  i::Handle<i::String> input_;
9076  AsciiVectorResource ascii_resource_;
9077  UC16VectorResource uc16_resource_;
9078};
9079
9080
9081// Test that a regular expression execution can be interrupted and
9082// the string changed without failing.
9083TEST(RegExpStringModification) {
9084  v8::Locker lock;
9085  v8::V8::Initialize();
9086  v8::HandleScope scope;
9087  Local<Context> local_env;
9088  {
9089    LocalContext env;
9090    local_env = env.local();
9091  }
9092
9093  // Local context should still be live.
9094  CHECK(!local_env.IsEmpty());
9095  local_env->Enter();
9096
9097  // Should complete without problems.
9098  RegExpStringModificationTest().RunTest();
9099
9100  local_env->Exit();
9101}
9102
9103
9104// Test that we can set a property on the global object even if there
9105// is a read-only property in the prototype chain.
9106TEST(ReadOnlyPropertyInGlobalProto) {
9107  v8::HandleScope scope;
9108  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9109  LocalContext context(0, templ);
9110  v8::Handle<v8::Object> global = context->Global();
9111  v8::Handle<v8::Object> global_proto =
9112      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9113  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9114  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9115  // Check without 'eval' or 'with'.
9116  v8::Handle<v8::Value> res =
9117      CompileRun("function f() { x = 42; return x; }; f()");
9118  // Check with 'eval'.
9119  res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9120  CHECK_EQ(v8::Integer::New(42), res);
9121  // Check with 'with'.
9122  res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9123  CHECK_EQ(v8::Integer::New(42), res);
9124}
9125
9126static int force_set_set_count = 0;
9127static int force_set_get_count = 0;
9128bool pass_on_get = false;
9129
9130static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9131                                            const v8::AccessorInfo& info) {
9132  force_set_get_count++;
9133  if (pass_on_get) {
9134    return v8::Handle<v8::Value>();
9135  } else {
9136    return v8::Int32::New(3);
9137  }
9138}
9139
9140static void ForceSetSetter(v8::Local<v8::String> name,
9141                           v8::Local<v8::Value> value,
9142                           const v8::AccessorInfo& info) {
9143  force_set_set_count++;
9144}
9145
9146static v8::Handle<v8::Value> ForceSetInterceptSetter(
9147    v8::Local<v8::String> name,
9148    v8::Local<v8::Value> value,
9149    const v8::AccessorInfo& info) {
9150  force_set_set_count++;
9151  return v8::Undefined();
9152}
9153
9154TEST(ForceSet) {
9155  force_set_get_count = 0;
9156  force_set_set_count = 0;
9157  pass_on_get = false;
9158
9159  v8::HandleScope scope;
9160  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9161  v8::Handle<v8::String> access_property = v8::String::New("a");
9162  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9163  LocalContext context(NULL, templ);
9164  v8::Handle<v8::Object> global = context->Global();
9165
9166  // Ordinary properties
9167  v8::Handle<v8::String> simple_property = v8::String::New("p");
9168  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9169  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9170  // This should fail because the property is read-only
9171  global->Set(simple_property, v8::Int32::New(5));
9172  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9173  // This should succeed even though the property is read-only
9174  global->ForceSet(simple_property, v8::Int32::New(6));
9175  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9176
9177  // Accessors
9178  CHECK_EQ(0, force_set_set_count);
9179  CHECK_EQ(0, force_set_get_count);
9180  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9181  // CHECK_EQ the property shouldn't override it, just call the setter
9182  // which in this case does nothing.
9183  global->Set(access_property, v8::Int32::New(7));
9184  CHECK_EQ(3, global->Get(access_property)->Int32Value());
9185  CHECK_EQ(1, force_set_set_count);
9186  CHECK_EQ(2, force_set_get_count);
9187  // Forcing the property to be set should override the accessor without
9188  // calling it
9189  global->ForceSet(access_property, v8::Int32::New(8));
9190  CHECK_EQ(8, global->Get(access_property)->Int32Value());
9191  CHECK_EQ(1, force_set_set_count);
9192  CHECK_EQ(2, force_set_get_count);
9193}
9194
9195TEST(ForceSetWithInterceptor) {
9196  force_set_get_count = 0;
9197  force_set_set_count = 0;
9198  pass_on_get = false;
9199
9200  v8::HandleScope scope;
9201  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9202  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9203  LocalContext context(NULL, templ);
9204  v8::Handle<v8::Object> global = context->Global();
9205
9206  v8::Handle<v8::String> some_property = v8::String::New("a");
9207  CHECK_EQ(0, force_set_set_count);
9208  CHECK_EQ(0, force_set_get_count);
9209  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9210  // Setting the property shouldn't override it, just call the setter
9211  // which in this case does nothing.
9212  global->Set(some_property, v8::Int32::New(7));
9213  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9214  CHECK_EQ(1, force_set_set_count);
9215  CHECK_EQ(2, force_set_get_count);
9216  // Getting the property when the interceptor returns an empty handle
9217  // should yield undefined, since the property isn't present on the
9218  // object itself yet.
9219  pass_on_get = true;
9220  CHECK(global->Get(some_property)->IsUndefined());
9221  CHECK_EQ(1, force_set_set_count);
9222  CHECK_EQ(3, force_set_get_count);
9223  // Forcing the property to be set should cause the value to be
9224  // set locally without calling the interceptor.
9225  global->ForceSet(some_property, v8::Int32::New(8));
9226  CHECK_EQ(8, global->Get(some_property)->Int32Value());
9227  CHECK_EQ(1, force_set_set_count);
9228  CHECK_EQ(4, force_set_get_count);
9229  // Reenabling the interceptor should cause it to take precedence over
9230  // the property
9231  pass_on_get = false;
9232  CHECK_EQ(3, global->Get(some_property)->Int32Value());
9233  CHECK_EQ(1, force_set_set_count);
9234  CHECK_EQ(5, force_set_get_count);
9235  // The interceptor should also work for other properties
9236  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9237  CHECK_EQ(1, force_set_set_count);
9238  CHECK_EQ(6, force_set_get_count);
9239}
9240
9241
9242THREADED_TEST(ForceDelete) {
9243  v8::HandleScope scope;
9244  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9245  LocalContext context(NULL, templ);
9246  v8::Handle<v8::Object> global = context->Global();
9247
9248  // Ordinary properties
9249  v8::Handle<v8::String> simple_property = v8::String::New("p");
9250  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9251  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9252  // This should fail because the property is dont-delete.
9253  CHECK(!global->Delete(simple_property));
9254  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9255  // This should succeed even though the property is dont-delete.
9256  CHECK(global->ForceDelete(simple_property));
9257  CHECK(global->Get(simple_property)->IsUndefined());
9258}
9259
9260
9261static int force_delete_interceptor_count = 0;
9262static bool pass_on_delete = false;
9263
9264
9265static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9266    v8::Local<v8::String> name,
9267    const v8::AccessorInfo& info) {
9268  force_delete_interceptor_count++;
9269  if (pass_on_delete) {
9270    return v8::Handle<v8::Boolean>();
9271  } else {
9272    return v8::True();
9273  }
9274}
9275
9276
9277THREADED_TEST(ForceDeleteWithInterceptor) {
9278  force_delete_interceptor_count = 0;
9279  pass_on_delete = false;
9280
9281  v8::HandleScope scope;
9282  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9283  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9284  LocalContext context(NULL, templ);
9285  v8::Handle<v8::Object> global = context->Global();
9286
9287  v8::Handle<v8::String> some_property = v8::String::New("a");
9288  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9289
9290  // Deleting a property should get intercepted and nothing should
9291  // happen.
9292  CHECK_EQ(0, force_delete_interceptor_count);
9293  CHECK(global->Delete(some_property));
9294  CHECK_EQ(1, force_delete_interceptor_count);
9295  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9296  // Deleting the property when the interceptor returns an empty
9297  // handle should not delete the property since it is DontDelete.
9298  pass_on_delete = true;
9299  CHECK(!global->Delete(some_property));
9300  CHECK_EQ(2, force_delete_interceptor_count);
9301  CHECK_EQ(42, global->Get(some_property)->Int32Value());
9302  // Forcing the property to be deleted should delete the value
9303  // without calling the interceptor.
9304  CHECK(global->ForceDelete(some_property));
9305  CHECK(global->Get(some_property)->IsUndefined());
9306  CHECK_EQ(2, force_delete_interceptor_count);
9307}
9308
9309
9310// Make sure that forcing a delete invalidates any IC stubs, so we
9311// don't read the hole value.
9312THREADED_TEST(ForceDeleteIC) {
9313  v8::HandleScope scope;
9314  LocalContext context;
9315  // Create a DontDelete variable on the global object.
9316  CompileRun("this.__proto__ = { foo: 'horse' };"
9317             "var foo = 'fish';"
9318             "function f() { return foo.length; }");
9319  // Initialize the IC for foo in f.
9320  CompileRun("for (var i = 0; i < 4; i++) f();");
9321  // Make sure the value of foo is correct before the deletion.
9322  CHECK_EQ(4, CompileRun("f()")->Int32Value());
9323  // Force the deletion of foo.
9324  CHECK(context->Global()->ForceDelete(v8_str("foo")));
9325  // Make sure the value for foo is read from the prototype, and that
9326  // we don't get in trouble with reading the deleted cell value
9327  // sentinel.
9328  CHECK_EQ(5, CompileRun("f()")->Int32Value());
9329}
9330
9331
9332v8::Persistent<Context> calling_context0;
9333v8::Persistent<Context> calling_context1;
9334v8::Persistent<Context> calling_context2;
9335
9336
9337// Check that the call to the callback is initiated in
9338// calling_context2, the directly calling context is calling_context1
9339// and the callback itself is in calling_context0.
9340static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9341  ApiTestFuzzer::Fuzz();
9342  CHECK(Context::GetCurrent() == calling_context0);
9343  CHECK(Context::GetCalling() == calling_context1);
9344  CHECK(Context::GetEntered() == calling_context2);
9345  return v8::Integer::New(42);
9346}
9347
9348
9349THREADED_TEST(GetCallingContext) {
9350  v8::HandleScope scope;
9351
9352  calling_context0 = Context::New();
9353  calling_context1 = Context::New();
9354  calling_context2 = Context::New();
9355
9356  // Allow cross-domain access.
9357  Local<String> token = v8_str("<security token>");
9358  calling_context0->SetSecurityToken(token);
9359  calling_context1->SetSecurityToken(token);
9360  calling_context2->SetSecurityToken(token);
9361
9362  // Create an object with a C++ callback in context0.
9363  calling_context0->Enter();
9364  Local<v8::FunctionTemplate> callback_templ =
9365      v8::FunctionTemplate::New(GetCallingContextCallback);
9366  calling_context0->Global()->Set(v8_str("callback"),
9367                                  callback_templ->GetFunction());
9368  calling_context0->Exit();
9369
9370  // Expose context0 in context1 and setup a function that calls the
9371  // callback function.
9372  calling_context1->Enter();
9373  calling_context1->Global()->Set(v8_str("context0"),
9374                                  calling_context0->Global());
9375  CompileRun("function f() { context0.callback() }");
9376  calling_context1->Exit();
9377
9378  // Expose context1 in context2 and call the callback function in
9379  // context0 indirectly through f in context1.
9380  calling_context2->Enter();
9381  calling_context2->Global()->Set(v8_str("context1"),
9382                                  calling_context1->Global());
9383  CompileRun("context1.f()");
9384  calling_context2->Exit();
9385
9386  // Dispose the contexts to allow them to be garbage collected.
9387  calling_context0.Dispose();
9388  calling_context1.Dispose();
9389  calling_context2.Dispose();
9390  calling_context0.Clear();
9391  calling_context1.Clear();
9392  calling_context2.Clear();
9393}
9394
9395
9396// Check that a variable declaration with no explicit initialization
9397// value does not shadow an existing property in the prototype chain.
9398//
9399// This is consistent with Firefox and Safari.
9400//
9401// See http://crbug.com/12548.
9402THREADED_TEST(InitGlobalVarInProtoChain) {
9403  v8::HandleScope scope;
9404  LocalContext context;
9405  // Introduce a variable in the prototype chain.
9406  CompileRun("__proto__.x = 42");
9407  v8::Handle<v8::Value> result = CompileRun("var x; x");
9408  CHECK(!result->IsUndefined());
9409  CHECK_EQ(42, result->Int32Value());
9410}
9411
9412
9413// Regression test for issue 398.
9414// If a function is added to an object, creating a constant function
9415// field, and the result is cloned, replacing the constant function on the
9416// original should not affect the clone.
9417// See http://code.google.com/p/v8/issues/detail?id=398
9418THREADED_TEST(ReplaceConstantFunction) {
9419  v8::HandleScope scope;
9420  LocalContext context;
9421  v8::Handle<v8::Object> obj = v8::Object::New();
9422  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
9423  v8::Handle<v8::String> foo_string = v8::String::New("foo");
9424  obj->Set(foo_string, func_templ->GetFunction());
9425  v8::Handle<v8::Object> obj_clone = obj->Clone();
9426  obj_clone->Set(foo_string, v8::String::New("Hello"));
9427  CHECK(!obj->Get(foo_string)->IsUndefined());
9428}
9429
9430
9431// Regression test for http://crbug.com/16276.
9432THREADED_TEST(Regress16276) {
9433  v8::HandleScope scope;
9434  LocalContext context;
9435  // Force the IC in f to be a dictionary load IC.
9436  CompileRun("function f(obj) { return obj.x; }\n"
9437             "var obj = { x: { foo: 42 }, y: 87 };\n"
9438             "var x = obj.x;\n"
9439             "delete obj.y;\n"
9440             "for (var i = 0; i < 5; i++) f(obj);");
9441  // Detach the global object to make 'this' refer directly to the
9442  // global object (not the proxy), and make sure that the dictionary
9443  // load IC doesn't mess up loading directly from the global object.
9444  context->DetachGlobal();
9445  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
9446}
9447
9448
9449THREADED_TEST(PixelArray) {
9450  v8::HandleScope scope;
9451  LocalContext context;
9452  const int kElementCount = 260;
9453  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
9454  i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
9455                                                              pixel_data);
9456  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9457  for (int i = 0; i < kElementCount; i++) {
9458    pixels->set(i, i % 256);
9459  }
9460  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9461  for (int i = 0; i < kElementCount; i++) {
9462    CHECK_EQ(i % 256, pixels->get(i));
9463    CHECK_EQ(i % 256, pixel_data[i]);
9464  }
9465
9466  v8::Handle<v8::Object> obj = v8::Object::New();
9467  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9468  // Set the elements to be the pixels.
9469  // jsobj->set_elements(*pixels);
9470  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
9471  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9472  obj->Set(v8_str("field"), v8::Int32::New(1503));
9473  context->Global()->Set(v8_str("pixels"), obj);
9474  v8::Handle<v8::Value> result = CompileRun("pixels.field");
9475  CHECK_EQ(1503, result->Int32Value());
9476  result = CompileRun("pixels[1]");
9477  CHECK_EQ(1, result->Int32Value());
9478
9479  result = CompileRun("var sum = 0;"
9480                      "for (var i = 0; i < 8; i++) {"
9481                      "  sum += pixels[i] = pixels[i] = -i;"
9482                      "}"
9483                      "sum;");
9484  CHECK_EQ(-28, result->Int32Value());
9485
9486  result = CompileRun("var sum = 0;"
9487                      "for (var i = 0; i < 8; i++) {"
9488                      "  sum += pixels[i] = pixels[i] = 0;"
9489                      "}"
9490                      "sum;");
9491  CHECK_EQ(0, result->Int32Value());
9492
9493  result = CompileRun("var sum = 0;"
9494                      "for (var i = 0; i < 8; i++) {"
9495                      "  sum += pixels[i] = pixels[i] = 255;"
9496                      "}"
9497                      "sum;");
9498  CHECK_EQ(8 * 255, result->Int32Value());
9499
9500  result = CompileRun("var sum = 0;"
9501                      "for (var i = 0; i < 8; i++) {"
9502                      "  sum += pixels[i] = pixels[i] = 256 + i;"
9503                      "}"
9504                      "sum;");
9505  CHECK_EQ(2076, result->Int32Value());
9506
9507  result = CompileRun("var sum = 0;"
9508                      "for (var i = 0; i < 8; i++) {"
9509                      "  sum += pixels[i] = pixels[i] = i;"
9510                      "}"
9511                      "sum;");
9512  CHECK_EQ(28, result->Int32Value());
9513
9514  result = CompileRun("var sum = 0;"
9515                      "for (var i = 0; i < 8; i++) {"
9516                      "  sum += pixels[i];"
9517                      "}"
9518                      "sum;");
9519  CHECK_EQ(28, result->Int32Value());
9520
9521  i::Handle<i::Smi> value(i::Smi::FromInt(2));
9522  i::SetElement(jsobj, 1, value);
9523  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9524  *value.location() = i::Smi::FromInt(256);
9525  i::SetElement(jsobj, 1, value);
9526  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9527  *value.location() = i::Smi::FromInt(-1);
9528  i::SetElement(jsobj, 1, value);
9529  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9530
9531  result = CompileRun("for (var i = 0; i < 8; i++) {"
9532                      "  pixels[i] = (i * 65) - 109;"
9533                      "}"
9534                      "pixels[1] + pixels[6];");
9535  CHECK_EQ(255, result->Int32Value());
9536  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9537  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9538  CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9539  CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9540  CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9541  CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9542  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9543  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9544  result = CompileRun("var sum = 0;"
9545                      "for (var i = 0; i < 8; i++) {"
9546                      "  sum += pixels[i];"
9547                      "}"
9548                      "sum;");
9549  CHECK_EQ(984, result->Int32Value());
9550
9551  result = CompileRun("for (var i = 0; i < 8; i++) {"
9552                      "  pixels[i] = (i * 1.1);"
9553                      "}"
9554                      "pixels[1] + pixels[6];");
9555  CHECK_EQ(8, result->Int32Value());
9556  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9557  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9558  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9559  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9560  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9561  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9562  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9563  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9564
9565  result = CompileRun("for (var i = 0; i < 8; i++) {"
9566                      "  pixels[7] = undefined;"
9567                      "}"
9568                      "pixels[7];");
9569  CHECK_EQ(0, result->Int32Value());
9570  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9571
9572  result = CompileRun("for (var i = 0; i < 8; i++) {"
9573                      "  pixels[6] = '2.3';"
9574                      "}"
9575                      "pixels[6];");
9576  CHECK_EQ(2, result->Int32Value());
9577  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9578
9579  result = CompileRun("for (var i = 0; i < 8; i++) {"
9580                      "  pixels[5] = NaN;"
9581                      "}"
9582                      "pixels[5];");
9583  CHECK_EQ(0, result->Int32Value());
9584  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9585
9586  result = CompileRun("for (var i = 0; i < 8; i++) {"
9587                      "  pixels[8] = Infinity;"
9588                      "}"
9589                      "pixels[8];");
9590  CHECK_EQ(255, result->Int32Value());
9591  CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9592
9593  result = CompileRun("for (var i = 0; i < 8; i++) {"
9594                      "  pixels[9] = -Infinity;"
9595                      "}"
9596                      "pixels[9];");
9597  CHECK_EQ(0, result->Int32Value());
9598  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9599
9600  result = CompileRun("pixels[3] = 33;"
9601                      "delete pixels[3];"
9602                      "pixels[3];");
9603  CHECK_EQ(33, result->Int32Value());
9604
9605  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9606                      "pixels[2] = 12; pixels[3] = 13;"
9607                      "pixels.__defineGetter__('2',"
9608                      "function() { return 120; });"
9609                      "pixels[2];");
9610  CHECK_EQ(12, result->Int32Value());
9611
9612  result = CompileRun("var js_array = new Array(40);"
9613                      "js_array[0] = 77;"
9614                      "js_array;");
9615  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9616
9617  result = CompileRun("pixels[1] = 23;"
9618                      "pixels.__proto__ = [];"
9619                      "js_array.__proto__ = pixels;"
9620                      "js_array.concat(pixels);");
9621  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9622  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9623
9624  result = CompileRun("pixels[1] = 23;");
9625  CHECK_EQ(23, result->Int32Value());
9626
9627  // Test for index greater than 255.  Regression test for:
9628  // http://code.google.com/p/chromium/issues/detail?id=26337.
9629  result = CompileRun("pixels[256] = 255;");
9630  CHECK_EQ(255, result->Int32Value());
9631  result = CompileRun("var i = 0;"
9632                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9633                      "i");
9634  CHECK_EQ(255, result->Int32Value());
9635
9636  free(pixel_data);
9637}
9638
9639
9640template <class ExternalArrayClass, class ElementType>
9641static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9642                                    int64_t low,
9643                                    int64_t high) {
9644  v8::HandleScope scope;
9645  LocalContext context;
9646  const int kElementCount = 40;
9647  int element_size = 0;
9648  switch (array_type) {
9649    case v8::kExternalByteArray:
9650    case v8::kExternalUnsignedByteArray:
9651      element_size = 1;
9652      break;
9653    case v8::kExternalShortArray:
9654    case v8::kExternalUnsignedShortArray:
9655      element_size = 2;
9656      break;
9657    case v8::kExternalIntArray:
9658    case v8::kExternalUnsignedIntArray:
9659    case v8::kExternalFloatArray:
9660      element_size = 4;
9661      break;
9662    default:
9663      UNREACHABLE();
9664      break;
9665  }
9666  ElementType* array_data =
9667      static_cast<ElementType*>(malloc(kElementCount * element_size));
9668  i::Handle<ExternalArrayClass> array =
9669      i::Handle<ExternalArrayClass>::cast(
9670          i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9671  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9672  for (int i = 0; i < kElementCount; i++) {
9673    array->set(i, static_cast<ElementType>(i));
9674  }
9675  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9676  for (int i = 0; i < kElementCount; i++) {
9677    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9678    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9679  }
9680
9681  v8::Handle<v8::Object> obj = v8::Object::New();
9682  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9683  // Set the elements to be the external array.
9684  obj->SetIndexedPropertiesToExternalArrayData(array_data,
9685                                               array_type,
9686                                               kElementCount);
9687  CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9688  obj->Set(v8_str("field"), v8::Int32::New(1503));
9689  context->Global()->Set(v8_str("ext_array"), obj);
9690  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9691  CHECK_EQ(1503, result->Int32Value());
9692  result = CompileRun("ext_array[1]");
9693  CHECK_EQ(1, result->Int32Value());
9694
9695  // Check pass through of assigned smis
9696  result = CompileRun("var sum = 0;"
9697                      "for (var i = 0; i < 8; i++) {"
9698                      "  sum += ext_array[i] = ext_array[i] = -i;"
9699                      "}"
9700                      "sum;");
9701  CHECK_EQ(-28, result->Int32Value());
9702
9703  // Check assigned smis
9704  result = CompileRun("for (var i = 0; i < 8; i++) {"
9705                      "  ext_array[i] = i;"
9706                      "}"
9707                      "var sum = 0;"
9708                      "for (var i = 0; i < 8; i++) {"
9709                      "  sum += ext_array[i];"
9710                      "}"
9711                      "sum;");
9712  CHECK_EQ(28, result->Int32Value());
9713
9714  // Check assigned smis in reverse order
9715  result = CompileRun("for (var i = 8; --i >= 0; ) {"
9716                      "  ext_array[i] = i;"
9717                      "}"
9718                      "var sum = 0;"
9719                      "for (var i = 0; i < 8; i++) {"
9720                      "  sum += ext_array[i];"
9721                      "}"
9722                      "sum;");
9723  CHECK_EQ(28, result->Int32Value());
9724
9725  // Check pass through of assigned HeapNumbers
9726  result = CompileRun("var sum = 0;"
9727                      "for (var i = 0; i < 16; i+=2) {"
9728                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9729                      "}"
9730                      "sum;");
9731  CHECK_EQ(-28, result->Int32Value());
9732
9733  // Check assigned HeapNumbers
9734  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9735                      "  ext_array[i] = (i * 0.5);"
9736                      "}"
9737                      "var sum = 0;"
9738                      "for (var i = 0; i < 16; i+=2) {"
9739                      "  sum += ext_array[i];"
9740                      "}"
9741                      "sum;");
9742  CHECK_EQ(28, result->Int32Value());
9743
9744  // Check assigned HeapNumbers in reverse order
9745  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9746                      "  ext_array[i] = (i * 0.5);"
9747                      "}"
9748                      "var sum = 0;"
9749                      "for (var i = 0; i < 16; i+=2) {"
9750                      "  sum += ext_array[i];"
9751                      "}"
9752                      "sum;");
9753  CHECK_EQ(28, result->Int32Value());
9754
9755  i::ScopedVector<char> test_buf(1024);
9756
9757  // Check legal boundary conditions.
9758  // The repeated loads and stores ensure the ICs are exercised.
9759  const char* boundary_program =
9760      "var res = 0;"
9761      "for (var i = 0; i < 16; i++) {"
9762      "  ext_array[i] = %lld;"
9763      "  if (i > 8) {"
9764      "    res = ext_array[i];"
9765      "  }"
9766      "}"
9767      "res;";
9768  i::OS::SNPrintF(test_buf,
9769                  boundary_program,
9770                  low);
9771  result = CompileRun(test_buf.start());
9772  CHECK_EQ(low, result->IntegerValue());
9773
9774  i::OS::SNPrintF(test_buf,
9775                  boundary_program,
9776                  high);
9777  result = CompileRun(test_buf.start());
9778  CHECK_EQ(high, result->IntegerValue());
9779
9780  // Check misprediction of type in IC.
9781  result = CompileRun("var tmp_array = ext_array;"
9782                      "var sum = 0;"
9783                      "for (var i = 0; i < 8; i++) {"
9784                      "  tmp_array[i] = i;"
9785                      "  sum += tmp_array[i];"
9786                      "  if (i == 4) {"
9787                      "    tmp_array = {};"
9788                      "  }"
9789                      "}"
9790                      "sum;");
9791  i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9792  CHECK_EQ(28, result->Int32Value());
9793
9794  // Make sure out-of-range loads do not throw.
9795  i::OS::SNPrintF(test_buf,
9796                  "var caught_exception = false;"
9797                  "try {"
9798                  "  ext_array[%d];"
9799                  "} catch (e) {"
9800                  "  caught_exception = true;"
9801                  "}"
9802                  "caught_exception;",
9803                  kElementCount);
9804  result = CompileRun(test_buf.start());
9805  CHECK_EQ(false, result->BooleanValue());
9806
9807  // Make sure out-of-range stores do not throw.
9808  i::OS::SNPrintF(test_buf,
9809                  "var caught_exception = false;"
9810                  "try {"
9811                  "  ext_array[%d] = 1;"
9812                  "} catch (e) {"
9813                  "  caught_exception = true;"
9814                  "}"
9815                  "caught_exception;",
9816                  kElementCount);
9817  result = CompileRun(test_buf.start());
9818  CHECK_EQ(false, result->BooleanValue());
9819
9820  // Check other boundary conditions, values and operations.
9821  result = CompileRun("for (var i = 0; i < 8; i++) {"
9822                      "  ext_array[7] = undefined;"
9823                      "}"
9824                      "ext_array[7];");
9825  CHECK_EQ(0, result->Int32Value());
9826  CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9827
9828  result = CompileRun("for (var i = 0; i < 8; i++) {"
9829                      "  ext_array[6] = '2.3';"
9830                      "}"
9831                      "ext_array[6];");
9832  CHECK_EQ(2, result->Int32Value());
9833  CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9834
9835  if (array_type != v8::kExternalFloatArray) {
9836    // Though the specification doesn't state it, be explicit about
9837    // converting NaNs and +/-Infinity to zero.
9838    result = CompileRun("for (var i = 0; i < 8; i++) {"
9839                        "  ext_array[i] = 5;"
9840                        "}"
9841                        "for (var i = 0; i < 8; i++) {"
9842                        "  ext_array[i] = NaN;"
9843                        "}"
9844                        "ext_array[5];");
9845    CHECK_EQ(0, result->Int32Value());
9846    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9847
9848    result = CompileRun("for (var i = 0; i < 8; i++) {"
9849                        "  ext_array[i] = 5;"
9850                        "}"
9851                        "for (var i = 0; i < 8; i++) {"
9852                        "  ext_array[i] = Infinity;"
9853                        "}"
9854                        "ext_array[5];");
9855    CHECK_EQ(0, result->Int32Value());
9856    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9857
9858    result = CompileRun("for (var i = 0; i < 8; i++) {"
9859                        "  ext_array[i] = 5;"
9860                        "}"
9861                        "for (var i = 0; i < 8; i++) {"
9862                        "  ext_array[i] = -Infinity;"
9863                        "}"
9864                        "ext_array[5];");
9865    CHECK_EQ(0, result->Int32Value());
9866    CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9867  }
9868
9869  result = CompileRun("ext_array[3] = 33;"
9870                      "delete ext_array[3];"
9871                      "ext_array[3];");
9872  CHECK_EQ(33, result->Int32Value());
9873
9874  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9875                      "ext_array[2] = 12; ext_array[3] = 13;"
9876                      "ext_array.__defineGetter__('2',"
9877                      "function() { return 120; });"
9878                      "ext_array[2];");
9879  CHECK_EQ(12, result->Int32Value());
9880
9881  result = CompileRun("var js_array = new Array(40);"
9882                      "js_array[0] = 77;"
9883                      "js_array;");
9884  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9885
9886  result = CompileRun("ext_array[1] = 23;"
9887                      "ext_array.__proto__ = [];"
9888                      "js_array.__proto__ = ext_array;"
9889                      "js_array.concat(ext_array);");
9890  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9891  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9892
9893  result = CompileRun("ext_array[1] = 23;");
9894  CHECK_EQ(23, result->Int32Value());
9895
9896  // Test more complex manipulations which cause eax to contain values
9897  // that won't be completely overwritten by loads from the arrays.
9898  // This catches bugs in the instructions used for the KeyedLoadIC
9899  // for byte and word types.
9900  {
9901    const int kXSize = 300;
9902    const int kYSize = 300;
9903    const int kLargeElementCount = kXSize * kYSize * 4;
9904    ElementType* large_array_data =
9905        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9906    i::Handle<ExternalArrayClass> large_array =
9907        i::Handle<ExternalArrayClass>::cast(
9908            i::Factory::NewExternalArray(kLargeElementCount,
9909                                         array_type,
9910                                         array_data));
9911    v8::Handle<v8::Object> large_obj = v8::Object::New();
9912    // Set the elements to be the external array.
9913    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9914                                                       array_type,
9915                                                       kLargeElementCount);
9916    context->Global()->Set(v8_str("large_array"), large_obj);
9917    // Initialize contents of a few rows.
9918    for (int x = 0; x < 300; x++) {
9919      int row = 0;
9920      int offset = row * 300 * 4;
9921      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9922      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9923      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9924      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9925      row = 150;
9926      offset = row * 300 * 4;
9927      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9928      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9929      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9930      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9931      row = 298;
9932      offset = row * 300 * 4;
9933      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9934      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9935      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9936      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9937    }
9938    // The goal of the code below is to make "offset" large enough
9939    // that the computation of the index (which goes into eax) has
9940    // high bits set which will not be overwritten by a byte or short
9941    // load.
9942    result = CompileRun("var failed = false;"
9943                        "var offset = 0;"
9944                        "for (var i = 0; i < 300; i++) {"
9945                        "  if (large_array[4 * i] != 127 ||"
9946                        "      large_array[4 * i + 1] != 0 ||"
9947                        "      large_array[4 * i + 2] != 0 ||"
9948                        "      large_array[4 * i + 3] != 127) {"
9949                        "    failed = true;"
9950                        "  }"
9951                        "}"
9952                        "offset = 150 * 300 * 4;"
9953                        "for (var i = 0; i < 300; i++) {"
9954                        "  if (large_array[offset + 4 * i] != 127 ||"
9955                        "      large_array[offset + 4 * i + 1] != 0 ||"
9956                        "      large_array[offset + 4 * i + 2] != 0 ||"
9957                        "      large_array[offset + 4 * i + 3] != 127) {"
9958                        "    failed = true;"
9959                        "  }"
9960                        "}"
9961                        "offset = 298 * 300 * 4;"
9962                        "for (var i = 0; i < 300; i++) {"
9963                        "  if (large_array[offset + 4 * i] != 127 ||"
9964                        "      large_array[offset + 4 * i + 1] != 0 ||"
9965                        "      large_array[offset + 4 * i + 2] != 0 ||"
9966                        "      large_array[offset + 4 * i + 3] != 127) {"
9967                        "    failed = true;"
9968                        "  }"
9969                        "}"
9970                        "!failed;");
9971    CHECK_EQ(true, result->BooleanValue());
9972    free(large_array_data);
9973  }
9974
9975  free(array_data);
9976}
9977
9978
9979THREADED_TEST(ExternalByteArray) {
9980  ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
9981      v8::kExternalByteArray,
9982      -128,
9983      127);
9984}
9985
9986
9987THREADED_TEST(ExternalUnsignedByteArray) {
9988  ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
9989      v8::kExternalUnsignedByteArray,
9990      0,
9991      255);
9992}
9993
9994
9995THREADED_TEST(ExternalShortArray) {
9996  ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
9997      v8::kExternalShortArray,
9998      -32768,
9999      32767);
10000}
10001
10002
10003THREADED_TEST(ExternalUnsignedShortArray) {
10004  ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
10005      v8::kExternalUnsignedShortArray,
10006      0,
10007      65535);
10008}
10009
10010
10011THREADED_TEST(ExternalIntArray) {
10012  ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
10013      v8::kExternalIntArray,
10014      INT_MIN,   // -2147483648
10015      INT_MAX);  //  2147483647
10016}
10017
10018
10019THREADED_TEST(ExternalUnsignedIntArray) {
10020  ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
10021      v8::kExternalUnsignedIntArray,
10022      0,
10023      UINT_MAX);  // 4294967295
10024}
10025
10026
10027THREADED_TEST(ExternalFloatArray) {
10028  ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
10029      v8::kExternalFloatArray,
10030      -500,
10031      500);
10032}
10033
10034
10035THREADED_TEST(ExternalArrays) {
10036  TestExternalByteArray();
10037  TestExternalUnsignedByteArray();
10038  TestExternalShortArray();
10039  TestExternalUnsignedShortArray();
10040  TestExternalIntArray();
10041  TestExternalUnsignedIntArray();
10042  TestExternalFloatArray();
10043}
10044
10045
10046THREADED_TEST(ScriptContextDependence) {
10047  v8::HandleScope scope;
10048  LocalContext c1;
10049  const char *source = "foo";
10050  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10051  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10052  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10053  CHECK_EQ(dep->Run()->Int32Value(), 100);
10054  CHECK_EQ(indep->Run()->Int32Value(), 100);
10055  LocalContext c2;
10056  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10057  CHECK_EQ(dep->Run()->Int32Value(), 100);
10058  CHECK_EQ(indep->Run()->Int32Value(), 101);
10059}
10060
10061
10062THREADED_TEST(StackTrace) {
10063  v8::HandleScope scope;
10064  LocalContext context;
10065  v8::TryCatch try_catch;
10066  const char *source = "function foo() { FAIL.FAIL; }; foo();";
10067  v8::Handle<v8::String> src = v8::String::New(source);
10068  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10069  v8::Script::New(src, origin)->Run();
10070  CHECK(try_catch.HasCaught());
10071  v8::String::Utf8Value stack(try_catch.StackTrace());
10072  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10073}
10074
10075
10076// Checks that a StackFrame has certain expected values.
10077void checkStackFrame(const char* expected_script_name,
10078    const char* expected_func_name, int expected_line_number,
10079    int expected_column, bool is_eval, bool is_constructor,
10080    v8::Handle<v8::StackFrame> frame) {
10081  v8::HandleScope scope;
10082  v8::String::Utf8Value func_name(frame->GetFunctionName());
10083  v8::String::Utf8Value script_name(frame->GetScriptName());
10084  if (*script_name == NULL) {
10085    // The situation where there is no associated script, like for evals.
10086    CHECK(expected_script_name == NULL);
10087  } else {
10088    CHECK(strstr(*script_name, expected_script_name) != NULL);
10089  }
10090  CHECK(strstr(*func_name, expected_func_name) != NULL);
10091  CHECK_EQ(expected_line_number, frame->GetLineNumber());
10092  CHECK_EQ(expected_column, frame->GetColumn());
10093  CHECK_EQ(is_eval, frame->IsEval());
10094  CHECK_EQ(is_constructor, frame->IsConstructor());
10095}
10096
10097
10098v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10099  v8::HandleScope scope;
10100  const char* origin = "capture-stack-trace-test";
10101  const int kOverviewTest = 1;
10102  const int kDetailedTest = 2;
10103
10104  ASSERT(args.Length() == 1);
10105
10106  int testGroup = args[0]->Int32Value();
10107  if (testGroup == kOverviewTest) {
10108    v8::Handle<v8::StackTrace> stackTrace =
10109        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10110    CHECK_EQ(4, stackTrace->GetFrameCount());
10111    checkStackFrame(origin, "bar", 2, 10, false, false,
10112                    stackTrace->GetFrame(0));
10113    checkStackFrame(origin, "foo", 6, 3, false, false,
10114                    stackTrace->GetFrame(1));
10115    checkStackFrame(NULL, "", 1, 1, false, false,
10116                    stackTrace->GetFrame(2));
10117    // The last frame is an anonymous function that has the initial call.
10118    checkStackFrame(origin, "", 8, 7, false, false,
10119                    stackTrace->GetFrame(3));
10120
10121    CHECK(stackTrace->AsArray()->IsArray());
10122  } else if (testGroup == kDetailedTest) {
10123    v8::Handle<v8::StackTrace> stackTrace =
10124        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10125    CHECK_EQ(4, stackTrace->GetFrameCount());
10126    checkStackFrame(origin, "bat", 4, 22, false, false,
10127                    stackTrace->GetFrame(0));
10128    checkStackFrame(origin, "baz", 8, 3, false, true,
10129                    stackTrace->GetFrame(1));
10130    checkStackFrame(NULL, "", 1, 1, true, false,
10131                    stackTrace->GetFrame(2));
10132    // The last frame is an anonymous function that has the initial call to foo.
10133    checkStackFrame(origin, "", 10, 1, false, false,
10134                    stackTrace->GetFrame(3));
10135
10136    CHECK(stackTrace->AsArray()->IsArray());
10137  }
10138  return v8::Undefined();
10139}
10140
10141
10142// Tests the C++ StackTrace API.
10143THREADED_TEST(CaptureStackTrace) {
10144  v8::HandleScope scope;
10145  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10146  Local<ObjectTemplate> templ = ObjectTemplate::New();
10147  templ->Set(v8_str("AnalyzeStackInNativeCode"),
10148             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10149  LocalContext context(0, templ);
10150
10151  // Test getting OVERVIEW information. Should ignore information that is not
10152  // script name, function name, line number, and column offset.
10153  const char *overview_source =
10154    "function bar() {\n"
10155    "  var y; AnalyzeStackInNativeCode(1);\n"
10156    "}\n"
10157    "function foo() {\n"
10158    "\n"
10159    "  bar();\n"
10160    "}\n"
10161    "var x;eval('new foo();');";
10162  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10163  v8::Handle<Value> overview_result =
10164      v8::Script::New(overview_src, origin)->Run();
10165  ASSERT(!overview_result.IsEmpty());
10166  ASSERT(overview_result->IsObject());
10167
10168  // Test getting DETAILED information.
10169  const char *detailed_source =
10170    "function bat() {AnalyzeStackInNativeCode(2);\n"
10171    "}\n"
10172    "\n"
10173    "function baz() {\n"
10174    "  bat();\n"
10175    "}\n"
10176    "eval('new baz();');";
10177  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10178  // Make the script using a non-zero line and column offset.
10179  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10180  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10181  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10182  v8::Handle<v8::Script> detailed_script(
10183      v8::Script::New(detailed_src, &detailed_origin));
10184  v8::Handle<Value> detailed_result = detailed_script->Run();
10185  ASSERT(!detailed_result.IsEmpty());
10186  ASSERT(detailed_result->IsObject());
10187}
10188
10189
10190// Test that idle notification can be handled and eventually returns true.
10191THREADED_TEST(IdleNotification) {
10192  bool rv = false;
10193  for (int i = 0; i < 100; i++) {
10194    rv = v8::V8::IdleNotification();
10195    if (rv)
10196      break;
10197  }
10198  CHECK(rv == true);
10199}
10200
10201
10202static uint32_t* stack_limit;
10203
10204static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
10205  stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
10206  return v8::Undefined();
10207}
10208
10209
10210// Uses the address of a local variable to determine the stack top now.
10211// Given a size, returns an address that is that far from the current
10212// top of stack.
10213static uint32_t* ComputeStackLimit(uint32_t size) {
10214  uint32_t* answer = &size - (size / sizeof(size));
10215  // If the size is very large and the stack is very near the bottom of
10216  // memory then the calculation above may wrap around and give an address
10217  // that is above the (downwards-growing) stack.  In that case we return
10218  // a very low address.
10219  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
10220  return answer;
10221}
10222
10223
10224TEST(SetResourceConstraints) {
10225  static const int K = 1024;
10226  uint32_t* set_limit = ComputeStackLimit(128 * K);
10227
10228  // Set stack limit.
10229  v8::ResourceConstraints constraints;
10230  constraints.set_stack_limit(set_limit);
10231  CHECK(v8::SetResourceConstraints(&constraints));
10232
10233  // Execute a script.
10234  v8::HandleScope scope;
10235  LocalContext env;
10236  Local<v8::FunctionTemplate> fun_templ =
10237      v8::FunctionTemplate::New(GetStackLimitCallback);
10238  Local<Function> fun = fun_templ->GetFunction();
10239  env->Global()->Set(v8_str("get_stack_limit"), fun);
10240  CompileRun("get_stack_limit();");
10241
10242  CHECK(stack_limit == set_limit);
10243}
10244
10245
10246TEST(SetResourceConstraintsInThread) {
10247  uint32_t* set_limit;
10248  {
10249    v8::Locker locker;
10250    static const int K = 1024;
10251    set_limit = ComputeStackLimit(128 * K);
10252
10253    // Set stack limit.
10254    v8::ResourceConstraints constraints;
10255    constraints.set_stack_limit(set_limit);
10256    CHECK(v8::SetResourceConstraints(&constraints));
10257
10258    // Execute a script.
10259    v8::HandleScope scope;
10260    LocalContext env;
10261    Local<v8::FunctionTemplate> fun_templ =
10262        v8::FunctionTemplate::New(GetStackLimitCallback);
10263    Local<Function> fun = fun_templ->GetFunction();
10264    env->Global()->Set(v8_str("get_stack_limit"), fun);
10265    CompileRun("get_stack_limit();");
10266
10267    CHECK(stack_limit == set_limit);
10268  }
10269  {
10270    v8::Locker locker;
10271    CHECK(stack_limit == set_limit);
10272  }
10273}
10274
10275
10276THREADED_TEST(GetHeapStatistics) {
10277  v8::HandleScope scope;
10278  LocalContext c1;
10279  v8::HeapStatistics heap_statistics;
10280  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
10281  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
10282  v8::V8::GetHeapStatistics(&heap_statistics);
10283  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
10284  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
10285}
10286
10287
10288static double DoubleFromBits(uint64_t value) {
10289  double target;
10290#ifdef BIG_ENDIAN_FLOATING_POINT
10291  const int kIntSize = 4;
10292  // Somebody swapped the lower and higher half of doubles.
10293  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10294  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10295#else
10296  memcpy(&target, &value, sizeof(target));
10297#endif
10298  return target;
10299}
10300
10301
10302static uint64_t DoubleToBits(double value) {
10303  uint64_t target;
10304#ifdef BIG_ENDIAN_FLOATING_POINT
10305  const int kIntSize = 4;
10306  // Somebody swapped the lower and higher half of doubles.
10307  memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
10308  memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
10309#else
10310  memcpy(&target, &value, sizeof(target));
10311#endif
10312  return target;
10313}
10314
10315
10316static double DoubleToDateTime(double input) {
10317  double date_limit = 864e13;
10318  if (IsNaN(input) || input < -date_limit || input > date_limit) {
10319    return i::OS::nan_value();
10320  }
10321  return (input < 0) ? -(floor(-input)) : floor(input);
10322}
10323
10324// We don't have a consistent way to write 64-bit constants syntactically, so we
10325// split them into two 32-bit constants and combine them programmatically.
10326static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
10327  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
10328}
10329
10330
10331THREADED_TEST(QuietSignalingNaNs) {
10332  v8::HandleScope scope;
10333  LocalContext context;
10334  v8::TryCatch try_catch;
10335
10336  // Special double values.
10337  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
10338  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
10339  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
10340  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
10341  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
10342  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
10343  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
10344
10345  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
10346  // on either side of the epoch.
10347  double date_limit = 864e13;
10348
10349  double test_values[] = {
10350      snan,
10351      qnan,
10352      infinity,
10353      max_normal,
10354      date_limit + 1,
10355      date_limit,
10356      min_normal,
10357      max_denormal,
10358      min_denormal,
10359      0,
10360      -0,
10361      -min_denormal,
10362      -max_denormal,
10363      -min_normal,
10364      -date_limit,
10365      -date_limit - 1,
10366      -max_normal,
10367      -infinity,
10368      -qnan,
10369      -snan
10370  };
10371  int num_test_values = 20;
10372
10373  for (int i = 0; i < num_test_values; i++) {
10374    double test_value = test_values[i];
10375
10376    // Check that Number::New preserves non-NaNs and quiets SNaNs.
10377    v8::Handle<v8::Value> number = v8::Number::New(test_value);
10378    double stored_number = number->NumberValue();
10379    if (!IsNaN(test_value)) {
10380      CHECK_EQ(test_value, stored_number);
10381    } else {
10382      uint64_t stored_bits = DoubleToBits(stored_number);
10383      // Check if quiet nan (bits 51..62 all set).
10384      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10385    }
10386
10387    // Check that Date::New preserves non-NaNs in the date range and
10388    // quiets SNaNs.
10389    v8::Handle<v8::Value> date = v8::Date::New(test_value);
10390    double expected_stored_date = DoubleToDateTime(test_value);
10391    double stored_date = date->NumberValue();
10392    if (!IsNaN(expected_stored_date)) {
10393      CHECK_EQ(expected_stored_date, stored_date);
10394    } else {
10395      uint64_t stored_bits = DoubleToBits(stored_date);
10396      // Check if quiet nan (bits 51..62 all set).
10397      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
10398    }
10399  }
10400}
10401
10402
10403static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
10404  v8::HandleScope scope;
10405  v8::TryCatch tc;
10406  v8::Handle<v8::String> str = args[0]->ToString();
10407  if (tc.HasCaught())
10408    return tc.ReThrow();
10409  return v8::Undefined();
10410}
10411
10412
10413// Test that an exception can be propagated down through a spaghetti
10414// stack using ReThrow.
10415THREADED_TEST(SpaghettiStackReThrow) {
10416  v8::HandleScope scope;
10417  LocalContext context;
10418  context->Global()->Set(
10419      v8::String::New("s"),
10420      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
10421  v8::TryCatch try_catch;
10422  CompileRun(
10423      "var i = 0;"
10424      "var o = {"
10425      "  toString: function () {"
10426      "    if (i == 10) {"
10427      "      throw 'Hey!';"
10428      "    } else {"
10429      "      i++;"
10430      "      return s(o);"
10431      "    }"
10432      "  }"
10433      "};"
10434      "s(o);");
10435  CHECK(try_catch.HasCaught());
10436  v8::String::Utf8Value value(try_catch.Exception());
10437  CHECK_EQ(0, strcmp(*value, "Hey!"));
10438}
10439
10440
10441TEST(Regress528) {
10442  v8::V8::Initialize();
10443
10444  v8::HandleScope scope;
10445  v8::Persistent<Context> context;
10446  v8::Persistent<Context> other_context;
10447  int gc_count;
10448
10449  // Create a context used to keep the code from aging in the compilation
10450  // cache.
10451  other_context = Context::New();
10452
10453  // Context-dependent context data creates reference from the compilation
10454  // cache to the global object.
10455  const char* source_simple = "1";
10456  context = Context::New();
10457  {
10458    v8::HandleScope scope;
10459
10460    context->Enter();
10461    Local<v8::String> obj = v8::String::New("");
10462    context->SetData(obj);
10463    CompileRun(source_simple);
10464    context->Exit();
10465  }
10466  context.Dispose();
10467  for (gc_count = 1; gc_count < 10; gc_count++) {
10468    other_context->Enter();
10469    CompileRun(source_simple);
10470    other_context->Exit();
10471    v8::internal::Heap::CollectAllGarbage(false);
10472    if (GetGlobalObjectsCount() == 1) break;
10473  }
10474  CHECK_GE(2, gc_count);
10475  CHECK_EQ(1, GetGlobalObjectsCount());
10476
10477  // Eval in a function creates reference from the compilation cache to the
10478  // global object.
10479  const char* source_eval = "function f(){eval('1')}; f()";
10480  context = Context::New();
10481  {
10482    v8::HandleScope scope;
10483
10484    context->Enter();
10485    CompileRun(source_eval);
10486    context->Exit();
10487  }
10488  context.Dispose();
10489  for (gc_count = 1; gc_count < 10; gc_count++) {
10490    other_context->Enter();
10491    CompileRun(source_eval);
10492    other_context->Exit();
10493    v8::internal::Heap::CollectAllGarbage(false);
10494    if (GetGlobalObjectsCount() == 1) break;
10495  }
10496  CHECK_GE(2, gc_count);
10497  CHECK_EQ(1, GetGlobalObjectsCount());
10498
10499  // Looking up the line number for an exception creates reference from the
10500  // compilation cache to the global object.
10501  const char* source_exception = "function f(){throw 1;} f()";
10502  context = Context::New();
10503  {
10504    v8::HandleScope scope;
10505
10506    context->Enter();
10507    v8::TryCatch try_catch;
10508    CompileRun(source_exception);
10509    CHECK(try_catch.HasCaught());
10510    v8::Handle<v8::Message> message = try_catch.Message();
10511    CHECK(!message.IsEmpty());
10512    CHECK_EQ(1, message->GetLineNumber());
10513    context->Exit();
10514  }
10515  context.Dispose();
10516  for (gc_count = 1; gc_count < 10; gc_count++) {
10517    other_context->Enter();
10518    CompileRun(source_exception);
10519    other_context->Exit();
10520    v8::internal::Heap::CollectAllGarbage(false);
10521    if (GetGlobalObjectsCount() == 1) break;
10522  }
10523  CHECK_GE(2, gc_count);
10524  CHECK_EQ(1, GetGlobalObjectsCount());
10525
10526  other_context.Dispose();
10527}
10528
10529
10530THREADED_TEST(ScriptOrigin) {
10531  v8::HandleScope scope;
10532  LocalContext env;
10533  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10534  v8::Handle<v8::String> script = v8::String::New(
10535      "function f() {}\n\nfunction g() {}");
10536  v8::Script::Compile(script, &origin)->Run();
10537  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10538      env->Global()->Get(v8::String::New("f")));
10539  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10540      env->Global()->Get(v8::String::New("g")));
10541
10542  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10543  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10544  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
10545
10546  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
10547  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
10548  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
10549}
10550
10551
10552THREADED_TEST(ScriptLineNumber) {
10553  v8::HandleScope scope;
10554  LocalContext env;
10555  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10556  v8::Handle<v8::String> script = v8::String::New(
10557      "function f() {}\n\nfunction g() {}");
10558  v8::Script::Compile(script, &origin)->Run();
10559  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10560      env->Global()->Get(v8::String::New("f")));
10561  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10562      env->Global()->Get(v8::String::New("g")));
10563  CHECK_EQ(0, f->GetScriptLineNumber());
10564  CHECK_EQ(2, g->GetScriptLineNumber());
10565}
10566
10567
10568static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
10569                                              const AccessorInfo& info) {
10570  return v8_num(42);
10571}
10572
10573
10574static void SetterWhichSetsYOnThisTo23(Local<String> name,
10575                                       Local<Value> value,
10576                                       const AccessorInfo& info) {
10577  info.This()->Set(v8_str("y"), v8_num(23));
10578}
10579
10580
10581TEST(SetterOnConstructorPrototype) {
10582  v8::HandleScope scope;
10583  Local<ObjectTemplate> templ = ObjectTemplate::New();
10584  templ->SetAccessor(v8_str("x"),
10585                     GetterWhichReturns42,
10586                     SetterWhichSetsYOnThisTo23);
10587  LocalContext context;
10588  context->Global()->Set(v8_str("P"), templ->NewInstance());
10589  CompileRun("function C1() {"
10590             "  this.x = 23;"
10591             "};"
10592             "C1.prototype = P;"
10593             "function C2() {"
10594             "  this.x = 23"
10595             "};"
10596             "C2.prototype = { };"
10597             "C2.prototype.__proto__ = P;");
10598
10599  v8::Local<v8::Script> script;
10600  script = v8::Script::Compile(v8_str("new C1();"));
10601  for (int i = 0; i < 10; i++) {
10602    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10603    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10604    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10605  }
10606
10607  script = v8::Script::Compile(v8_str("new C2();"));
10608  for (int i = 0; i < 10; i++) {
10609    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10610    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10611    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10612  }
10613}
10614
10615
10616static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10617    Local<String> name, const AccessorInfo& info) {
10618  return v8_num(42);
10619}
10620
10621
10622static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10623    Local<String> name, Local<Value> value, const AccessorInfo& info) {
10624  if (name->Equals(v8_str("x"))) {
10625    info.This()->Set(v8_str("y"), v8_num(23));
10626  }
10627  return v8::Handle<Value>();
10628}
10629
10630
10631THREADED_TEST(InterceptorOnConstructorPrototype) {
10632  v8::HandleScope scope;
10633  Local<ObjectTemplate> templ = ObjectTemplate::New();
10634  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10635                                 NamedPropertySetterWhichSetsYOnThisTo23);
10636  LocalContext context;
10637  context->Global()->Set(v8_str("P"), templ->NewInstance());
10638  CompileRun("function C1() {"
10639             "  this.x = 23;"
10640             "};"
10641             "C1.prototype = P;"
10642             "function C2() {"
10643             "  this.x = 23"
10644             "};"
10645             "C2.prototype = { };"
10646             "C2.prototype.__proto__ = P;");
10647
10648  v8::Local<v8::Script> script;
10649  script = v8::Script::Compile(v8_str("new C1();"));
10650  for (int i = 0; i < 10; i++) {
10651    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10652    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10653    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10654  }
10655
10656  script = v8::Script::Compile(v8_str("new C2();"));
10657  for (int i = 0; i < 10; i++) {
10658    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10659    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10660    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10661  }
10662}
10663
10664
10665TEST(Bug618) {
10666  const char* source = "function C1() {"
10667                       "  this.x = 23;"
10668                       "};"
10669                       "C1.prototype = P;";
10670
10671  v8::HandleScope scope;
10672  LocalContext context;
10673  v8::Local<v8::Script> script;
10674
10675  // Use a simple object as prototype.
10676  v8::Local<v8::Object> prototype = v8::Object::New();
10677  prototype->Set(v8_str("y"), v8_num(42));
10678  context->Global()->Set(v8_str("P"), prototype);
10679
10680  // This compile will add the code to the compilation cache.
10681  CompileRun(source);
10682
10683  script = v8::Script::Compile(v8_str("new C1();"));
10684  for (int i = 0; i < 10; i++) {
10685    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10686    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10687    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10688  }
10689
10690  // Use an API object with accessors as prototype.
10691  Local<ObjectTemplate> templ = ObjectTemplate::New();
10692  templ->SetAccessor(v8_str("x"),
10693                     GetterWhichReturns42,
10694                     SetterWhichSetsYOnThisTo23);
10695  context->Global()->Set(v8_str("P"), templ->NewInstance());
10696
10697  // This compile will get the code from the compilation cache.
10698  CompileRun(source);
10699
10700  script = v8::Script::Compile(v8_str("new C1();"));
10701  for (int i = 0; i < 10; i++) {
10702    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10703    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10704    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10705  }
10706}
10707
10708int prologue_call_count = 0;
10709int epilogue_call_count = 0;
10710int prologue_call_count_second = 0;
10711int epilogue_call_count_second = 0;
10712
10713void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10714  ++prologue_call_count;
10715}
10716
10717void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10718  ++epilogue_call_count;
10719}
10720
10721void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10722  ++prologue_call_count_second;
10723}
10724
10725void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10726  ++epilogue_call_count_second;
10727}
10728
10729TEST(GCCallbacks) {
10730  LocalContext context;
10731
10732  v8::V8::AddGCPrologueCallback(PrologueCallback);
10733  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10734  CHECK_EQ(0, prologue_call_count);
10735  CHECK_EQ(0, epilogue_call_count);
10736  i::Heap::CollectAllGarbage(false);
10737  CHECK_EQ(1, prologue_call_count);
10738  CHECK_EQ(1, epilogue_call_count);
10739  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10740  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10741  i::Heap::CollectAllGarbage(false);
10742  CHECK_EQ(2, prologue_call_count);
10743  CHECK_EQ(2, epilogue_call_count);
10744  CHECK_EQ(1, prologue_call_count_second);
10745  CHECK_EQ(1, epilogue_call_count_second);
10746  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10747  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10748  i::Heap::CollectAllGarbage(false);
10749  CHECK_EQ(2, prologue_call_count);
10750  CHECK_EQ(2, epilogue_call_count);
10751  CHECK_EQ(2, prologue_call_count_second);
10752  CHECK_EQ(2, epilogue_call_count_second);
10753  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10754  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
10755  i::Heap::CollectAllGarbage(false);
10756  CHECK_EQ(2, prologue_call_count);
10757  CHECK_EQ(2, epilogue_call_count);
10758  CHECK_EQ(2, prologue_call_count_second);
10759  CHECK_EQ(2, epilogue_call_count_second);
10760}
10761
10762
10763THREADED_TEST(AddToJSFunctionResultCache) {
10764  i::FLAG_allow_natives_syntax = true;
10765  v8::HandleScope scope;
10766
10767  LocalContext context;
10768
10769  const char* code =
10770      "(function() {"
10771      "  var key0 = 'a';"
10772      "  var key1 = 'b';"
10773      "  var r0 = %_GetFromCache(0, key0);"
10774      "  var r1 = %_GetFromCache(0, key1);"
10775      "  var r0_ = %_GetFromCache(0, key0);"
10776      "  if (r0 !== r0_)"
10777      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
10778      "  var r1_ = %_GetFromCache(0, key1);"
10779      "  if (r1 !== r1_)"
10780      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
10781      "  return 'PASSED';"
10782      "})()";
10783  v8::internal::Heap::ClearJSFunctionResultCaches();
10784  ExpectString(code, "PASSED");
10785}
10786
10787
10788static const int k0CacheSize = 16;
10789
10790THREADED_TEST(FillJSFunctionResultCache) {
10791  i::FLAG_allow_natives_syntax = true;
10792  v8::HandleScope scope;
10793
10794  LocalContext context;
10795
10796  const char* code =
10797      "(function() {"
10798      "  var k = 'a';"
10799      "  var r = %_GetFromCache(0, k);"
10800      "  for (var i = 0; i < 16; i++) {"
10801      "    %_GetFromCache(0, 'a' + i);"
10802      "  };"
10803      "  if (r === %_GetFromCache(0, k))"
10804      "    return 'FAILED: k0CacheSize is too small';"
10805      "  return 'PASSED';"
10806      "})()";
10807  v8::internal::Heap::ClearJSFunctionResultCaches();
10808  ExpectString(code, "PASSED");
10809}
10810
10811
10812THREADED_TEST(RoundRobinGetFromCache) {
10813  i::FLAG_allow_natives_syntax = true;
10814  v8::HandleScope scope;
10815
10816  LocalContext context;
10817
10818  const char* code =
10819      "(function() {"
10820      "  var keys = [];"
10821      "  for (var i = 0; i < 16; i++) keys.push(i);"
10822      "  var values = [];"
10823      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10824      "  for (var i = 0; i < 16; i++) {"
10825      "    var v = %_GetFromCache(0, keys[i]);"
10826      "    if (v !== values[i])"
10827      "      return 'Wrong value for ' + "
10828      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10829      "  };"
10830      "  return 'PASSED';"
10831      "})()";
10832  v8::internal::Heap::ClearJSFunctionResultCaches();
10833  ExpectString(code, "PASSED");
10834}
10835
10836
10837THREADED_TEST(ReverseGetFromCache) {
10838  i::FLAG_allow_natives_syntax = true;
10839  v8::HandleScope scope;
10840
10841  LocalContext context;
10842
10843  const char* code =
10844      "(function() {"
10845      "  var keys = [];"
10846      "  for (var i = 0; i < 16; i++) keys.push(i);"
10847      "  var values = [];"
10848      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10849      "  for (var i = 15; i >= 16; i--) {"
10850      "    var v = %_GetFromCache(0, keys[i]);"
10851      "    if (v !== values[i])"
10852      "      return 'Wrong value for ' + "
10853      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
10854      "  };"
10855      "  return 'PASSED';"
10856      "})()";
10857  v8::internal::Heap::ClearJSFunctionResultCaches();
10858  ExpectString(code, "PASSED");
10859}
10860
10861
10862THREADED_TEST(TestEviction) {
10863  i::FLAG_allow_natives_syntax = true;
10864  v8::HandleScope scope;
10865
10866  LocalContext context;
10867
10868  const char* code =
10869      "(function() {"
10870      "  for (var i = 0; i < 2*16; i++) {"
10871      "    %_GetFromCache(0, 'a' + i);"
10872      "  };"
10873      "  return 'PASSED';"
10874      "})()";
10875  v8::internal::Heap::ClearJSFunctionResultCaches();
10876  ExpectString(code, "PASSED");
10877}
10878