~ubuntu-branches/ubuntu/trusty/libv8-3.14/trusty

« back to all changes in this revision

Viewing changes to .pc/0099_powerpc_support.patch/test/cctest/test-api.cc

  • Committer: Package Import Robot
  • Author(s): Adam Conrad
  • Date: 2014-02-12 10:26:54 UTC
  • Revision ID: package-import@ubuntu.com-20140212102654-mh2oalg31ifhjs0g
Tags: 3.14.5.8-5ubuntu1
* 0099_powerpc_support.patch: Pull in Andrew Low's powerpc port.
* debian/rules: Enable powerpc/ppc64/ppc64el for package builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
 
2
// Redistribution and use in source and binary forms, with or without
 
3
// modification, are permitted provided that the following conditions are
 
4
// met:
 
5
//
 
6
//     * Redistributions of source code must retain the above copyright
 
7
//       notice, this list of conditions and the following disclaimer.
 
8
//     * Redistributions in binary form must reproduce the above
 
9
//       copyright notice, this list of conditions and the following
 
10
//       disclaimer in the documentation and/or other materials provided
 
11
//       with the distribution.
 
12
//     * Neither the name of Google Inc. nor the names of its
 
13
//       contributors may be used to endorse or promote products derived
 
14
//       from this software without specific prior written permission.
 
15
//
 
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 
 
28
#include <limits.h>
 
29
 
 
30
#ifndef WIN32
 
31
#include <signal.h>  // kill
 
32
#include <unistd.h>  // getpid
 
33
#endif  // WIN32
 
34
 
 
35
#include "v8.h"
 
36
 
 
37
#include "api.h"
 
38
#include "isolate.h"
 
39
#include "compilation-cache.h"
 
40
#include "execution.h"
 
41
#include "objects.h"
 
42
#include "snapshot.h"
 
43
#include "platform.h"
 
44
#include "utils.h"
 
45
#include "cctest.h"
 
46
#include "parser.h"
 
47
#include "unicode-inl.h"
 
48
 
 
49
static const bool kLogThreading = false;
 
50
 
 
51
static bool IsNaN(double x) {
 
52
#ifdef WIN32
 
53
  return _isnan(x);
 
54
#else
 
55
  return isnan(x);
 
56
#endif
 
57
}
 
58
 
 
59
using ::v8::AccessorInfo;
 
60
using ::v8::Arguments;
 
61
using ::v8::Context;
 
62
using ::v8::Extension;
 
63
using ::v8::Function;
 
64
using ::v8::FunctionTemplate;
 
65
using ::v8::Handle;
 
66
using ::v8::HandleScope;
 
67
using ::v8::Local;
 
68
using ::v8::Message;
 
69
using ::v8::MessageCallback;
 
70
using ::v8::Object;
 
71
using ::v8::ObjectTemplate;
 
72
using ::v8::Persistent;
 
73
using ::v8::Script;
 
74
using ::v8::StackTrace;
 
75
using ::v8::String;
 
76
using ::v8::TryCatch;
 
77
using ::v8::Undefined;
 
78
using ::v8::V8;
 
79
using ::v8::Value;
 
80
 
 
81
 
 
82
static void ExpectString(const char* code, const char* expected) {
 
83
  Local<Value> result = CompileRun(code);
 
84
  CHECK(result->IsString());
 
85
  String::AsciiValue ascii(result);
 
86
  CHECK_EQ(expected, *ascii);
 
87
}
 
88
 
 
89
static void ExpectInt32(const char* code, int expected) {
 
90
  Local<Value> result = CompileRun(code);
 
91
  CHECK(result->IsInt32());
 
92
  CHECK_EQ(expected, result->Int32Value());
 
93
}
 
94
 
 
95
static void ExpectBoolean(const char* code, bool expected) {
 
96
  Local<Value> result = CompileRun(code);
 
97
  CHECK(result->IsBoolean());
 
98
  CHECK_EQ(expected, result->BooleanValue());
 
99
}
 
100
 
 
101
 
 
102
static void ExpectTrue(const char* code) {
 
103
  ExpectBoolean(code, true);
 
104
}
 
105
 
 
106
 
 
107
static void ExpectFalse(const char* code) {
 
108
  ExpectBoolean(code, false);
 
109
}
 
110
 
 
111
 
 
112
static void ExpectObject(const char* code, Local<Value> expected) {
 
113
  Local<Value> result = CompileRun(code);
 
114
  CHECK(result->Equals(expected));
 
115
}
 
116
 
 
117
 
 
118
static void ExpectUndefined(const char* code) {
 
119
  Local<Value> result = CompileRun(code);
 
120
  CHECK(result->IsUndefined());
 
121
}
 
122
 
 
123
 
 
124
static int signature_callback_count;
 
125
static v8::Handle<Value> IncrementingSignatureCallback(
 
126
    const v8::Arguments& args) {
 
127
  ApiTestFuzzer::Fuzz();
 
128
  signature_callback_count++;
 
129
  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
 
130
  for (int i = 0; i < args.Length(); i++)
 
131
    result->Set(v8::Integer::New(i), args[i]);
 
132
  return result;
 
133
}
 
134
 
 
135
 
 
136
static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
 
137
  ApiTestFuzzer::Fuzz();
 
138
  v8::Handle<v8::Array> result = v8::Array::New(args.Length());
 
139
  for (int i = 0; i < args.Length(); i++) {
 
140
    result->Set(v8::Integer::New(i), args[i]);
 
141
  }
 
142
  return result;
 
143
}
 
144
 
 
145
 
 
146
THREADED_TEST(Handles) {
 
147
  v8::HandleScope scope;
 
148
  Local<Context> local_env;
 
149
  {
 
150
    LocalContext env;
 
151
    local_env = env.local();
 
152
  }
 
153
 
 
154
  // Local context should still be live.
 
155
  CHECK(!local_env.IsEmpty());
 
156
  local_env->Enter();
 
157
 
 
158
  v8::Handle<v8::Primitive> undef = v8::Undefined();
 
159
  CHECK(!undef.IsEmpty());
 
160
  CHECK(undef->IsUndefined());
 
161
 
 
162
  const char* c_source = "1 + 2 + 3";
 
163
  Local<String> source = String::New(c_source);
 
164
  Local<Script> script = Script::Compile(source);
 
165
  CHECK_EQ(6, script->Run()->Int32Value());
 
166
 
 
167
  local_env->Exit();
 
168
}
 
169
 
 
170
 
 
171
THREADED_TEST(ReceiverSignature) {
 
172
  v8::HandleScope scope;
 
173
  LocalContext env;
 
174
  v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
 
175
  v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
 
176
  fun->PrototypeTemplate()->Set(
 
177
      v8_str("m"),
 
178
      v8::FunctionTemplate::New(IncrementingSignatureCallback,
 
179
                                v8::Handle<Value>(),
 
180
                                sig));
 
181
  env->Global()->Set(v8_str("Fun"), fun->GetFunction());
 
182
  signature_callback_count = 0;
 
183
  CompileRun(
 
184
      "var o = new Fun();"
 
185
      "o.m();");
 
186
  CHECK_EQ(1, signature_callback_count);
 
187
  v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
 
188
  sub_fun->Inherit(fun);
 
189
  env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
 
190
  CompileRun(
 
191
      "var o = new SubFun();"
 
192
      "o.m();");
 
193
  CHECK_EQ(2, signature_callback_count);
 
194
 
 
195
  v8::TryCatch try_catch;
 
196
  CompileRun(
 
197
      "var o = { };"
 
198
      "o.m = Fun.prototype.m;"
 
199
      "o.m();");
 
200
  CHECK_EQ(2, signature_callback_count);
 
201
  CHECK(try_catch.HasCaught());
 
202
  try_catch.Reset();
 
203
  v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
 
204
  sub_fun->Inherit(fun);
 
205
  env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
 
206
  CompileRun(
 
207
      "var o = new UnrelFun();"
 
208
      "o.m = Fun.prototype.m;"
 
209
      "o.m();");
 
210
  CHECK_EQ(2, signature_callback_count);
 
211
  CHECK(try_catch.HasCaught());
 
212
}
 
213
 
 
214
 
 
215
THREADED_TEST(ArgumentSignature) {
 
216
  v8::HandleScope scope;
 
217
  LocalContext env;
 
218
  v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
 
219
  cons->SetClassName(v8_str("Cons"));
 
220
  v8::Handle<v8::Signature> sig =
 
221
      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
 
222
  v8::Handle<v8::FunctionTemplate> fun =
 
223
      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
 
224
  env->Global()->Set(v8_str("Cons"), cons->GetFunction());
 
225
  env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
 
226
 
 
227
  v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
 
228
  CHECK(value1->IsTrue());
 
229
 
 
230
  v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
 
231
  CHECK(value2->IsTrue());
 
232
 
 
233
  v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
 
234
  CHECK(value3->IsTrue());
 
235
 
 
236
  v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
 
237
  cons1->SetClassName(v8_str("Cons1"));
 
238
  v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
 
239
  cons2->SetClassName(v8_str("Cons2"));
 
240
  v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
 
241
  cons3->SetClassName(v8_str("Cons3"));
 
242
 
 
243
  v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
 
244
  v8::Handle<v8::Signature> wsig =
 
245
      v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
 
246
  v8::Handle<v8::FunctionTemplate> fun2 =
 
247
      v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
 
248
 
 
249
  env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
 
250
  env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
 
251
  env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
 
252
  env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
 
253
  v8::Handle<Value> value4 = CompileRun(
 
254
      "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
 
255
      "'[object Cons1],[object Cons2],[object Cons3]'");
 
256
  CHECK(value4->IsTrue());
 
257
 
 
258
  v8::Handle<Value> value5 = CompileRun(
 
259
      "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
 
260
  CHECK(value5->IsTrue());
 
261
 
 
262
  v8::Handle<Value> value6 = CompileRun(
 
263
      "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
 
264
  CHECK(value6->IsTrue());
 
265
 
 
266
  v8::Handle<Value> value7 = CompileRun(
 
267
      "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
 
268
      "'[object Cons1],[object Cons2],[object Cons3],d';");
 
269
  CHECK(value7->IsTrue());
 
270
 
 
271
  v8::Handle<Value> value8 = CompileRun(
 
272
      "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
 
273
  CHECK(value8->IsTrue());
 
274
}
 
275
 
 
276
 
 
277
THREADED_TEST(HulIgennem) {
 
278
  v8::HandleScope scope;
 
279
  LocalContext env;
 
280
  v8::Handle<v8::Primitive> undef = v8::Undefined();
 
281
  Local<String> undef_str = undef->ToString();
 
282
  char* value = i::NewArray<char>(undef_str->Length() + 1);
 
283
  undef_str->WriteAscii(value);
 
284
  CHECK_EQ(0, strcmp(value, "undefined"));
 
285
  i::DeleteArray(value);
 
286
}
 
287
 
 
288
 
 
289
THREADED_TEST(Access) {
 
290
  v8::HandleScope scope;
 
291
  LocalContext env;
 
292
  Local<v8::Object> obj = v8::Object::New();
 
293
  Local<Value> foo_before = obj->Get(v8_str("foo"));
 
294
  CHECK(foo_before->IsUndefined());
 
295
  Local<String> bar_str = v8_str("bar");
 
296
  obj->Set(v8_str("foo"), bar_str);
 
297
  Local<Value> foo_after = obj->Get(v8_str("foo"));
 
298
  CHECK(!foo_after->IsUndefined());
 
299
  CHECK(foo_after->IsString());
 
300
  CHECK_EQ(bar_str, foo_after);
 
301
}
 
302
 
 
303
 
 
304
THREADED_TEST(AccessElement) {
 
305
  v8::HandleScope scope;
 
306
  LocalContext env;
 
307
  Local<v8::Object> obj = v8::Object::New();
 
308
  Local<Value> before = obj->Get(1);
 
309
  CHECK(before->IsUndefined());
 
310
  Local<String> bar_str = v8_str("bar");
 
311
  obj->Set(1, bar_str);
 
312
  Local<Value> after = obj->Get(1);
 
313
  CHECK(!after->IsUndefined());
 
314
  CHECK(after->IsString());
 
315
  CHECK_EQ(bar_str, after);
 
316
 
 
317
  Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
 
318
  CHECK_EQ(v8_str("a"), value->Get(0));
 
319
  CHECK_EQ(v8_str("b"), value->Get(1));
 
320
}
 
321
 
 
322
 
 
323
THREADED_TEST(Script) {
 
324
  v8::HandleScope scope;
 
325
  LocalContext env;
 
326
  const char* c_source = "1 + 2 + 3";
 
327
  Local<String> source = String::New(c_source);
 
328
  Local<Script> script = Script::Compile(source);
 
329
  CHECK_EQ(6, script->Run()->Int32Value());
 
330
}
 
331
 
 
332
 
 
333
static uint16_t* AsciiToTwoByteString(const char* source) {
 
334
  int array_length = i::StrLength(source) + 1;
 
335
  uint16_t* converted = i::NewArray<uint16_t>(array_length);
 
336
  for (int i = 0; i < array_length; i++) converted[i] = source[i];
 
337
  return converted;
 
338
}
 
339
 
 
340
 
 
341
class TestResource: public String::ExternalStringResource {
 
342
 public:
 
343
  explicit TestResource(uint16_t* data, int* counter = NULL)
 
344
    : data_(data), length_(0), counter_(counter) {
 
345
    while (data[length_]) ++length_;
 
346
  }
 
347
 
 
348
  ~TestResource() {
 
349
    i::DeleteArray(data_);
 
350
    if (counter_ != NULL) ++*counter_;
 
351
  }
 
352
 
 
353
  const uint16_t* data() const {
 
354
    return data_;
 
355
  }
 
356
 
 
357
  size_t length() const {
 
358
    return length_;
 
359
  }
 
360
 private:
 
361
  uint16_t* data_;
 
362
  size_t length_;
 
363
  int* counter_;
 
364
};
 
365
 
 
366
 
 
367
class TestAsciiResource: public String::ExternalAsciiStringResource {
 
368
 public:
 
369
  explicit TestAsciiResource(const char* data, int* counter = NULL)
 
370
    : data_(data), length_(strlen(data)), counter_(counter) { }
 
371
 
 
372
  ~TestAsciiResource() {
 
373
    i::DeleteArray(data_);
 
374
    if (counter_ != NULL) ++*counter_;
 
375
  }
 
376
 
 
377
  const char* data() const {
 
378
    return data_;
 
379
  }
 
380
 
 
381
  size_t length() const {
 
382
    return length_;
 
383
  }
 
384
 private:
 
385
  const char* data_;
 
386
  size_t length_;
 
387
  int* counter_;
 
388
};
 
389
 
 
390
 
 
391
THREADED_TEST(ScriptUsingStringResource) {
 
392
  int dispose_count = 0;
 
393
  const char* c_source = "1 + 2 * 3";
 
394
  uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
 
395
  {
 
396
    v8::HandleScope scope;
 
397
    LocalContext env;
 
398
    TestResource* resource = new TestResource(two_byte_source, &dispose_count);
 
399
    Local<String> source = String::NewExternal(resource);
 
400
    Local<Script> script = Script::Compile(source);
 
401
    Local<Value> value = script->Run();
 
402
    CHECK(value->IsNumber());
 
403
    CHECK_EQ(7, value->Int32Value());
 
404
    CHECK(source->IsExternal());
 
405
    CHECK_EQ(resource,
 
406
             static_cast<TestResource*>(source->GetExternalStringResource()));
 
407
    String::Encoding encoding = String::UNKNOWN_ENCODING;
 
408
    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
 
409
             source->GetExternalStringResourceBase(&encoding));
 
410
    CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
 
411
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
412
    CHECK_EQ(0, dispose_count);
 
413
  }
 
414
  v8::internal::Isolate::Current()->compilation_cache()->Clear();
 
415
  HEAP->CollectAllAvailableGarbage();
 
416
  CHECK_EQ(1, dispose_count);
 
417
}
 
418
 
 
419
 
 
420
THREADED_TEST(ScriptUsingAsciiStringResource) {
 
421
  int dispose_count = 0;
 
422
  const char* c_source = "1 + 2 * 3";
 
423
  {
 
424
    v8::HandleScope scope;
 
425
    LocalContext env;
 
426
    TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
 
427
                                                        &dispose_count);
 
428
    Local<String> source = String::NewExternal(resource);
 
429
    CHECK(source->IsExternalAscii());
 
430
    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
 
431
             source->GetExternalAsciiStringResource());
 
432
    String::Encoding encoding = String::UNKNOWN_ENCODING;
 
433
    CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
 
434
             source->GetExternalStringResourceBase(&encoding));
 
435
    CHECK_EQ(String::ASCII_ENCODING, encoding);
 
436
    Local<Script> script = Script::Compile(source);
 
437
    Local<Value> value = script->Run();
 
438
    CHECK(value->IsNumber());
 
439
    CHECK_EQ(7, value->Int32Value());
 
440
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
441
    CHECK_EQ(0, dispose_count);
 
442
  }
 
443
  i::Isolate::Current()->compilation_cache()->Clear();
 
444
  HEAP->CollectAllAvailableGarbage();
 
445
  CHECK_EQ(1, dispose_count);
 
446
}
 
447
 
 
448
 
 
449
THREADED_TEST(ScriptMakingExternalString) {
 
450
  int dispose_count = 0;
 
451
  uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
 
452
  {
 
453
    v8::HandleScope scope;
 
454
    LocalContext env;
 
455
    Local<String> source = String::New(two_byte_source);
 
456
    // Trigger GCs so that the newly allocated string moves to old gen.
 
457
    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
458
    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
459
    CHECK_EQ(source->IsExternal(), false);
 
460
    CHECK_EQ(source->IsExternalAscii(), false);
 
461
    String::Encoding encoding = String::UNKNOWN_ENCODING;
 
462
    CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
 
463
    CHECK_EQ(String::ASCII_ENCODING, encoding);
 
464
    bool success = source->MakeExternal(new TestResource(two_byte_source,
 
465
                                                         &dispose_count));
 
466
    CHECK(success);
 
467
    Local<Script> script = Script::Compile(source);
 
468
    Local<Value> value = script->Run();
 
469
    CHECK(value->IsNumber());
 
470
    CHECK_EQ(7, value->Int32Value());
 
471
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
472
    CHECK_EQ(0, dispose_count);
 
473
  }
 
474
  i::Isolate::Current()->compilation_cache()->Clear();
 
475
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
476
  CHECK_EQ(1, dispose_count);
 
477
}
 
478
 
 
479
 
 
480
THREADED_TEST(ScriptMakingExternalAsciiString) {
 
481
  int dispose_count = 0;
 
482
  const char* c_source = "1 + 2 * 3";
 
483
  {
 
484
    v8::HandleScope scope;
 
485
    LocalContext env;
 
486
    Local<String> source = v8_str(c_source);
 
487
    // Trigger GCs so that the newly allocated string moves to old gen.
 
488
    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
489
    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
490
    bool success = source->MakeExternal(
 
491
        new TestAsciiResource(i::StrDup(c_source), &dispose_count));
 
492
    CHECK(success);
 
493
    Local<Script> script = Script::Compile(source);
 
494
    Local<Value> value = script->Run();
 
495
    CHECK(value->IsNumber());
 
496
    CHECK_EQ(7, value->Int32Value());
 
497
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
498
    CHECK_EQ(0, dispose_count);
 
499
  }
 
500
  i::Isolate::Current()->compilation_cache()->Clear();
 
501
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
502
  CHECK_EQ(1, dispose_count);
 
503
}
 
504
 
 
505
 
 
506
TEST(MakingExternalStringConditions) {
 
507
  v8::HandleScope scope;
 
508
  LocalContext env;
 
509
 
 
510
  // Free some space in the new space so that we can check freshness.
 
511
  HEAP->CollectGarbage(i::NEW_SPACE);
 
512
  HEAP->CollectGarbage(i::NEW_SPACE);
 
513
 
 
514
  uint16_t* two_byte_string = AsciiToTwoByteString("s1");
 
515
  Local<String> small_string = String::New(two_byte_string);
 
516
  i::DeleteArray(two_byte_string);
 
517
 
 
518
  // We should refuse to externalize newly created small string.
 
519
  CHECK(!small_string->CanMakeExternal());
 
520
  // Trigger GCs so that the newly allocated string moves to old gen.
 
521
  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
522
  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
523
  // Old space strings should be accepted.
 
524
  CHECK(small_string->CanMakeExternal());
 
525
 
 
526
  two_byte_string = AsciiToTwoByteString("small string 2");
 
527
  small_string = String::New(two_byte_string);
 
528
  i::DeleteArray(two_byte_string);
 
529
 
 
530
  // We should refuse externalizing newly created small string.
 
531
  CHECK(!small_string->CanMakeExternal());
 
532
  for (int i = 0; i < 100; i++) {
 
533
    String::Value value(small_string);
 
534
  }
 
535
  // Frequently used strings should be accepted.
 
536
  CHECK(small_string->CanMakeExternal());
 
537
 
 
538
  const int buf_size = 10 * 1024;
 
539
  char* buf = i::NewArray<char>(buf_size);
 
540
  memset(buf, 'a', buf_size);
 
541
  buf[buf_size - 1] = '\0';
 
542
 
 
543
  two_byte_string = AsciiToTwoByteString(buf);
 
544
  Local<String> large_string = String::New(two_byte_string);
 
545
  i::DeleteArray(buf);
 
546
  i::DeleteArray(two_byte_string);
 
547
  // Large strings should be immediately accepted.
 
548
  CHECK(large_string->CanMakeExternal());
 
549
}
 
550
 
 
551
 
 
552
TEST(MakingExternalAsciiStringConditions) {
 
553
  v8::HandleScope scope;
 
554
  LocalContext env;
 
555
 
 
556
  // Free some space in the new space so that we can check freshness.
 
557
  HEAP->CollectGarbage(i::NEW_SPACE);
 
558
  HEAP->CollectGarbage(i::NEW_SPACE);
 
559
 
 
560
  Local<String> small_string = String::New("s1");
 
561
  // We should refuse to externalize newly created small string.
 
562
  CHECK(!small_string->CanMakeExternal());
 
563
  // Trigger GCs so that the newly allocated string moves to old gen.
 
564
  HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
565
  HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
566
  // Old space strings should be accepted.
 
567
  CHECK(small_string->CanMakeExternal());
 
568
 
 
569
  small_string = String::New("small string 2");
 
570
  // We should refuse externalizing newly created small string.
 
571
  CHECK(!small_string->CanMakeExternal());
 
572
  for (int i = 0; i < 100; i++) {
 
573
    String::Value value(small_string);
 
574
  }
 
575
  // Frequently used strings should be accepted.
 
576
  CHECK(small_string->CanMakeExternal());
 
577
 
 
578
  const int buf_size = 10 * 1024;
 
579
  char* buf = i::NewArray<char>(buf_size);
 
580
  memset(buf, 'a', buf_size);
 
581
  buf[buf_size - 1] = '\0';
 
582
  Local<String> large_string = String::New(buf);
 
583
  i::DeleteArray(buf);
 
584
  // Large strings should be immediately accepted.
 
585
  CHECK(large_string->CanMakeExternal());
 
586
}
 
587
 
 
588
 
 
589
THREADED_TEST(UsingExternalString) {
 
590
  {
 
591
    v8::HandleScope scope;
 
592
    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
 
593
    Local<String> string =
 
594
        String::NewExternal(new TestResource(two_byte_string));
 
595
    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
 
596
    // Trigger GCs so that the newly allocated string moves to old gen.
 
597
    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
598
    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
599
    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
 
600
    CHECK(isymbol->IsSymbol());
 
601
  }
 
602
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
603
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
604
}
 
605
 
 
606
 
 
607
THREADED_TEST(UsingExternalAsciiString) {
 
608
  {
 
609
    v8::HandleScope scope;
 
610
    const char* one_byte_string = "test string";
 
611
    Local<String> string = String::NewExternal(
 
612
        new TestAsciiResource(i::StrDup(one_byte_string)));
 
613
    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
 
614
    // Trigger GCs so that the newly allocated string moves to old gen.
 
615
    HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
 
616
    HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
 
617
    i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
 
618
    CHECK(isymbol->IsSymbol());
 
619
  }
 
620
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
621
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
622
}
 
623
 
 
624
 
 
625
THREADED_TEST(ScavengeExternalString) {
 
626
  int dispose_count = 0;
 
627
  bool in_new_space = false;
 
628
  {
 
629
    v8::HandleScope scope;
 
630
    uint16_t* two_byte_string = AsciiToTwoByteString("test string");
 
631
    Local<String> string =
 
632
      String::NewExternal(new TestResource(two_byte_string,
 
633
                                           &dispose_count));
 
634
    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
 
635
    HEAP->CollectGarbage(i::NEW_SPACE);
 
636
    in_new_space = HEAP->InNewSpace(*istring);
 
637
    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
 
638
    CHECK_EQ(0, dispose_count);
 
639
  }
 
640
  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
 
641
  CHECK_EQ(1, dispose_count);
 
642
}
 
643
 
 
644
 
 
645
THREADED_TEST(ScavengeExternalAsciiString) {
 
646
  int dispose_count = 0;
 
647
  bool in_new_space = false;
 
648
  {
 
649
    v8::HandleScope scope;
 
650
    const char* one_byte_string = "test string";
 
651
    Local<String> string = String::NewExternal(
 
652
        new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
 
653
    i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
 
654
    HEAP->CollectGarbage(i::NEW_SPACE);
 
655
    in_new_space = HEAP->InNewSpace(*istring);
 
656
    CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
 
657
    CHECK_EQ(0, dispose_count);
 
658
  }
 
659
  HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
 
660
  CHECK_EQ(1, dispose_count);
 
661
}
 
662
 
 
663
 
 
664
class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
 
665
 public:
 
666
  // Only used by non-threaded tests, so it can use static fields.
 
667
  static int dispose_calls;
 
668
  static int dispose_count;
 
669
 
 
670
  TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
 
671
      : TestAsciiResource(data, &dispose_count),
 
672
        dispose_(dispose) { }
 
673
 
 
674
  void Dispose() {
 
675
    ++dispose_calls;
 
676
    if (dispose_) delete this;
 
677
  }
 
678
 private:
 
679
  bool dispose_;
 
680
};
 
681
 
 
682
 
 
683
int TestAsciiResourceWithDisposeControl::dispose_count = 0;
 
684
int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
 
685
 
 
686
 
 
687
TEST(ExternalStringWithDisposeHandling) {
 
688
  const char* c_source = "1 + 2 * 3";
 
689
 
 
690
  // Use a stack allocated external string resource allocated object.
 
691
  TestAsciiResourceWithDisposeControl::dispose_count = 0;
 
692
  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
 
693
  TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
 
694
  {
 
695
    v8::HandleScope scope;
 
696
    LocalContext env;
 
697
    Local<String> source =  String::NewExternal(&res_stack);
 
698
    Local<Script> script = Script::Compile(source);
 
699
    Local<Value> value = script->Run();
 
700
    CHECK(value->IsNumber());
 
701
    CHECK_EQ(7, value->Int32Value());
 
702
    HEAP->CollectAllAvailableGarbage();
 
703
    CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
 
704
  }
 
705
  i::Isolate::Current()->compilation_cache()->Clear();
 
706
  HEAP->CollectAllAvailableGarbage();
 
707
  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
 
708
  CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
 
709
 
 
710
  // Use a heap allocated external string resource allocated object.
 
711
  TestAsciiResourceWithDisposeControl::dispose_count = 0;
 
712
  TestAsciiResourceWithDisposeControl::dispose_calls = 0;
 
713
  TestAsciiResource* res_heap =
 
714
      new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
 
715
  {
 
716
    v8::HandleScope scope;
 
717
    LocalContext env;
 
718
    Local<String> source =  String::NewExternal(res_heap);
 
719
    Local<Script> script = Script::Compile(source);
 
720
    Local<Value> value = script->Run();
 
721
    CHECK(value->IsNumber());
 
722
    CHECK_EQ(7, value->Int32Value());
 
723
    HEAP->CollectAllAvailableGarbage();
 
724
    CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
 
725
  }
 
726
  i::Isolate::Current()->compilation_cache()->Clear();
 
727
  HEAP->CollectAllAvailableGarbage();
 
728
  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
 
729
  CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
 
730
}
 
731
 
 
732
 
 
733
THREADED_TEST(StringConcat) {
 
734
  {
 
735
    v8::HandleScope scope;
 
736
    LocalContext env;
 
737
    const char* one_byte_string_1 = "function a_times_t";
 
738
    const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
 
739
    const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
 
740
    const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
 
741
    const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
 
742
    const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
 
743
    const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
 
744
    Local<String> left = v8_str(one_byte_string_1);
 
745
 
 
746
    uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
 
747
    Local<String> right = String::New(two_byte_source);
 
748
    i::DeleteArray(two_byte_source);
 
749
 
 
750
    Local<String> source = String::Concat(left, right);
 
751
    right = String::NewExternal(
 
752
        new TestAsciiResource(i::StrDup(one_byte_extern_1)));
 
753
    source = String::Concat(source, right);
 
754
    right = String::NewExternal(
 
755
        new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
 
756
    source = String::Concat(source, right);
 
757
    right = v8_str(one_byte_string_2);
 
758
    source = String::Concat(source, right);
 
759
 
 
760
    two_byte_source = AsciiToTwoByteString(two_byte_string_2);
 
761
    right = String::New(two_byte_source);
 
762
    i::DeleteArray(two_byte_source);
 
763
 
 
764
    source = String::Concat(source, right);
 
765
    right = String::NewExternal(
 
766
        new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
 
767
    source = String::Concat(source, right);
 
768
    Local<Script> script = Script::Compile(source);
 
769
    Local<Value> value = script->Run();
 
770
    CHECK(value->IsNumber());
 
771
    CHECK_EQ(68, value->Int32Value());
 
772
  }
 
773
  i::Isolate::Current()->compilation_cache()->Clear();
 
774
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
775
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
776
}
 
777
 
 
778
 
 
779
THREADED_TEST(GlobalProperties) {
 
780
  v8::HandleScope scope;
 
781
  LocalContext env;
 
782
  v8::Handle<v8::Object> global = env->Global();
 
783
  global->Set(v8_str("pi"), v8_num(3.1415926));
 
784
  Local<Value> pi = global->Get(v8_str("pi"));
 
785
  CHECK_EQ(3.1415926, pi->NumberValue());
 
786
}
 
787
 
 
788
 
 
789
static v8::Handle<Value> handle_call(const v8::Arguments& args) {
 
790
  ApiTestFuzzer::Fuzz();
 
791
  return v8_num(102);
 
792
}
 
793
 
 
794
 
 
795
static v8::Handle<Value> construct_call(const v8::Arguments& args) {
 
796
  ApiTestFuzzer::Fuzz();
 
797
  args.This()->Set(v8_str("x"), v8_num(1));
 
798
  args.This()->Set(v8_str("y"), v8_num(2));
 
799
  return args.This();
 
800
}
 
801
 
 
802
static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
 
803
  ApiTestFuzzer::Fuzz();
 
804
  return v8_num(239);
 
805
}
 
806
 
 
807
 
 
808
THREADED_TEST(FunctionTemplate) {
 
809
  v8::HandleScope scope;
 
810
  LocalContext env;
 
811
  {
 
812
    Local<v8::FunctionTemplate> fun_templ =
 
813
        v8::FunctionTemplate::New(handle_call);
 
814
    Local<Function> fun = fun_templ->GetFunction();
 
815
    env->Global()->Set(v8_str("obj"), fun);
 
816
    Local<Script> script = v8_compile("obj()");
 
817
    CHECK_EQ(102, script->Run()->Int32Value());
 
818
  }
 
819
  // Use SetCallHandler to initialize a function template, should work like the
 
820
  // previous one.
 
821
  {
 
822
    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
823
    fun_templ->SetCallHandler(handle_call);
 
824
    Local<Function> fun = fun_templ->GetFunction();
 
825
    env->Global()->Set(v8_str("obj"), fun);
 
826
    Local<Script> script = v8_compile("obj()");
 
827
    CHECK_EQ(102, script->Run()->Int32Value());
 
828
  }
 
829
  // Test constructor calls.
 
830
  {
 
831
    Local<v8::FunctionTemplate> fun_templ =
 
832
        v8::FunctionTemplate::New(construct_call);
 
833
    fun_templ->SetClassName(v8_str("funky"));
 
834
    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
 
835
    Local<Function> fun = fun_templ->GetFunction();
 
836
    env->Global()->Set(v8_str("obj"), fun);
 
837
    Local<Script> script = v8_compile("var s = new obj(); s.x");
 
838
    CHECK_EQ(1, script->Run()->Int32Value());
 
839
 
 
840
    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
 
841
    CHECK_EQ(v8_str("[object funky]"), result);
 
842
 
 
843
    result = v8_compile("(new obj()).m")->Run();
 
844
    CHECK_EQ(239, result->Int32Value());
 
845
  }
 
846
}
 
847
 
 
848
 
 
849
static void* expected_ptr;
 
850
static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
 
851
  void* ptr = v8::External::Unwrap(args.Data());
 
852
  CHECK_EQ(expected_ptr, ptr);
 
853
  return v8::True();
 
854
}
 
855
 
 
856
 
 
857
static void TestExternalPointerWrapping() {
 
858
  v8::HandleScope scope;
 
859
  LocalContext env;
 
860
 
 
861
  v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
 
862
 
 
863
  v8::Handle<v8::Object> obj = v8::Object::New();
 
864
  obj->Set(v8_str("func"),
 
865
           v8::FunctionTemplate::New(callback, data)->GetFunction());
 
866
  env->Global()->Set(v8_str("obj"), obj);
 
867
 
 
868
  CHECK(CompileRun(
 
869
        "function foo() {\n"
 
870
        "  for (var i = 0; i < 13; i++) obj.func();\n"
 
871
        "}\n"
 
872
        "foo(), true")->BooleanValue());
 
873
}
 
874
 
 
875
 
 
876
THREADED_TEST(ExternalWrap) {
 
877
  // Check heap allocated object.
 
878
  int* ptr = new int;
 
879
  expected_ptr = ptr;
 
880
  TestExternalPointerWrapping();
 
881
  delete ptr;
 
882
 
 
883
  // Check stack allocated object.
 
884
  int foo;
 
885
  expected_ptr = &foo;
 
886
  TestExternalPointerWrapping();
 
887
 
 
888
  // Check not aligned addresses.
 
889
  const int n = 100;
 
890
  char* s = new char[n];
 
891
  for (int i = 0; i < n; i++) {
 
892
    expected_ptr = s + i;
 
893
    TestExternalPointerWrapping();
 
894
  }
 
895
 
 
896
  delete[] s;
 
897
 
 
898
  // Check several invalid addresses.
 
899
  expected_ptr = reinterpret_cast<void*>(1);
 
900
  TestExternalPointerWrapping();
 
901
 
 
902
  expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
 
903
  TestExternalPointerWrapping();
 
904
 
 
905
  expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
 
906
  TestExternalPointerWrapping();
 
907
 
 
908
#if defined(V8_HOST_ARCH_X64)
 
909
  // Check a value with a leading 1 bit in x64 Smi encoding.
 
910
  expected_ptr = reinterpret_cast<void*>(0x400000000);
 
911
  TestExternalPointerWrapping();
 
912
 
 
913
  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
 
914
  TestExternalPointerWrapping();
 
915
 
 
916
  expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
 
917
  TestExternalPointerWrapping();
 
918
#endif
 
919
}
 
920
 
 
921
 
 
922
THREADED_TEST(FindInstanceInPrototypeChain) {
 
923
  v8::HandleScope scope;
 
924
  LocalContext env;
 
925
 
 
926
  Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
 
927
  Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
 
928
  Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
 
929
  derived->Inherit(base);
 
930
 
 
931
  Local<v8::Function> base_function = base->GetFunction();
 
932
  Local<v8::Function> derived_function = derived->GetFunction();
 
933
  Local<v8::Function> other_function = other->GetFunction();
 
934
 
 
935
  Local<v8::Object> base_instance = base_function->NewInstance();
 
936
  Local<v8::Object> derived_instance = derived_function->NewInstance();
 
937
  Local<v8::Object> derived_instance2 = derived_function->NewInstance();
 
938
  Local<v8::Object> other_instance = other_function->NewInstance();
 
939
  derived_instance2->Set(v8_str("__proto__"), derived_instance);
 
940
  other_instance->Set(v8_str("__proto__"), derived_instance2);
 
941
 
 
942
  // base_instance is only an instance of base.
 
943
  CHECK_EQ(base_instance,
 
944
           base_instance->FindInstanceInPrototypeChain(base));
 
945
  CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
 
946
  CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
 
947
 
 
948
  // derived_instance is an instance of base and derived.
 
949
  CHECK_EQ(derived_instance,
 
950
           derived_instance->FindInstanceInPrototypeChain(base));
 
951
  CHECK_EQ(derived_instance,
 
952
           derived_instance->FindInstanceInPrototypeChain(derived));
 
953
  CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
 
954
 
 
955
  // other_instance is an instance of other and its immediate
 
956
  // prototype derived_instance2 is an instance of base and derived.
 
957
  // Note, derived_instance is an instance of base and derived too,
 
958
  // but it comes after derived_instance2 in the prototype chain of
 
959
  // other_instance.
 
960
  CHECK_EQ(derived_instance2,
 
961
           other_instance->FindInstanceInPrototypeChain(base));
 
962
  CHECK_EQ(derived_instance2,
 
963
           other_instance->FindInstanceInPrototypeChain(derived));
 
964
  CHECK_EQ(other_instance,
 
965
           other_instance->FindInstanceInPrototypeChain(other));
 
966
}
 
967
 
 
968
 
 
969
THREADED_TEST(TinyInteger) {
 
970
  v8::HandleScope scope;
 
971
  LocalContext env;
 
972
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
973
 
 
974
  int32_t value = 239;
 
975
  Local<v8::Integer> value_obj = v8::Integer::New(value);
 
976
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
977
 
 
978
  value_obj = v8::Integer::New(value, isolate);
 
979
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
980
}
 
981
 
 
982
 
 
983
THREADED_TEST(BigSmiInteger) {
 
984
  v8::HandleScope scope;
 
985
  LocalContext env;
 
986
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
987
 
 
988
  int32_t value = i::Smi::kMaxValue;
 
989
  // We cannot add one to a Smi::kMaxValue without wrapping.
 
990
  if (i::kSmiValueSize < 32) {
 
991
    CHECK(i::Smi::IsValid(value));
 
992
    CHECK(!i::Smi::IsValid(value + 1));
 
993
 
 
994
    Local<v8::Integer> value_obj = v8::Integer::New(value);
 
995
    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
996
 
 
997
    value_obj = v8::Integer::New(value, isolate);
 
998
    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
999
  }
 
1000
}
 
1001
 
 
1002
 
 
1003
THREADED_TEST(BigInteger) {
 
1004
  v8::HandleScope scope;
 
1005
  LocalContext env;
 
1006
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
1007
 
 
1008
  // We cannot add one to a Smi::kMaxValue without wrapping.
 
1009
  if (i::kSmiValueSize < 32) {
 
1010
    // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
 
1011
    // The code will not be run in that case, due to the "if" guard.
 
1012
    int32_t value =
 
1013
        static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
 
1014
    CHECK(value > i::Smi::kMaxValue);
 
1015
    CHECK(!i::Smi::IsValid(value));
 
1016
 
 
1017
    Local<v8::Integer> value_obj = v8::Integer::New(value);
 
1018
    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1019
 
 
1020
    value_obj = v8::Integer::New(value, isolate);
 
1021
    CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1022
  }
 
1023
}
 
1024
 
 
1025
 
 
1026
THREADED_TEST(TinyUnsignedInteger) {
 
1027
  v8::HandleScope scope;
 
1028
  LocalContext env;
 
1029
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
1030
 
 
1031
  uint32_t value = 239;
 
1032
 
 
1033
  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
 
1034
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1035
 
 
1036
  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
 
1037
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1038
}
 
1039
 
 
1040
 
 
1041
THREADED_TEST(BigUnsignedSmiInteger) {
 
1042
  v8::HandleScope scope;
 
1043
  LocalContext env;
 
1044
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
1045
 
 
1046
  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
 
1047
  CHECK(i::Smi::IsValid(value));
 
1048
  CHECK(!i::Smi::IsValid(value + 1));
 
1049
 
 
1050
  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
 
1051
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1052
 
 
1053
  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
 
1054
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1055
}
 
1056
 
 
1057
 
 
1058
THREADED_TEST(BigUnsignedInteger) {
 
1059
  v8::HandleScope scope;
 
1060
  LocalContext env;
 
1061
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
1062
 
 
1063
  uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
 
1064
  CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
 
1065
  CHECK(!i::Smi::IsValid(value));
 
1066
 
 
1067
  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
 
1068
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1069
 
 
1070
  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
 
1071
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1072
}
 
1073
 
 
1074
 
 
1075
THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
 
1076
  v8::HandleScope scope;
 
1077
  LocalContext env;
 
1078
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
1079
 
 
1080
  uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
 
1081
  uint32_t value = INT32_MAX_AS_UINT + 1;
 
1082
  CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
 
1083
 
 
1084
  Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
 
1085
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1086
 
 
1087
  value_obj = v8::Integer::NewFromUnsigned(value, isolate);
 
1088
  CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
 
1089
}
 
1090
 
 
1091
 
 
1092
THREADED_TEST(IsNativeError) {
 
1093
  v8::HandleScope scope;
 
1094
  LocalContext env;
 
1095
  v8::Handle<Value> syntax_error = CompileRun(
 
1096
      "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
 
1097
  CHECK(syntax_error->IsNativeError());
 
1098
  v8::Handle<Value> not_error = CompileRun("{a:42}");
 
1099
  CHECK(!not_error->IsNativeError());
 
1100
  v8::Handle<Value> not_object = CompileRun("42");
 
1101
  CHECK(!not_object->IsNativeError());
 
1102
}
 
1103
 
 
1104
 
 
1105
THREADED_TEST(StringObject) {
 
1106
  v8::HandleScope scope;
 
1107
  LocalContext env;
 
1108
  v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
 
1109
  CHECK(boxed_string->IsStringObject());
 
1110
  v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
 
1111
  CHECK(!unboxed_string->IsStringObject());
 
1112
  v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
 
1113
  CHECK(!boxed_not_string->IsStringObject());
 
1114
  v8::Handle<Value> not_object = CompileRun("0");
 
1115
  CHECK(!not_object->IsStringObject());
 
1116
  v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
 
1117
  CHECK(!as_boxed.IsEmpty());
 
1118
  Local<v8::String> the_string = as_boxed->StringValue();
 
1119
  CHECK(!the_string.IsEmpty());
 
1120
  ExpectObject("\"test\"", the_string);
 
1121
  v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
 
1122
  CHECK(new_boxed_string->IsStringObject());
 
1123
  as_boxed = new_boxed_string.As<v8::StringObject>();
 
1124
  the_string = as_boxed->StringValue();
 
1125
  CHECK(!the_string.IsEmpty());
 
1126
  ExpectObject("\"test\"", the_string);
 
1127
}
 
1128
 
 
1129
 
 
1130
THREADED_TEST(NumberObject) {
 
1131
  v8::HandleScope scope;
 
1132
  LocalContext env;
 
1133
  v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
 
1134
  CHECK(boxed_number->IsNumberObject());
 
1135
  v8::Handle<Value> unboxed_number = CompileRun("42");
 
1136
  CHECK(!unboxed_number->IsNumberObject());
 
1137
  v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
 
1138
  CHECK(!boxed_not_number->IsNumberObject());
 
1139
  v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
 
1140
  CHECK(!as_boxed.IsEmpty());
 
1141
  double the_number = as_boxed->NumberValue();
 
1142
  CHECK_EQ(42.0, the_number);
 
1143
  v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
 
1144
  CHECK(new_boxed_number->IsNumberObject());
 
1145
  as_boxed = new_boxed_number.As<v8::NumberObject>();
 
1146
  the_number = as_boxed->NumberValue();
 
1147
  CHECK_EQ(43.0, the_number);
 
1148
}
 
1149
 
 
1150
 
 
1151
THREADED_TEST(BooleanObject) {
 
1152
  v8::HandleScope scope;
 
1153
  LocalContext env;
 
1154
  v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
 
1155
  CHECK(boxed_boolean->IsBooleanObject());
 
1156
  v8::Handle<Value> unboxed_boolean = CompileRun("true");
 
1157
  CHECK(!unboxed_boolean->IsBooleanObject());
 
1158
  v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
 
1159
  CHECK(!boxed_not_boolean->IsBooleanObject());
 
1160
  v8::Handle<v8::BooleanObject> as_boxed =
 
1161
      boxed_boolean.As<v8::BooleanObject>();
 
1162
  CHECK(!as_boxed.IsEmpty());
 
1163
  bool the_boolean = as_boxed->BooleanValue();
 
1164
  CHECK_EQ(true, the_boolean);
 
1165
  v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
 
1166
  v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
 
1167
  CHECK(boxed_true->IsBooleanObject());
 
1168
  CHECK(boxed_false->IsBooleanObject());
 
1169
  as_boxed = boxed_true.As<v8::BooleanObject>();
 
1170
  CHECK_EQ(true, as_boxed->BooleanValue());
 
1171
  as_boxed = boxed_false.As<v8::BooleanObject>();
 
1172
  CHECK_EQ(false, as_boxed->BooleanValue());
 
1173
}
 
1174
 
 
1175
 
 
1176
THREADED_TEST(Number) {
 
1177
  v8::HandleScope scope;
 
1178
  LocalContext env;
 
1179
  double PI = 3.1415926;
 
1180
  Local<v8::Number> pi_obj = v8::Number::New(PI);
 
1181
  CHECK_EQ(PI, pi_obj->NumberValue());
 
1182
}
 
1183
 
 
1184
 
 
1185
THREADED_TEST(ToNumber) {
 
1186
  v8::HandleScope scope;
 
1187
  LocalContext env;
 
1188
  Local<String> str = v8_str("3.1415926");
 
1189
  CHECK_EQ(3.1415926, str->NumberValue());
 
1190
  v8::Handle<v8::Boolean> t = v8::True();
 
1191
  CHECK_EQ(1.0, t->NumberValue());
 
1192
  v8::Handle<v8::Boolean> f = v8::False();
 
1193
  CHECK_EQ(0.0, f->NumberValue());
 
1194
}
 
1195
 
 
1196
 
 
1197
THREADED_TEST(Date) {
 
1198
  v8::HandleScope scope;
 
1199
  LocalContext env;
 
1200
  double PI = 3.1415926;
 
1201
  Local<Value> date = v8::Date::New(PI);
 
1202
  CHECK_EQ(3.0, date->NumberValue());
 
1203
  date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
 
1204
  CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
 
1205
}
 
1206
 
 
1207
 
 
1208
THREADED_TEST(Boolean) {
 
1209
  v8::HandleScope scope;
 
1210
  LocalContext env;
 
1211
  v8::Handle<v8::Boolean> t = v8::True();
 
1212
  CHECK(t->Value());
 
1213
  v8::Handle<v8::Boolean> f = v8::False();
 
1214
  CHECK(!f->Value());
 
1215
  v8::Handle<v8::Primitive> u = v8::Undefined();
 
1216
  CHECK(!u->BooleanValue());
 
1217
  v8::Handle<v8::Primitive> n = v8::Null();
 
1218
  CHECK(!n->BooleanValue());
 
1219
  v8::Handle<String> str1 = v8_str("");
 
1220
  CHECK(!str1->BooleanValue());
 
1221
  v8::Handle<String> str2 = v8_str("x");
 
1222
  CHECK(str2->BooleanValue());
 
1223
  CHECK(!v8::Number::New(0)->BooleanValue());
 
1224
  CHECK(v8::Number::New(-1)->BooleanValue());
 
1225
  CHECK(v8::Number::New(1)->BooleanValue());
 
1226
  CHECK(v8::Number::New(42)->BooleanValue());
 
1227
  CHECK(!v8_compile("NaN")->Run()->BooleanValue());
 
1228
}
 
1229
 
 
1230
 
 
1231
static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
 
1232
  ApiTestFuzzer::Fuzz();
 
1233
  return v8_num(13.4);
 
1234
}
 
1235
 
 
1236
 
 
1237
static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
 
1238
  ApiTestFuzzer::Fuzz();
 
1239
  return v8_num(876);
 
1240
}
 
1241
 
 
1242
 
 
1243
THREADED_TEST(GlobalPrototype) {
 
1244
  v8::HandleScope scope;
 
1245
  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
 
1246
  func_templ->PrototypeTemplate()->Set(
 
1247
      "dummy",
 
1248
      v8::FunctionTemplate::New(DummyCallHandler));
 
1249
  v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
 
1250
  templ->Set("x", v8_num(200));
 
1251
  templ->SetAccessor(v8_str("m"), GetM);
 
1252
  LocalContext env(0, templ);
 
1253
  v8::Handle<Script> script(v8_compile("dummy()"));
 
1254
  v8::Handle<Value> result(script->Run());
 
1255
  CHECK_EQ(13.4, result->NumberValue());
 
1256
  CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
 
1257
  CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
 
1258
}
 
1259
 
 
1260
 
 
1261
THREADED_TEST(ObjectTemplate) {
 
1262
  v8::HandleScope scope;
 
1263
  Local<ObjectTemplate> templ1 = ObjectTemplate::New();
 
1264
  templ1->Set("x", v8_num(10));
 
1265
  templ1->Set("y", v8_num(13));
 
1266
  LocalContext env;
 
1267
  Local<v8::Object> instance1 = templ1->NewInstance();
 
1268
  env->Global()->Set(v8_str("p"), instance1);
 
1269
  CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
 
1270
  CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
 
1271
  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
 
1272
  fun->PrototypeTemplate()->Set("nirk", v8_num(123));
 
1273
  Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
 
1274
  templ2->Set("a", v8_num(12));
 
1275
  templ2->Set("b", templ1);
 
1276
  Local<v8::Object> instance2 = templ2->NewInstance();
 
1277
  env->Global()->Set(v8_str("q"), instance2);
 
1278
  CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
 
1279
  CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
 
1280
  CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
 
1281
  CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
 
1282
}
 
1283
 
 
1284
 
 
1285
static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
 
1286
  ApiTestFuzzer::Fuzz();
 
1287
  return v8_num(17.2);
 
1288
}
 
1289
 
 
1290
 
 
1291
static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
 
1292
  ApiTestFuzzer::Fuzz();
 
1293
  return v8_num(15.2);
 
1294
}
 
1295
 
 
1296
 
 
1297
THREADED_TEST(DescriptorInheritance) {
 
1298
  v8::HandleScope scope;
 
1299
  v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
 
1300
  super->PrototypeTemplate()->Set("flabby",
 
1301
                                  v8::FunctionTemplate::New(GetFlabby));
 
1302
  super->PrototypeTemplate()->Set("PI", v8_num(3.14));
 
1303
 
 
1304
  super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
 
1305
 
 
1306
  v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
 
1307
  base1->Inherit(super);
 
1308
  base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
 
1309
 
 
1310
  v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
 
1311
  base2->Inherit(super);
 
1312
  base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
 
1313
 
 
1314
  LocalContext env;
 
1315
 
 
1316
  env->Global()->Set(v8_str("s"), super->GetFunction());
 
1317
  env->Global()->Set(v8_str("base1"), base1->GetFunction());
 
1318
  env->Global()->Set(v8_str("base2"), base2->GetFunction());
 
1319
 
 
1320
  // Checks right __proto__ chain.
 
1321
  CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
 
1322
  CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
 
1323
 
 
1324
  CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
 
1325
 
 
1326
  // Instance accessor should not be visible on function object or its prototype
 
1327
  CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
 
1328
  CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
 
1329
  CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
 
1330
 
 
1331
  env->Global()->Set(v8_str("obj"),
 
1332
                     base1->GetFunction()->NewInstance());
 
1333
  CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
 
1334
  CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
 
1335
  CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
 
1336
  CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
 
1337
  CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
 
1338
 
 
1339
  env->Global()->Set(v8_str("obj2"),
 
1340
                     base2->GetFunction()->NewInstance());
 
1341
  CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
 
1342
  CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
 
1343
  CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
 
1344
  CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
 
1345
  CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
 
1346
 
 
1347
  // base1 and base2 cannot cross reference to each's prototype
 
1348
  CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
 
1349
  CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
 
1350
}
 
1351
 
 
1352
 
 
1353
int echo_named_call_count;
 
1354
 
 
1355
 
 
1356
static v8::Handle<Value> EchoNamedProperty(Local<String> name,
 
1357
                                           const AccessorInfo& info) {
 
1358
  ApiTestFuzzer::Fuzz();
 
1359
  CHECK_EQ(v8_str("data"), info.Data());
 
1360
  echo_named_call_count++;
 
1361
  return name;
 
1362
}
 
1363
 
 
1364
// Helper functions for Interceptor/Accessor interaction tests
 
1365
 
 
1366
Handle<Value> SimpleAccessorGetter(Local<String> name,
 
1367
                                   const AccessorInfo& info) {
 
1368
  Handle<Object> self = info.This();
 
1369
  return self->Get(String::Concat(v8_str("accessor_"), name));
 
1370
}
 
1371
 
 
1372
void SimpleAccessorSetter(Local<String> name, Local<Value> value,
 
1373
                          const AccessorInfo& info) {
 
1374
  Handle<Object> self = info.This();
 
1375
  self->Set(String::Concat(v8_str("accessor_"), name), value);
 
1376
}
 
1377
 
 
1378
Handle<Value> EmptyInterceptorGetter(Local<String> name,
 
1379
                                     const AccessorInfo& info) {
 
1380
  return Handle<Value>();
 
1381
}
 
1382
 
 
1383
Handle<Value> EmptyInterceptorSetter(Local<String> name,
 
1384
                                     Local<Value> value,
 
1385
                                     const AccessorInfo& info) {
 
1386
  return Handle<Value>();
 
1387
}
 
1388
 
 
1389
Handle<Value> InterceptorGetter(Local<String> name,
 
1390
                                const AccessorInfo& info) {
 
1391
  // Intercept names that start with 'interceptor_'.
 
1392
  String::AsciiValue ascii(name);
 
1393
  char* name_str = *ascii;
 
1394
  char prefix[] = "interceptor_";
 
1395
  int i;
 
1396
  for (i = 0; name_str[i] && prefix[i]; ++i) {
 
1397
    if (name_str[i] != prefix[i]) return Handle<Value>();
 
1398
  }
 
1399
  Handle<Object> self = info.This();
 
1400
  return self->GetHiddenValue(v8_str(name_str + i));
 
1401
}
 
1402
 
 
1403
Handle<Value> InterceptorSetter(Local<String> name,
 
1404
                                Local<Value> value,
 
1405
                                const AccessorInfo& info) {
 
1406
  // Intercept accesses that set certain integer values.
 
1407
  if (value->IsInt32() && value->Int32Value() < 10000) {
 
1408
    Handle<Object> self = info.This();
 
1409
    self->SetHiddenValue(name, value);
 
1410
    return value;
 
1411
  }
 
1412
  return Handle<Value>();
 
1413
}
 
1414
 
 
1415
void AddAccessor(Handle<FunctionTemplate> templ,
 
1416
                 Handle<String> name,
 
1417
                 v8::AccessorGetter getter,
 
1418
                 v8::AccessorSetter setter) {
 
1419
  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
 
1420
}
 
1421
 
 
1422
void AddInterceptor(Handle<FunctionTemplate> templ,
 
1423
                    v8::NamedPropertyGetter getter,
 
1424
                    v8::NamedPropertySetter setter) {
 
1425
  templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
 
1426
}
 
1427
 
 
1428
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
 
1429
  v8::HandleScope scope;
 
1430
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1431
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1432
  child->Inherit(parent);
 
1433
  AddAccessor(parent, v8_str("age"),
 
1434
              SimpleAccessorGetter, SimpleAccessorSetter);
 
1435
  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
1436
  LocalContext env;
 
1437
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1438
  CompileRun("var child = new Child;"
 
1439
             "child.age = 10;");
 
1440
  ExpectBoolean("child.hasOwnProperty('age')", false);
 
1441
  ExpectInt32("child.age", 10);
 
1442
  ExpectInt32("child.accessor_age", 10);
 
1443
}
 
1444
 
 
1445
THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
 
1446
  v8::HandleScope scope;
 
1447
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1448
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1449
  child->Inherit(parent);
 
1450
  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
1451
  LocalContext env;
 
1452
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1453
  CompileRun("var child = new Child;"
 
1454
             "var parent = child.__proto__;"
 
1455
             "Object.defineProperty(parent, 'age', "
 
1456
             "  {get: function(){ return this.accessor_age; }, "
 
1457
             "   set: function(v){ this.accessor_age = v; }, "
 
1458
             "   enumerable: true, configurable: true});"
 
1459
             "child.age = 10;");
 
1460
  ExpectBoolean("child.hasOwnProperty('age')", false);
 
1461
  ExpectInt32("child.age", 10);
 
1462
  ExpectInt32("child.accessor_age", 10);
 
1463
}
 
1464
 
 
1465
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
 
1466
  v8::HandleScope scope;
 
1467
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1468
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1469
  child->Inherit(parent);
 
1470
  AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
1471
  LocalContext env;
 
1472
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1473
  CompileRun("var child = new Child;"
 
1474
             "var parent = child.__proto__;"
 
1475
             "parent.name = 'Alice';");
 
1476
  ExpectBoolean("child.hasOwnProperty('name')", false);
 
1477
  ExpectString("child.name", "Alice");
 
1478
  CompileRun("child.name = 'Bob';");
 
1479
  ExpectString("child.name", "Bob");
 
1480
  ExpectBoolean("child.hasOwnProperty('name')", true);
 
1481
  ExpectString("parent.name", "Alice");
 
1482
}
 
1483
 
 
1484
THREADED_TEST(SwitchFromInterceptorToAccessor) {
 
1485
  v8::HandleScope scope;
 
1486
  Handle<FunctionTemplate> templ = FunctionTemplate::New();
 
1487
  AddAccessor(templ, v8_str("age"),
 
1488
              SimpleAccessorGetter, SimpleAccessorSetter);
 
1489
  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
 
1490
  LocalContext env;
 
1491
  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
 
1492
  CompileRun("var obj = new Obj;"
 
1493
             "function setAge(i){ obj.age = i; };"
 
1494
             "for(var i = 0; i <= 10000; i++) setAge(i);");
 
1495
  // All i < 10000 go to the interceptor.
 
1496
  ExpectInt32("obj.interceptor_age", 9999);
 
1497
  // The last i goes to the accessor.
 
1498
  ExpectInt32("obj.accessor_age", 10000);
 
1499
}
 
1500
 
 
1501
THREADED_TEST(SwitchFromAccessorToInterceptor) {
 
1502
  v8::HandleScope scope;
 
1503
  Handle<FunctionTemplate> templ = FunctionTemplate::New();
 
1504
  AddAccessor(templ, v8_str("age"),
 
1505
              SimpleAccessorGetter, SimpleAccessorSetter);
 
1506
  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
 
1507
  LocalContext env;
 
1508
  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
 
1509
  CompileRun("var obj = new Obj;"
 
1510
             "function setAge(i){ obj.age = i; };"
 
1511
             "for(var i = 20000; i >= 9999; i--) setAge(i);");
 
1512
  // All i >= 10000 go to the accessor.
 
1513
  ExpectInt32("obj.accessor_age", 10000);
 
1514
  // The last i goes to the interceptor.
 
1515
  ExpectInt32("obj.interceptor_age", 9999);
 
1516
}
 
1517
 
 
1518
THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
 
1519
  v8::HandleScope scope;
 
1520
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1521
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1522
  child->Inherit(parent);
 
1523
  AddAccessor(parent, v8_str("age"),
 
1524
              SimpleAccessorGetter, SimpleAccessorSetter);
 
1525
  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
 
1526
  LocalContext env;
 
1527
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1528
  CompileRun("var child = new Child;"
 
1529
             "function setAge(i){ child.age = i; };"
 
1530
             "for(var i = 0; i <= 10000; i++) setAge(i);");
 
1531
  // All i < 10000 go to the interceptor.
 
1532
  ExpectInt32("child.interceptor_age", 9999);
 
1533
  // The last i goes to the accessor.
 
1534
  ExpectInt32("child.accessor_age", 10000);
 
1535
}
 
1536
 
 
1537
THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
 
1538
  v8::HandleScope scope;
 
1539
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1540
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1541
  child->Inherit(parent);
 
1542
  AddAccessor(parent, v8_str("age"),
 
1543
              SimpleAccessorGetter, SimpleAccessorSetter);
 
1544
  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
 
1545
  LocalContext env;
 
1546
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1547
  CompileRun("var child = new Child;"
 
1548
             "function setAge(i){ child.age = i; };"
 
1549
             "for(var i = 20000; i >= 9999; i--) setAge(i);");
 
1550
  // All i >= 10000 go to the accessor.
 
1551
  ExpectInt32("child.accessor_age", 10000);
 
1552
  // The last i goes to the interceptor.
 
1553
  ExpectInt32("child.interceptor_age", 9999);
 
1554
}
 
1555
 
 
1556
THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
 
1557
  v8::HandleScope scope;
 
1558
  Handle<FunctionTemplate> templ = FunctionTemplate::New();
 
1559
  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
 
1560
  LocalContext env;
 
1561
  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
 
1562
  CompileRun("var obj = new Obj;"
 
1563
             "function setter(i) { this.accessor_age = i; };"
 
1564
             "function getter() { return this.accessor_age; };"
 
1565
             "function setAge(i) { obj.age = i; };"
 
1566
             "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
 
1567
             "for(var i = 0; i <= 10000; i++) setAge(i);");
 
1568
  // All i < 10000 go to the interceptor.
 
1569
  ExpectInt32("obj.interceptor_age", 9999);
 
1570
  // The last i goes to the JavaScript accessor.
 
1571
  ExpectInt32("obj.accessor_age", 10000);
 
1572
  // The installed JavaScript getter is still intact.
 
1573
  // This last part is a regression test for issue 1651 and relies on the fact
 
1574
  // that both interceptor and accessor are being installed on the same object.
 
1575
  ExpectInt32("obj.age", 10000);
 
1576
  ExpectBoolean("obj.hasOwnProperty('age')", true);
 
1577
  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
 
1578
}
 
1579
 
 
1580
THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
 
1581
  v8::HandleScope scope;
 
1582
  Handle<FunctionTemplate> templ = FunctionTemplate::New();
 
1583
  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
 
1584
  LocalContext env;
 
1585
  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
 
1586
  CompileRun("var obj = new Obj;"
 
1587
             "function setter(i) { this.accessor_age = i; };"
 
1588
             "function getter() { return this.accessor_age; };"
 
1589
             "function setAge(i) { obj.age = i; };"
 
1590
             "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
 
1591
             "for(var i = 20000; i >= 9999; i--) setAge(i);");
 
1592
  // All i >= 10000 go to the accessor.
 
1593
  ExpectInt32("obj.accessor_age", 10000);
 
1594
  // The last i goes to the interceptor.
 
1595
  ExpectInt32("obj.interceptor_age", 9999);
 
1596
  // The installed JavaScript getter is still intact.
 
1597
  // This last part is a regression test for issue 1651 and relies on the fact
 
1598
  // that both interceptor and accessor are being installed on the same object.
 
1599
  ExpectInt32("obj.age", 10000);
 
1600
  ExpectBoolean("obj.hasOwnProperty('age')", true);
 
1601
  ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
 
1602
}
 
1603
 
 
1604
THREADED_TEST(SwitchFromInterceptorToProperty) {
 
1605
  v8::HandleScope scope;
 
1606
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1607
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1608
  child->Inherit(parent);
 
1609
  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
 
1610
  LocalContext env;
 
1611
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1612
  CompileRun("var child = new Child;"
 
1613
             "function setAge(i){ child.age = i; };"
 
1614
             "for(var i = 0; i <= 10000; i++) setAge(i);");
 
1615
  // All i < 10000 go to the interceptor.
 
1616
  ExpectInt32("child.interceptor_age", 9999);
 
1617
  // The last i goes to child's own property.
 
1618
  ExpectInt32("child.age", 10000);
 
1619
}
 
1620
 
 
1621
THREADED_TEST(SwitchFromPropertyToInterceptor) {
 
1622
  v8::HandleScope scope;
 
1623
  Handle<FunctionTemplate> parent = FunctionTemplate::New();
 
1624
  Handle<FunctionTemplate> child = FunctionTemplate::New();
 
1625
  child->Inherit(parent);
 
1626
  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
 
1627
  LocalContext env;
 
1628
  env->Global()->Set(v8_str("Child"), child->GetFunction());
 
1629
  CompileRun("var child = new Child;"
 
1630
             "function setAge(i){ child.age = i; };"
 
1631
             "for(var i = 20000; i >= 9999; i--) setAge(i);");
 
1632
  // All i >= 10000 go to child's own property.
 
1633
  ExpectInt32("child.age", 10000);
 
1634
  // The last i goes to the interceptor.
 
1635
  ExpectInt32("child.interceptor_age", 9999);
 
1636
}
 
1637
 
 
1638
THREADED_TEST(NamedPropertyHandlerGetter) {
 
1639
  echo_named_call_count = 0;
 
1640
  v8::HandleScope scope;
 
1641
  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
1642
  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
 
1643
                                                     0, 0, 0, 0,
 
1644
                                                     v8_str("data"));
 
1645
  LocalContext env;
 
1646
  env->Global()->Set(v8_str("obj"),
 
1647
                     templ->GetFunction()->NewInstance());
 
1648
  CHECK_EQ(echo_named_call_count, 0);
 
1649
  v8_compile("obj.x")->Run();
 
1650
  CHECK_EQ(echo_named_call_count, 1);
 
1651
  const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
 
1652
  v8::Handle<Value> str = CompileRun(code);
 
1653
  String::AsciiValue value(str);
 
1654
  CHECK_EQ(*value, "oddlepoddle");
 
1655
  // Check default behavior
 
1656
  CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
 
1657
  CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
 
1658
  CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
 
1659
}
 
1660
 
 
1661
 
 
1662
int echo_indexed_call_count = 0;
 
1663
 
 
1664
 
 
1665
static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
 
1666
                                             const AccessorInfo& info) {
 
1667
  ApiTestFuzzer::Fuzz();
 
1668
  CHECK_EQ(v8_num(637), info.Data());
 
1669
  echo_indexed_call_count++;
 
1670
  return v8_num(index);
 
1671
}
 
1672
 
 
1673
 
 
1674
THREADED_TEST(IndexedPropertyHandlerGetter) {
 
1675
  v8::HandleScope scope;
 
1676
  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
1677
  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
 
1678
                                                       0, 0, 0, 0,
 
1679
                                                       v8_num(637));
 
1680
  LocalContext env;
 
1681
  env->Global()->Set(v8_str("obj"),
 
1682
                     templ->GetFunction()->NewInstance());
 
1683
  Local<Script> script = v8_compile("obj[900]");
 
1684
  CHECK_EQ(script->Run()->Int32Value(), 900);
 
1685
}
 
1686
 
 
1687
 
 
1688
v8::Handle<v8::Object> bottom;
 
1689
 
 
1690
static v8::Handle<Value> CheckThisIndexedPropertyHandler(
 
1691
    uint32_t index,
 
1692
    const AccessorInfo& info) {
 
1693
  ApiTestFuzzer::Fuzz();
 
1694
  CHECK(info.This()->Equals(bottom));
 
1695
  return v8::Handle<Value>();
 
1696
}
 
1697
 
 
1698
static v8::Handle<Value> CheckThisNamedPropertyHandler(
 
1699
    Local<String> name,
 
1700
    const AccessorInfo& info) {
 
1701
  ApiTestFuzzer::Fuzz();
 
1702
  CHECK(info.This()->Equals(bottom));
 
1703
  return v8::Handle<Value>();
 
1704
}
 
1705
 
 
1706
 
 
1707
v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
 
1708
                                                 Local<Value> value,
 
1709
                                                 const AccessorInfo& info) {
 
1710
  ApiTestFuzzer::Fuzz();
 
1711
  CHECK(info.This()->Equals(bottom));
 
1712
  return v8::Handle<Value>();
 
1713
}
 
1714
 
 
1715
 
 
1716
v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
 
1717
                                               Local<Value> value,
 
1718
                                               const AccessorInfo& info) {
 
1719
  ApiTestFuzzer::Fuzz();
 
1720
  CHECK(info.This()->Equals(bottom));
 
1721
  return v8::Handle<Value>();
 
1722
}
 
1723
 
 
1724
v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
 
1725
    uint32_t index,
 
1726
    const AccessorInfo& info) {
 
1727
  ApiTestFuzzer::Fuzz();
 
1728
  CHECK(info.This()->Equals(bottom));
 
1729
  return v8::Handle<v8::Integer>();
 
1730
}
 
1731
 
 
1732
 
 
1733
v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
 
1734
                                                    const AccessorInfo& info) {
 
1735
  ApiTestFuzzer::Fuzz();
 
1736
  CHECK(info.This()->Equals(bottom));
 
1737
  return v8::Handle<v8::Integer>();
 
1738
}
 
1739
 
 
1740
 
 
1741
v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
 
1742
    uint32_t index,
 
1743
    const AccessorInfo& info) {
 
1744
  ApiTestFuzzer::Fuzz();
 
1745
  CHECK(info.This()->Equals(bottom));
 
1746
  return v8::Handle<v8::Boolean>();
 
1747
}
 
1748
 
 
1749
 
 
1750
v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
 
1751
    Local<String> property,
 
1752
    const AccessorInfo& info) {
 
1753
  ApiTestFuzzer::Fuzz();
 
1754
  CHECK(info.This()->Equals(bottom));
 
1755
  return v8::Handle<v8::Boolean>();
 
1756
}
 
1757
 
 
1758
 
 
1759
v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
 
1760
    const AccessorInfo& info) {
 
1761
  ApiTestFuzzer::Fuzz();
 
1762
  CHECK(info.This()->Equals(bottom));
 
1763
  return v8::Handle<v8::Array>();
 
1764
}
 
1765
 
 
1766
 
 
1767
v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
 
1768
    const AccessorInfo& info) {
 
1769
  ApiTestFuzzer::Fuzz();
 
1770
  CHECK(info.This()->Equals(bottom));
 
1771
  return v8::Handle<v8::Array>();
 
1772
}
 
1773
 
 
1774
 
 
1775
THREADED_TEST(PropertyHandlerInPrototype) {
 
1776
  v8::HandleScope scope;
 
1777
  LocalContext env;
 
1778
 
 
1779
  // Set up a prototype chain with three interceptors.
 
1780
  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
1781
  templ->InstanceTemplate()->SetIndexedPropertyHandler(
 
1782
      CheckThisIndexedPropertyHandler,
 
1783
      CheckThisIndexedPropertySetter,
 
1784
      CheckThisIndexedPropertyQuery,
 
1785
      CheckThisIndexedPropertyDeleter,
 
1786
      CheckThisIndexedPropertyEnumerator);
 
1787
 
 
1788
  templ->InstanceTemplate()->SetNamedPropertyHandler(
 
1789
      CheckThisNamedPropertyHandler,
 
1790
      CheckThisNamedPropertySetter,
 
1791
      CheckThisNamedPropertyQuery,
 
1792
      CheckThisNamedPropertyDeleter,
 
1793
      CheckThisNamedPropertyEnumerator);
 
1794
 
 
1795
  bottom = templ->GetFunction()->NewInstance();
 
1796
  Local<v8::Object> top = templ->GetFunction()->NewInstance();
 
1797
  Local<v8::Object> middle = templ->GetFunction()->NewInstance();
 
1798
 
 
1799
  bottom->Set(v8_str("__proto__"), middle);
 
1800
  middle->Set(v8_str("__proto__"), top);
 
1801
  env->Global()->Set(v8_str("obj"), bottom);
 
1802
 
 
1803
  // Indexed and named get.
 
1804
  Script::Compile(v8_str("obj[0]"))->Run();
 
1805
  Script::Compile(v8_str("obj.x"))->Run();
 
1806
 
 
1807
  // Indexed and named set.
 
1808
  Script::Compile(v8_str("obj[1] = 42"))->Run();
 
1809
  Script::Compile(v8_str("obj.y = 42"))->Run();
 
1810
 
 
1811
  // Indexed and named query.
 
1812
  Script::Compile(v8_str("0 in obj"))->Run();
 
1813
  Script::Compile(v8_str("'x' in obj"))->Run();
 
1814
 
 
1815
  // Indexed and named deleter.
 
1816
  Script::Compile(v8_str("delete obj[0]"))->Run();
 
1817
  Script::Compile(v8_str("delete obj.x"))->Run();
 
1818
 
 
1819
  // Enumerators.
 
1820
  Script::Compile(v8_str("for (var p in obj) ;"))->Run();
 
1821
}
 
1822
 
 
1823
 
 
1824
static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
 
1825
                                               const AccessorInfo& info) {
 
1826
  ApiTestFuzzer::Fuzz();
 
1827
  if (v8_str("pre")->Equals(key)) {
 
1828
    return v8_str("PrePropertyHandler: pre");
 
1829
  }
 
1830
  return v8::Handle<String>();
 
1831
}
 
1832
 
 
1833
 
 
1834
static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
 
1835
                                                       const AccessorInfo&) {
 
1836
  if (v8_str("pre")->Equals(key)) {
 
1837
    return v8::Integer::New(v8::None);
 
1838
  }
 
1839
 
 
1840
  return v8::Handle<v8::Integer>();  // do not intercept the call
 
1841
}
 
1842
 
 
1843
 
 
1844
THREADED_TEST(PrePropertyHandler) {
 
1845
  v8::HandleScope scope;
 
1846
  v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
 
1847
  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
 
1848
                                                    0,
 
1849
                                                    PrePropertyHandlerQuery);
 
1850
  LocalContext env(NULL, desc->InstanceTemplate());
 
1851
  Script::Compile(v8_str(
 
1852
      "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
 
1853
  v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
 
1854
  CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
 
1855
  v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
 
1856
  CHECK_EQ(v8_str("Object: on"), result_on);
 
1857
  v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
 
1858
  CHECK(result_post.IsEmpty());
 
1859
}
 
1860
 
 
1861
 
 
1862
THREADED_TEST(UndefinedIsNotEnumerable) {
 
1863
  v8::HandleScope scope;
 
1864
  LocalContext env;
 
1865
  v8::Handle<Value> result = Script::Compile(v8_str(
 
1866
      "this.propertyIsEnumerable(undefined)"))->Run();
 
1867
  CHECK(result->IsFalse());
 
1868
}
 
1869
 
 
1870
 
 
1871
v8::Handle<Script> call_recursively_script;
 
1872
static const int kTargetRecursionDepth = 200;  // near maximum
 
1873
 
 
1874
 
 
1875
static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
 
1876
  ApiTestFuzzer::Fuzz();
 
1877
  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
 
1878
  if (depth == kTargetRecursionDepth) return v8::Undefined();
 
1879
  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
 
1880
  return call_recursively_script->Run();
 
1881
}
 
1882
 
 
1883
 
 
1884
static v8::Handle<Value> CallFunctionRecursivelyCall(
 
1885
    const v8::Arguments& args) {
 
1886
  ApiTestFuzzer::Fuzz();
 
1887
  int depth = args.This()->Get(v8_str("depth"))->Int32Value();
 
1888
  if (depth == kTargetRecursionDepth) {
 
1889
    printf("[depth = %d]\n", depth);
 
1890
    return v8::Undefined();
 
1891
  }
 
1892
  args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
 
1893
  v8::Handle<Value> function =
 
1894
      args.This()->Get(v8_str("callFunctionRecursively"));
 
1895
  return function.As<Function>()->Call(args.This(), 0, NULL);
 
1896
}
 
1897
 
 
1898
 
 
1899
THREADED_TEST(DeepCrossLanguageRecursion) {
 
1900
  v8::HandleScope scope;
 
1901
  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
 
1902
  global->Set(v8_str("callScriptRecursively"),
 
1903
              v8::FunctionTemplate::New(CallScriptRecursivelyCall));
 
1904
  global->Set(v8_str("callFunctionRecursively"),
 
1905
              v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
 
1906
  LocalContext env(NULL, global);
 
1907
 
 
1908
  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
 
1909
  call_recursively_script = v8_compile("callScriptRecursively()");
 
1910
  call_recursively_script->Run();
 
1911
  call_recursively_script = v8::Handle<Script>();
 
1912
 
 
1913
  env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
 
1914
  Script::Compile(v8_str("callFunctionRecursively()"))->Run();
 
1915
}
 
1916
 
 
1917
 
 
1918
static v8::Handle<Value>
 
1919
    ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
 
1920
  ApiTestFuzzer::Fuzz();
 
1921
  return v8::ThrowException(key);
 
1922
}
 
1923
 
 
1924
 
 
1925
static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
 
1926
                                                    Local<Value>,
 
1927
                                                    const AccessorInfo&) {
 
1928
  v8::ThrowException(key);
 
1929
  return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
 
1930
}
 
1931
 
 
1932
 
 
1933
THREADED_TEST(CallbackExceptionRegression) {
 
1934
  v8::HandleScope scope;
 
1935
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
1936
  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
 
1937
                               ThrowingPropertyHandlerSet);
 
1938
  LocalContext env;
 
1939
  env->Global()->Set(v8_str("obj"), obj->NewInstance());
 
1940
  v8::Handle<Value> otto = Script::Compile(v8_str(
 
1941
      "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
 
1942
  CHECK_EQ(v8_str("otto"), otto);
 
1943
  v8::Handle<Value> netto = Script::Compile(v8_str(
 
1944
      "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
 
1945
  CHECK_EQ(v8_str("netto"), netto);
 
1946
}
 
1947
 
 
1948
 
 
1949
THREADED_TEST(FunctionPrototype) {
 
1950
  v8::HandleScope scope;
 
1951
  Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
 
1952
  Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
 
1953
  LocalContext env;
 
1954
  env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
 
1955
  Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
 
1956
  CHECK_EQ(script->Run()->Int32Value(), 321);
 
1957
}
 
1958
 
 
1959
 
 
1960
THREADED_TEST(InternalFields) {
 
1961
  v8::HandleScope scope;
 
1962
  LocalContext env;
 
1963
 
 
1964
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
1965
  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
 
1966
  instance_templ->SetInternalFieldCount(1);
 
1967
  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
 
1968
  CHECK_EQ(1, obj->InternalFieldCount());
 
1969
  CHECK(obj->GetInternalField(0)->IsUndefined());
 
1970
  obj->SetInternalField(0, v8_num(17));
 
1971
  CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
 
1972
}
 
1973
 
 
1974
 
 
1975
THREADED_TEST(GlobalObjectInternalFields) {
 
1976
  v8::HandleScope scope;
 
1977
  Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
1978
  global_template->SetInternalFieldCount(1);
 
1979
  LocalContext env(NULL, global_template);
 
1980
  v8::Handle<v8::Object> global_proxy = env->Global();
 
1981
  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
 
1982
  CHECK_EQ(1, global->InternalFieldCount());
 
1983
  CHECK(global->GetInternalField(0)->IsUndefined());
 
1984
  global->SetInternalField(0, v8_num(17));
 
1985
  CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
 
1986
}
 
1987
 
 
1988
 
 
1989
THREADED_TEST(InternalFieldsNativePointers) {
 
1990
  v8::HandleScope scope;
 
1991
  LocalContext env;
 
1992
 
 
1993
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
1994
  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
 
1995
  instance_templ->SetInternalFieldCount(1);
 
1996
  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
 
1997
  CHECK_EQ(1, obj->InternalFieldCount());
 
1998
  CHECK(obj->GetPointerFromInternalField(0) == NULL);
 
1999
 
 
2000
  char* data = new char[100];
 
2001
 
 
2002
  void* aligned = data;
 
2003
  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
 
2004
  void* unaligned = data + 1;
 
2005
  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
 
2006
 
 
2007
  // Check reading and writing aligned pointers.
 
2008
  obj->SetPointerInInternalField(0, aligned);
 
2009
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2010
  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
 
2011
 
 
2012
  // Check reading and writing unaligned pointers.
 
2013
  obj->SetPointerInInternalField(0, unaligned);
 
2014
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2015
  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
 
2016
 
 
2017
  delete[] data;
 
2018
}
 
2019
 
 
2020
 
 
2021
THREADED_TEST(InternalFieldsNativePointersAndExternal) {
 
2022
  v8::HandleScope scope;
 
2023
  LocalContext env;
 
2024
 
 
2025
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
2026
  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
 
2027
  instance_templ->SetInternalFieldCount(1);
 
2028
  Local<v8::Object> obj = templ->GetFunction()->NewInstance();
 
2029
  CHECK_EQ(1, obj->InternalFieldCount());
 
2030
  CHECK(obj->GetPointerFromInternalField(0) == NULL);
 
2031
 
 
2032
  char* data = new char[100];
 
2033
 
 
2034
  void* aligned = data;
 
2035
  CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
 
2036
  void* unaligned = data + 1;
 
2037
  CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
 
2038
 
 
2039
  obj->SetPointerInInternalField(0, aligned);
 
2040
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2041
  CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
 
2042
 
 
2043
  obj->SetPointerInInternalField(0, unaligned);
 
2044
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2045
  CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
 
2046
 
 
2047
  obj->SetInternalField(0, v8::External::Wrap(aligned));
 
2048
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2049
  CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
 
2050
 
 
2051
  obj->SetInternalField(0, v8::External::Wrap(unaligned));
 
2052
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2053
  CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
 
2054
 
 
2055
  delete[] data;
 
2056
}
 
2057
 
 
2058
 
 
2059
THREADED_TEST(IdentityHash) {
 
2060
  v8::HandleScope scope;
 
2061
  LocalContext env;
 
2062
 
 
2063
  // Ensure that the test starts with an fresh heap to test whether the hash
 
2064
  // code is based on the address.
 
2065
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2066
  Local<v8::Object> obj = v8::Object::New();
 
2067
  int hash = obj->GetIdentityHash();
 
2068
  int hash1 = obj->GetIdentityHash();
 
2069
  CHECK_EQ(hash, hash1);
 
2070
  int hash2 = v8::Object::New()->GetIdentityHash();
 
2071
  // Since the identity hash is essentially a random number two consecutive
 
2072
  // objects should not be assigned the same hash code. If the test below fails
 
2073
  // the random number generator should be evaluated.
 
2074
  CHECK_NE(hash, hash2);
 
2075
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2076
  int hash3 = v8::Object::New()->GetIdentityHash();
 
2077
  // Make sure that the identity hash is not based on the initial address of
 
2078
  // the object alone. If the test below fails the random number generator
 
2079
  // should be evaluated.
 
2080
  CHECK_NE(hash, hash3);
 
2081
  int hash4 = obj->GetIdentityHash();
 
2082
  CHECK_EQ(hash, hash4);
 
2083
 
 
2084
  // Check identity hashes behaviour in the presence of JS accessors.
 
2085
  // Put a getter for 'v8::IdentityHash' on the Object's prototype:
 
2086
  {
 
2087
    CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
 
2088
    Local<v8::Object> o1 = v8::Object::New();
 
2089
    Local<v8::Object> o2 = v8::Object::New();
 
2090
    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
 
2091
  }
 
2092
  {
 
2093
    CompileRun(
 
2094
        "function cnst() { return 42; };\n"
 
2095
        "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
 
2096
    Local<v8::Object> o1 = v8::Object::New();
 
2097
    Local<v8::Object> o2 = v8::Object::New();
 
2098
    CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
 
2099
  }
 
2100
}
 
2101
 
 
2102
 
 
2103
THREADED_TEST(HiddenProperties) {
 
2104
  v8::HandleScope scope;
 
2105
  LocalContext env;
 
2106
 
 
2107
  v8::Local<v8::Object> obj = v8::Object::New();
 
2108
  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
 
2109
  v8::Local<v8::String> empty = v8_str("");
 
2110
  v8::Local<v8::String> prop_name = v8_str("prop_name");
 
2111
 
 
2112
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2113
 
 
2114
  // Make sure delete of a non-existent hidden value works
 
2115
  CHECK(obj->DeleteHiddenValue(key));
 
2116
 
 
2117
  CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
 
2118
  CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
 
2119
  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
 
2120
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2121
 
 
2122
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2123
 
 
2124
  // Make sure we do not find the hidden property.
 
2125
  CHECK(!obj->Has(empty));
 
2126
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2127
  CHECK(obj->Get(empty)->IsUndefined());
 
2128
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2129
  CHECK(obj->Set(empty, v8::Integer::New(2003)));
 
2130
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2131
  CHECK_EQ(2003, obj->Get(empty)->Int32Value());
 
2132
 
 
2133
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2134
 
 
2135
  // Add another property and delete it afterwards to force the object in
 
2136
  // slow case.
 
2137
  CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
 
2138
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2139
  CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
 
2140
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2141
  CHECK(obj->Delete(prop_name));
 
2142
  CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
 
2143
 
 
2144
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
2145
 
 
2146
  CHECK(obj->SetHiddenValue(key, Handle<Value>()));
 
2147
  CHECK(obj->GetHiddenValue(key).IsEmpty());
 
2148
 
 
2149
  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
 
2150
  CHECK(obj->DeleteHiddenValue(key));
 
2151
  CHECK(obj->GetHiddenValue(key).IsEmpty());
 
2152
}
 
2153
 
 
2154
 
 
2155
THREADED_TEST(Regress97784) {
 
2156
  // Regression test for crbug.com/97784
 
2157
  // Messing with the Object.prototype should not have effect on
 
2158
  // hidden properties.
 
2159
  v8::HandleScope scope;
 
2160
  LocalContext env;
 
2161
 
 
2162
  v8::Local<v8::Object> obj = v8::Object::New();
 
2163
  v8::Local<v8::String> key = v8_str("hidden");
 
2164
 
 
2165
  CompileRun(
 
2166
      "set_called = false;"
 
2167
      "Object.defineProperty("
 
2168
      "    Object.prototype,"
 
2169
      "    'hidden',"
 
2170
      "    {get: function() { return 45; },"
 
2171
      "     set: function() { set_called = true; }})");
 
2172
 
 
2173
  CHECK(obj->GetHiddenValue(key).IsEmpty());
 
2174
  // Make sure that the getter and setter from Object.prototype is not invoked.
 
2175
  // If it did we would have full access to the hidden properties in
 
2176
  // the accessor.
 
2177
  CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
 
2178
  ExpectFalse("set_called");
 
2179
  CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
 
2180
}
 
2181
 
 
2182
 
 
2183
static bool interceptor_for_hidden_properties_called;
 
2184
static v8::Handle<Value> InterceptorForHiddenProperties(
 
2185
    Local<String> name, const AccessorInfo& info) {
 
2186
  interceptor_for_hidden_properties_called = true;
 
2187
  return v8::Handle<Value>();
 
2188
}
 
2189
 
 
2190
 
 
2191
THREADED_TEST(HiddenPropertiesWithInterceptors) {
 
2192
  v8::HandleScope scope;
 
2193
  LocalContext context;
 
2194
 
 
2195
  interceptor_for_hidden_properties_called = false;
 
2196
 
 
2197
  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
 
2198
 
 
2199
  // Associate an interceptor with an object and start setting hidden values.
 
2200
  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
2201
  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
 
2202
  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
 
2203
  Local<v8::Function> function = fun_templ->GetFunction();
 
2204
  Local<v8::Object> obj = function->NewInstance();
 
2205
  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
 
2206
  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
 
2207
  CHECK(!interceptor_for_hidden_properties_called);
 
2208
}
 
2209
 
 
2210
 
 
2211
THREADED_TEST(External) {
 
2212
  v8::HandleScope scope;
 
2213
  int x = 3;
 
2214
  Local<v8::External> ext = v8::External::New(&x);
 
2215
  LocalContext env;
 
2216
  env->Global()->Set(v8_str("ext"), ext);
 
2217
  Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
 
2218
  v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
 
2219
  int* ptr = static_cast<int*>(reext->Value());
 
2220
  CHECK_EQ(x, 3);
 
2221
  *ptr = 10;
 
2222
  CHECK_EQ(x, 10);
 
2223
 
 
2224
  // Make sure unaligned pointers are wrapped properly.
 
2225
  char* data = i::StrDup("0123456789");
 
2226
  Local<v8::Value> zero = v8::External::Wrap(&data[0]);
 
2227
  Local<v8::Value> one = v8::External::Wrap(&data[1]);
 
2228
  Local<v8::Value> two = v8::External::Wrap(&data[2]);
 
2229
  Local<v8::Value> three = v8::External::Wrap(&data[3]);
 
2230
 
 
2231
  char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
 
2232
  CHECK_EQ('0', *char_ptr);
 
2233
  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
 
2234
  CHECK_EQ('1', *char_ptr);
 
2235
  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
 
2236
  CHECK_EQ('2', *char_ptr);
 
2237
  char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
 
2238
  CHECK_EQ('3', *char_ptr);
 
2239
  i::DeleteArray(data);
 
2240
}
 
2241
 
 
2242
 
 
2243
THREADED_TEST(GlobalHandle) {
 
2244
  v8::Persistent<String> global;
 
2245
  {
 
2246
    v8::HandleScope scope;
 
2247
    Local<String> str = v8_str("str");
 
2248
    global = v8::Persistent<String>::New(str);
 
2249
  }
 
2250
  CHECK_EQ(global->Length(), 3);
 
2251
  global.Dispose();
 
2252
}
 
2253
 
 
2254
 
 
2255
class WeakCallCounter {
 
2256
 public:
 
2257
  explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
 
2258
  int id() { return id_; }
 
2259
  void increment() { number_of_weak_calls_++; }
 
2260
  int NumberOfWeakCalls() { return number_of_weak_calls_; }
 
2261
 private:
 
2262
  int id_;
 
2263
  int number_of_weak_calls_;
 
2264
};
 
2265
 
 
2266
 
 
2267
static void WeakPointerCallback(Persistent<Value> handle, void* id) {
 
2268
  WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
 
2269
  CHECK_EQ(1234, counter->id());
 
2270
  counter->increment();
 
2271
  handle.Dispose();
 
2272
}
 
2273
 
 
2274
 
 
2275
THREADED_TEST(ApiObjectGroups) {
 
2276
  HandleScope scope;
 
2277
  LocalContext env;
 
2278
 
 
2279
  Persistent<Object> g1s1;
 
2280
  Persistent<Object> g1s2;
 
2281
  Persistent<Object> g1c1;
 
2282
  Persistent<Object> g2s1;
 
2283
  Persistent<Object> g2s2;
 
2284
  Persistent<Object> g2c1;
 
2285
 
 
2286
  WeakCallCounter counter(1234);
 
2287
 
 
2288
  {
 
2289
    HandleScope scope;
 
2290
    g1s1 = Persistent<Object>::New(Object::New());
 
2291
    g1s2 = Persistent<Object>::New(Object::New());
 
2292
    g1c1 = Persistent<Object>::New(Object::New());
 
2293
    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2294
    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2295
    g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2296
 
 
2297
    g2s1 = Persistent<Object>::New(Object::New());
 
2298
    g2s2 = Persistent<Object>::New(Object::New());
 
2299
    g2c1 = Persistent<Object>::New(Object::New());
 
2300
    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2301
    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2302
    g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2303
  }
 
2304
 
 
2305
  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
 
2306
 
 
2307
  // Connect group 1 and 2, make a cycle.
 
2308
  CHECK(g1s2->Set(0, g2s2));
 
2309
  CHECK(g2s1->Set(0, g1s1));
 
2310
 
 
2311
  {
 
2312
    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
 
2313
    Persistent<Value> g1_children[] = { g1c1 };
 
2314
    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
 
2315
    Persistent<Value> g2_children[] = { g2c1 };
 
2316
    V8::AddObjectGroup(g1_objects, 2);
 
2317
    V8::AddImplicitReferences(g1s1, g1_children, 1);
 
2318
    V8::AddObjectGroup(g2_objects, 2);
 
2319
    V8::AddImplicitReferences(g2s2, g2_children, 1);
 
2320
  }
 
2321
  // Do a single full GC, ensure incremental marking is stopped.
 
2322
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
2323
 
 
2324
  // All object should be alive.
 
2325
  CHECK_EQ(0, counter.NumberOfWeakCalls());
 
2326
 
 
2327
  // Weaken the root.
 
2328
  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2329
  // But make children strong roots---all the objects (except for children)
 
2330
  // should be collectable now.
 
2331
  g1c1.ClearWeak();
 
2332
  g2c1.ClearWeak();
 
2333
 
 
2334
  // Groups are deleted, rebuild groups.
 
2335
  {
 
2336
    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
 
2337
    Persistent<Value> g1_children[] = { g1c1 };
 
2338
    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
 
2339
    Persistent<Value> g2_children[] = { g2c1 };
 
2340
    V8::AddObjectGroup(g1_objects, 2);
 
2341
    V8::AddImplicitReferences(g1s1, g1_children, 1);
 
2342
    V8::AddObjectGroup(g2_objects, 2);
 
2343
    V8::AddImplicitReferences(g2s2, g2_children, 1);
 
2344
  }
 
2345
 
 
2346
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
2347
 
 
2348
  // All objects should be gone. 5 global handles in total.
 
2349
  CHECK_EQ(5, counter.NumberOfWeakCalls());
 
2350
 
 
2351
  // And now make children weak again and collect them.
 
2352
  g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2353
  g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2354
 
 
2355
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
2356
  CHECK_EQ(7, counter.NumberOfWeakCalls());
 
2357
}
 
2358
 
 
2359
 
 
2360
THREADED_TEST(ApiObjectGroupsCycle) {
 
2361
  HandleScope scope;
 
2362
  LocalContext env;
 
2363
 
 
2364
  WeakCallCounter counter(1234);
 
2365
 
 
2366
  Persistent<Object> g1s1;
 
2367
  Persistent<Object> g1s2;
 
2368
  Persistent<Object> g2s1;
 
2369
  Persistent<Object> g2s2;
 
2370
  Persistent<Object> g3s1;
 
2371
  Persistent<Object> g3s2;
 
2372
 
 
2373
  {
 
2374
    HandleScope scope;
 
2375
    g1s1 = Persistent<Object>::New(Object::New());
 
2376
    g1s2 = Persistent<Object>::New(Object::New());
 
2377
    g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2378
    g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2379
 
 
2380
    g2s1 = Persistent<Object>::New(Object::New());
 
2381
    g2s2 = Persistent<Object>::New(Object::New());
 
2382
    g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2383
    g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2384
 
 
2385
    g3s1 = Persistent<Object>::New(Object::New());
 
2386
    g3s2 = Persistent<Object>::New(Object::New());
 
2387
    g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2388
    g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2389
  }
 
2390
 
 
2391
  Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
 
2392
 
 
2393
  // Connect groups.  We're building the following cycle:
 
2394
  // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
 
2395
  // groups.
 
2396
  {
 
2397
    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
 
2398
    Persistent<Value> g1_children[] = { g2s1 };
 
2399
    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
 
2400
    Persistent<Value> g2_children[] = { g3s1 };
 
2401
    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
 
2402
    Persistent<Value> g3_children[] = { g1s1 };
 
2403
    V8::AddObjectGroup(g1_objects, 2);
 
2404
    V8::AddImplicitReferences(g1s1, g1_children, 1);
 
2405
    V8::AddObjectGroup(g2_objects, 2);
 
2406
    V8::AddImplicitReferences(g2s1, g2_children, 1);
 
2407
    V8::AddObjectGroup(g3_objects, 2);
 
2408
    V8::AddImplicitReferences(g3s1, g3_children, 1);
 
2409
  }
 
2410
  // Do a single full GC
 
2411
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
2412
 
 
2413
  // All object should be alive.
 
2414
  CHECK_EQ(0, counter.NumberOfWeakCalls());
 
2415
 
 
2416
  // Weaken the root.
 
2417
  root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
 
2418
 
 
2419
  // Groups are deleted, rebuild groups.
 
2420
  {
 
2421
    Persistent<Value> g1_objects[] = { g1s1, g1s2 };
 
2422
    Persistent<Value> g1_children[] = { g2s1 };
 
2423
    Persistent<Value> g2_objects[] = { g2s1, g2s2 };
 
2424
    Persistent<Value> g2_children[] = { g3s1 };
 
2425
    Persistent<Value> g3_objects[] = { g3s1, g3s2 };
 
2426
    Persistent<Value> g3_children[] = { g1s1 };
 
2427
    V8::AddObjectGroup(g1_objects, 2);
 
2428
    V8::AddImplicitReferences(g1s1, g1_children, 1);
 
2429
    V8::AddObjectGroup(g2_objects, 2);
 
2430
    V8::AddImplicitReferences(g2s1, g2_children, 1);
 
2431
    V8::AddObjectGroup(g3_objects, 2);
 
2432
    V8::AddImplicitReferences(g3s1, g3_children, 1);
 
2433
  }
 
2434
 
 
2435
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
2436
 
 
2437
  // All objects should be gone. 7 global handles in total.
 
2438
  CHECK_EQ(7, counter.NumberOfWeakCalls());
 
2439
}
 
2440
 
 
2441
 
 
2442
THREADED_TEST(ScriptException) {
 
2443
  v8::HandleScope scope;
 
2444
  LocalContext env;
 
2445
  Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
 
2446
  v8::TryCatch try_catch;
 
2447
  Local<Value> result = script->Run();
 
2448
  CHECK(result.IsEmpty());
 
2449
  CHECK(try_catch.HasCaught());
 
2450
  String::AsciiValue exception_value(try_catch.Exception());
 
2451
  CHECK_EQ(*exception_value, "panama!");
 
2452
}
 
2453
 
 
2454
 
 
2455
bool message_received;
 
2456
 
 
2457
 
 
2458
static void check_message_0(v8::Handle<v8::Message> message,
 
2459
                            v8::Handle<Value> data) {
 
2460
  CHECK_EQ(5.76, data->NumberValue());
 
2461
  CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
 
2462
  CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
 
2463
  message_received = true;
 
2464
}
 
2465
 
 
2466
 
 
2467
THREADED_TEST(MessageHandler0) {
 
2468
  message_received = false;
 
2469
  v8::HandleScope scope;
 
2470
  CHECK(!message_received);
 
2471
  v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
 
2472
  LocalContext context;
 
2473
  v8::ScriptOrigin origin =
 
2474
      v8::ScriptOrigin(v8_str("6.75"));
 
2475
  v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
 
2476
                                                  &origin);
 
2477
  script->SetData(v8_str("7.56"));
 
2478
  script->Run();
 
2479
  CHECK(message_received);
 
2480
  // clear out the message listener
 
2481
  v8::V8::RemoveMessageListeners(check_message_0);
 
2482
}
 
2483
 
 
2484
 
 
2485
static void check_message_1(v8::Handle<v8::Message> message,
 
2486
                            v8::Handle<Value> data) {
 
2487
  CHECK(data->IsNumber());
 
2488
  CHECK_EQ(1337, data->Int32Value());
 
2489
  message_received = true;
 
2490
}
 
2491
 
 
2492
 
 
2493
TEST(MessageHandler1) {
 
2494
  message_received = false;
 
2495
  v8::HandleScope scope;
 
2496
  CHECK(!message_received);
 
2497
  v8::V8::AddMessageListener(check_message_1);
 
2498
  LocalContext context;
 
2499
  CompileRun("throw 1337;");
 
2500
  CHECK(message_received);
 
2501
  // clear out the message listener
 
2502
  v8::V8::RemoveMessageListeners(check_message_1);
 
2503
}
 
2504
 
 
2505
 
 
2506
static void check_message_2(v8::Handle<v8::Message> message,
 
2507
                            v8::Handle<Value> data) {
 
2508
  LocalContext context;
 
2509
  CHECK(data->IsObject());
 
2510
  v8::Local<v8::Value> hidden_property =
 
2511
      v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
 
2512
  CHECK(v8_str("hidden value")->Equals(hidden_property));
 
2513
  message_received = true;
 
2514
}
 
2515
 
 
2516
 
 
2517
TEST(MessageHandler2) {
 
2518
  message_received = false;
 
2519
  v8::HandleScope scope;
 
2520
  CHECK(!message_received);
 
2521
  v8::V8::AddMessageListener(check_message_2);
 
2522
  LocalContext context;
 
2523
  v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
 
2524
  v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
 
2525
                                           v8_str("hidden value"));
 
2526
  context->Global()->Set(v8_str("error"), error);
 
2527
  CompileRun("throw error;");
 
2528
  CHECK(message_received);
 
2529
  // clear out the message listener
 
2530
  v8::V8::RemoveMessageListeners(check_message_2);
 
2531
}
 
2532
 
 
2533
 
 
2534
THREADED_TEST(GetSetProperty) {
 
2535
  v8::HandleScope scope;
 
2536
  LocalContext context;
 
2537
  context->Global()->Set(v8_str("foo"), v8_num(14));
 
2538
  context->Global()->Set(v8_str("12"), v8_num(92));
 
2539
  context->Global()->Set(v8::Integer::New(16), v8_num(32));
 
2540
  context->Global()->Set(v8_num(13), v8_num(56));
 
2541
  Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
 
2542
  CHECK_EQ(14, foo->Int32Value());
 
2543
  Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
 
2544
  CHECK_EQ(92, twelve->Int32Value());
 
2545
  Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
 
2546
  CHECK_EQ(32, sixteen->Int32Value());
 
2547
  Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
 
2548
  CHECK_EQ(56, thirteen->Int32Value());
 
2549
  CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
 
2550
  CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
 
2551
  CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
 
2552
  CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
 
2553
  CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
 
2554
  CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
 
2555
  CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
 
2556
  CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
 
2557
  CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
 
2558
}
 
2559
 
 
2560
 
 
2561
THREADED_TEST(PropertyAttributes) {
 
2562
  v8::HandleScope scope;
 
2563
  LocalContext context;
 
2564
  // none
 
2565
  Local<String> prop = v8_str("none");
 
2566
  context->Global()->Set(prop, v8_num(7));
 
2567
  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
 
2568
  // read-only
 
2569
  prop = v8_str("read_only");
 
2570
  context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
 
2571
  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
 
2572
  CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
 
2573
  Script::Compile(v8_str("read_only = 9"))->Run();
 
2574
  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
 
2575
  context->Global()->Set(prop, v8_num(10));
 
2576
  CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
 
2577
  // dont-delete
 
2578
  prop = v8_str("dont_delete");
 
2579
  context->Global()->Set(prop, v8_num(13), v8::DontDelete);
 
2580
  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
 
2581
  Script::Compile(v8_str("delete dont_delete"))->Run();
 
2582
  CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
 
2583
  CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
 
2584
  // dont-enum
 
2585
  prop = v8_str("dont_enum");
 
2586
  context->Global()->Set(prop, v8_num(28), v8::DontEnum);
 
2587
  CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
 
2588
  // absent
 
2589
  prop = v8_str("absent");
 
2590
  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
 
2591
  Local<Value> fake_prop = v8_num(1);
 
2592
  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
 
2593
  // exception
 
2594
  TryCatch try_catch;
 
2595
  Local<Value> exception =
 
2596
      CompileRun("({ toString: function() { throw 'exception';} })");
 
2597
  CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
 
2598
  CHECK(try_catch.HasCaught());
 
2599
  String::AsciiValue exception_value(try_catch.Exception());
 
2600
  CHECK_EQ("exception", *exception_value);
 
2601
  try_catch.Reset();
 
2602
}
 
2603
 
 
2604
 
 
2605
THREADED_TEST(Array) {
 
2606
  v8::HandleScope scope;
 
2607
  LocalContext context;
 
2608
  Local<v8::Array> array = v8::Array::New();
 
2609
  CHECK_EQ(0, array->Length());
 
2610
  CHECK(array->Get(0)->IsUndefined());
 
2611
  CHECK(!array->Has(0));
 
2612
  CHECK(array->Get(100)->IsUndefined());
 
2613
  CHECK(!array->Has(100));
 
2614
  array->Set(2, v8_num(7));
 
2615
  CHECK_EQ(3, array->Length());
 
2616
  CHECK(!array->Has(0));
 
2617
  CHECK(!array->Has(1));
 
2618
  CHECK(array->Has(2));
 
2619
  CHECK_EQ(7, array->Get(2)->Int32Value());
 
2620
  Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
 
2621
  Local<v8::Array> arr = obj.As<v8::Array>();
 
2622
  CHECK_EQ(3, arr->Length());
 
2623
  CHECK_EQ(1, arr->Get(0)->Int32Value());
 
2624
  CHECK_EQ(2, arr->Get(1)->Int32Value());
 
2625
  CHECK_EQ(3, arr->Get(2)->Int32Value());
 
2626
  array = v8::Array::New(27);
 
2627
  CHECK_EQ(27, array->Length());
 
2628
  array = v8::Array::New(-27);
 
2629
  CHECK_EQ(0, array->Length());
 
2630
}
 
2631
 
 
2632
 
 
2633
v8::Handle<Value> HandleF(const v8::Arguments& args) {
 
2634
  v8::HandleScope scope;
 
2635
  ApiTestFuzzer::Fuzz();
 
2636
  Local<v8::Array> result = v8::Array::New(args.Length());
 
2637
  for (int i = 0; i < args.Length(); i++)
 
2638
    result->Set(i, args[i]);
 
2639
  return scope.Close(result);
 
2640
}
 
2641
 
 
2642
 
 
2643
THREADED_TEST(Vector) {
 
2644
  v8::HandleScope scope;
 
2645
  Local<ObjectTemplate> global = ObjectTemplate::New();
 
2646
  global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
 
2647
  LocalContext context(0, global);
 
2648
 
 
2649
  const char* fun = "f()";
 
2650
  Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
 
2651
  CHECK_EQ(0, a0->Length());
 
2652
 
 
2653
  const char* fun2 = "f(11)";
 
2654
  Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
 
2655
  CHECK_EQ(1, a1->Length());
 
2656
  CHECK_EQ(11, a1->Get(0)->Int32Value());
 
2657
 
 
2658
  const char* fun3 = "f(12, 13)";
 
2659
  Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
 
2660
  CHECK_EQ(2, a2->Length());
 
2661
  CHECK_EQ(12, a2->Get(0)->Int32Value());
 
2662
  CHECK_EQ(13, a2->Get(1)->Int32Value());
 
2663
 
 
2664
  const char* fun4 = "f(14, 15, 16)";
 
2665
  Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
 
2666
  CHECK_EQ(3, a3->Length());
 
2667
  CHECK_EQ(14, a3->Get(0)->Int32Value());
 
2668
  CHECK_EQ(15, a3->Get(1)->Int32Value());
 
2669
  CHECK_EQ(16, a3->Get(2)->Int32Value());
 
2670
 
 
2671
  const char* fun5 = "f(17, 18, 19, 20)";
 
2672
  Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
 
2673
  CHECK_EQ(4, a4->Length());
 
2674
  CHECK_EQ(17, a4->Get(0)->Int32Value());
 
2675
  CHECK_EQ(18, a4->Get(1)->Int32Value());
 
2676
  CHECK_EQ(19, a4->Get(2)->Int32Value());
 
2677
  CHECK_EQ(20, a4->Get(3)->Int32Value());
 
2678
}
 
2679
 
 
2680
 
 
2681
THREADED_TEST(FunctionCall) {
 
2682
  v8::HandleScope scope;
 
2683
  LocalContext context;
 
2684
  CompileRun(
 
2685
    "function Foo() {"
 
2686
    "  var result = [];"
 
2687
    "  for (var i = 0; i < arguments.length; i++) {"
 
2688
    "    result.push(arguments[i]);"
 
2689
    "  }"
 
2690
    "  return result;"
 
2691
    "}");
 
2692
  Local<Function> Foo =
 
2693
      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
 
2694
 
 
2695
  v8::Handle<Value>* args0 = NULL;
 
2696
  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
 
2697
  CHECK_EQ(0, a0->Length());
 
2698
 
 
2699
  v8::Handle<Value> args1[] = { v8_num(1.1) };
 
2700
  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
 
2701
  CHECK_EQ(1, a1->Length());
 
2702
  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
 
2703
 
 
2704
  v8::Handle<Value> args2[] = { v8_num(2.2),
 
2705
                                v8_num(3.3) };
 
2706
  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
 
2707
  CHECK_EQ(2, a2->Length());
 
2708
  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
 
2709
  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
 
2710
 
 
2711
  v8::Handle<Value> args3[] = { v8_num(4.4),
 
2712
                                v8_num(5.5),
 
2713
                                v8_num(6.6) };
 
2714
  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
 
2715
  CHECK_EQ(3, a3->Length());
 
2716
  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
 
2717
  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
 
2718
  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
 
2719
 
 
2720
  v8::Handle<Value> args4[] = { v8_num(7.7),
 
2721
                                v8_num(8.8),
 
2722
                                v8_num(9.9),
 
2723
                                v8_num(10.11) };
 
2724
  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
 
2725
  CHECK_EQ(4, a4->Length());
 
2726
  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
 
2727
  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
 
2728
  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
 
2729
  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
 
2730
}
 
2731
 
 
2732
 
 
2733
static const char* js_code_causing_out_of_memory =
 
2734
    "var a = new Array(); while(true) a.push(a);";
 
2735
 
 
2736
 
 
2737
// These tests run for a long time and prevent us from running tests
 
2738
// that come after them so they cannot run in parallel.
 
2739
TEST(OutOfMemory) {
 
2740
  // It's not possible to read a snapshot into a heap with different dimensions.
 
2741
  if (i::Snapshot::IsEnabled()) return;
 
2742
  // Set heap limits.
 
2743
  static const int K = 1024;
 
2744
  v8::ResourceConstraints constraints;
 
2745
  constraints.set_max_young_space_size(256 * K);
 
2746
  constraints.set_max_old_space_size(4 * K * K);
 
2747
  v8::SetResourceConstraints(&constraints);
 
2748
 
 
2749
  // Execute a script that causes out of memory.
 
2750
  v8::HandleScope scope;
 
2751
  LocalContext context;
 
2752
  v8::V8::IgnoreOutOfMemoryException();
 
2753
  Local<Script> script =
 
2754
      Script::Compile(String::New(js_code_causing_out_of_memory));
 
2755
  Local<Value> result = script->Run();
 
2756
 
 
2757
  // Check for out of memory state.
 
2758
  CHECK(result.IsEmpty());
 
2759
  CHECK(context->HasOutOfMemoryException());
 
2760
}
 
2761
 
 
2762
 
 
2763
v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
 
2764
  ApiTestFuzzer::Fuzz();
 
2765
 
 
2766
  v8::HandleScope scope;
 
2767
  LocalContext context;
 
2768
  Local<Script> script =
 
2769
      Script::Compile(String::New(js_code_causing_out_of_memory));
 
2770
  Local<Value> result = script->Run();
 
2771
 
 
2772
  // Check for out of memory state.
 
2773
  CHECK(result.IsEmpty());
 
2774
  CHECK(context->HasOutOfMemoryException());
 
2775
 
 
2776
  return result;
 
2777
}
 
2778
 
 
2779
 
 
2780
TEST(OutOfMemoryNested) {
 
2781
  // It's not possible to read a snapshot into a heap with different dimensions.
 
2782
  if (i::Snapshot::IsEnabled()) return;
 
2783
  // Set heap limits.
 
2784
  static const int K = 1024;
 
2785
  v8::ResourceConstraints constraints;
 
2786
  constraints.set_max_young_space_size(256 * K);
 
2787
  constraints.set_max_old_space_size(4 * K * K);
 
2788
  v8::SetResourceConstraints(&constraints);
 
2789
 
 
2790
  v8::HandleScope scope;
 
2791
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
2792
  templ->Set(v8_str("ProvokeOutOfMemory"),
 
2793
             v8::FunctionTemplate::New(ProvokeOutOfMemory));
 
2794
  LocalContext context(0, templ);
 
2795
  v8::V8::IgnoreOutOfMemoryException();
 
2796
  Local<Value> result = CompileRun(
 
2797
    "var thrown = false;"
 
2798
    "try {"
 
2799
    "  ProvokeOutOfMemory();"
 
2800
    "} catch (e) {"
 
2801
    "  thrown = true;"
 
2802
    "}");
 
2803
  // Check for out of memory state.
 
2804
  CHECK(result.IsEmpty());
 
2805
  CHECK(context->HasOutOfMemoryException());
 
2806
}
 
2807
 
 
2808
 
 
2809
TEST(HugeConsStringOutOfMemory) {
 
2810
  // It's not possible to read a snapshot into a heap with different dimensions.
 
2811
  if (i::Snapshot::IsEnabled()) return;
 
2812
  // Set heap limits.
 
2813
  static const int K = 1024;
 
2814
  v8::ResourceConstraints constraints;
 
2815
  constraints.set_max_young_space_size(256 * K);
 
2816
  constraints.set_max_old_space_size(3 * K * K);
 
2817
  v8::SetResourceConstraints(&constraints);
 
2818
 
 
2819
  // Execute a script that causes out of memory.
 
2820
  v8::V8::IgnoreOutOfMemoryException();
 
2821
 
 
2822
  v8::HandleScope scope;
 
2823
  LocalContext context;
 
2824
 
 
2825
  // Build huge string. This should fail with out of memory exception.
 
2826
  Local<Value> result = CompileRun(
 
2827
    "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
 
2828
    "for (var i = 0; i < 22; i++) { str = str + str; }");
 
2829
 
 
2830
  // Check for out of memory state.
 
2831
  CHECK(result.IsEmpty());
 
2832
  CHECK(context->HasOutOfMemoryException());
 
2833
}
 
2834
 
 
2835
 
 
2836
THREADED_TEST(ConstructCall) {
 
2837
  v8::HandleScope scope;
 
2838
  LocalContext context;
 
2839
  CompileRun(
 
2840
    "function Foo() {"
 
2841
    "  var result = [];"
 
2842
    "  for (var i = 0; i < arguments.length; i++) {"
 
2843
    "    result.push(arguments[i]);"
 
2844
    "  }"
 
2845
    "  return result;"
 
2846
    "}");
 
2847
  Local<Function> Foo =
 
2848
      Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
 
2849
 
 
2850
  v8::Handle<Value>* args0 = NULL;
 
2851
  Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
 
2852
  CHECK_EQ(0, a0->Length());
 
2853
 
 
2854
  v8::Handle<Value> args1[] = { v8_num(1.1) };
 
2855
  Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
 
2856
  CHECK_EQ(1, a1->Length());
 
2857
  CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
 
2858
 
 
2859
  v8::Handle<Value> args2[] = { v8_num(2.2),
 
2860
                                v8_num(3.3) };
 
2861
  Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
 
2862
  CHECK_EQ(2, a2->Length());
 
2863
  CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
 
2864
  CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
 
2865
 
 
2866
  v8::Handle<Value> args3[] = { v8_num(4.4),
 
2867
                                v8_num(5.5),
 
2868
                                v8_num(6.6) };
 
2869
  Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
 
2870
  CHECK_EQ(3, a3->Length());
 
2871
  CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
 
2872
  CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
 
2873
  CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
 
2874
 
 
2875
  v8::Handle<Value> args4[] = { v8_num(7.7),
 
2876
                                v8_num(8.8),
 
2877
                                v8_num(9.9),
 
2878
                                v8_num(10.11) };
 
2879
  Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
 
2880
  CHECK_EQ(4, a4->Length());
 
2881
  CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
 
2882
  CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
 
2883
  CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
 
2884
  CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
 
2885
}
 
2886
 
 
2887
 
 
2888
static void CheckUncle(v8::TryCatch* try_catch) {
 
2889
  CHECK(try_catch->HasCaught());
 
2890
  String::AsciiValue str_value(try_catch->Exception());
 
2891
  CHECK_EQ(*str_value, "uncle?");
 
2892
  try_catch->Reset();
 
2893
}
 
2894
 
 
2895
 
 
2896
THREADED_TEST(ConversionNumber) {
 
2897
  v8::HandleScope scope;
 
2898
  LocalContext env;
 
2899
  // Very large number.
 
2900
  CompileRun("var obj = Math.pow(2,32) * 1237;");
 
2901
  Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
2902
  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
 
2903
  CHECK_EQ(0, obj->ToInt32()->Value());
 
2904
  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
 
2905
  // Large number.
 
2906
  CompileRun("var obj = -1234567890123;");
 
2907
  obj = env->Global()->Get(v8_str("obj"));
 
2908
  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
 
2909
  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
 
2910
  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
 
2911
  // Small positive integer.
 
2912
  CompileRun("var obj = 42;");
 
2913
  obj = env->Global()->Get(v8_str("obj"));
 
2914
  CHECK_EQ(42.0, obj->ToNumber()->Value());
 
2915
  CHECK_EQ(42, obj->ToInt32()->Value());
 
2916
  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
 
2917
  // Negative integer.
 
2918
  CompileRun("var obj = -37;");
 
2919
  obj = env->Global()->Get(v8_str("obj"));
 
2920
  CHECK_EQ(-37.0, obj->ToNumber()->Value());
 
2921
  CHECK_EQ(-37, obj->ToInt32()->Value());
 
2922
  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
 
2923
  // Positive non-int32 integer.
 
2924
  CompileRun("var obj = 0x81234567;");
 
2925
  obj = env->Global()->Get(v8_str("obj"));
 
2926
  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
 
2927
  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
 
2928
  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
 
2929
  // Fraction.
 
2930
  CompileRun("var obj = 42.3;");
 
2931
  obj = env->Global()->Get(v8_str("obj"));
 
2932
  CHECK_EQ(42.3, obj->ToNumber()->Value());
 
2933
  CHECK_EQ(42, obj->ToInt32()->Value());
 
2934
  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
 
2935
  // Large negative fraction.
 
2936
  CompileRun("var obj = -5726623061.75;");
 
2937
  obj = env->Global()->Get(v8_str("obj"));
 
2938
  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
 
2939
  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
 
2940
  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
 
2941
}
 
2942
 
 
2943
 
 
2944
THREADED_TEST(isNumberType) {
 
2945
  v8::HandleScope scope;
 
2946
  LocalContext env;
 
2947
  // Very large number.
 
2948
  CompileRun("var obj = Math.pow(2,32) * 1237;");
 
2949
  Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
2950
  CHECK(!obj->IsInt32());
 
2951
  CHECK(!obj->IsUint32());
 
2952
  // Large negative number.
 
2953
  CompileRun("var obj = -1234567890123;");
 
2954
  obj = env->Global()->Get(v8_str("obj"));
 
2955
  CHECK(!obj->IsInt32());
 
2956
  CHECK(!obj->IsUint32());
 
2957
  // Small positive integer.
 
2958
  CompileRun("var obj = 42;");
 
2959
  obj = env->Global()->Get(v8_str("obj"));
 
2960
  CHECK(obj->IsInt32());
 
2961
  CHECK(obj->IsUint32());
 
2962
  // Negative integer.
 
2963
  CompileRun("var obj = -37;");
 
2964
  obj = env->Global()->Get(v8_str("obj"));
 
2965
  CHECK(obj->IsInt32());
 
2966
  CHECK(!obj->IsUint32());
 
2967
  // Positive non-int32 integer.
 
2968
  CompileRun("var obj = 0x81234567;");
 
2969
  obj = env->Global()->Get(v8_str("obj"));
 
2970
  CHECK(!obj->IsInt32());
 
2971
  CHECK(obj->IsUint32());
 
2972
  // Fraction.
 
2973
  CompileRun("var obj = 42.3;");
 
2974
  obj = env->Global()->Get(v8_str("obj"));
 
2975
  CHECK(!obj->IsInt32());
 
2976
  CHECK(!obj->IsUint32());
 
2977
  // Large negative fraction.
 
2978
  CompileRun("var obj = -5726623061.75;");
 
2979
  obj = env->Global()->Get(v8_str("obj"));
 
2980
  CHECK(!obj->IsInt32());
 
2981
  CHECK(!obj->IsUint32());
 
2982
  // Positive zero
 
2983
  CompileRun("var obj = 0.0;");
 
2984
  obj = env->Global()->Get(v8_str("obj"));
 
2985
  CHECK(obj->IsInt32());
 
2986
  CHECK(obj->IsUint32());
 
2987
  // Positive zero
 
2988
  CompileRun("var obj = -0.0;");
 
2989
  obj = env->Global()->Get(v8_str("obj"));
 
2990
  CHECK(!obj->IsInt32());
 
2991
  CHECK(!obj->IsUint32());
 
2992
}
 
2993
 
 
2994
 
 
2995
THREADED_TEST(ConversionException) {
 
2996
  v8::HandleScope scope;
 
2997
  LocalContext env;
 
2998
  CompileRun(
 
2999
    "function TestClass() { };"
 
3000
    "TestClass.prototype.toString = function () { throw 'uncle?'; };"
 
3001
    "var obj = new TestClass();");
 
3002
  Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
3003
 
 
3004
  v8::TryCatch try_catch;
 
3005
 
 
3006
  Local<Value> to_string_result = obj->ToString();
 
3007
  CHECK(to_string_result.IsEmpty());
 
3008
  CheckUncle(&try_catch);
 
3009
 
 
3010
  Local<Value> to_number_result = obj->ToNumber();
 
3011
  CHECK(to_number_result.IsEmpty());
 
3012
  CheckUncle(&try_catch);
 
3013
 
 
3014
  Local<Value> to_integer_result = obj->ToInteger();
 
3015
  CHECK(to_integer_result.IsEmpty());
 
3016
  CheckUncle(&try_catch);
 
3017
 
 
3018
  Local<Value> to_uint32_result = obj->ToUint32();
 
3019
  CHECK(to_uint32_result.IsEmpty());
 
3020
  CheckUncle(&try_catch);
 
3021
 
 
3022
  Local<Value> to_int32_result = obj->ToInt32();
 
3023
  CHECK(to_int32_result.IsEmpty());
 
3024
  CheckUncle(&try_catch);
 
3025
 
 
3026
  Local<Value> to_object_result = v8::Undefined()->ToObject();
 
3027
  CHECK(to_object_result.IsEmpty());
 
3028
  CHECK(try_catch.HasCaught());
 
3029
  try_catch.Reset();
 
3030
 
 
3031
  int32_t int32_value = obj->Int32Value();
 
3032
  CHECK_EQ(0, int32_value);
 
3033
  CheckUncle(&try_catch);
 
3034
 
 
3035
  uint32_t uint32_value = obj->Uint32Value();
 
3036
  CHECK_EQ(0, uint32_value);
 
3037
  CheckUncle(&try_catch);
 
3038
 
 
3039
  double number_value = obj->NumberValue();
 
3040
  CHECK_NE(0, IsNaN(number_value));
 
3041
  CheckUncle(&try_catch);
 
3042
 
 
3043
  int64_t integer_value = obj->IntegerValue();
 
3044
  CHECK_EQ(0.0, static_cast<double>(integer_value));
 
3045
  CheckUncle(&try_catch);
 
3046
}
 
3047
 
 
3048
 
 
3049
v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
 
3050
  ApiTestFuzzer::Fuzz();
 
3051
  return v8::ThrowException(v8_str("konto"));
 
3052
}
 
3053
 
 
3054
 
 
3055
v8::Handle<Value> CCatcher(const v8::Arguments& args) {
 
3056
  if (args.Length() < 1) return v8::False();
 
3057
  v8::HandleScope scope;
 
3058
  v8::TryCatch try_catch;
 
3059
  Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
 
3060
  CHECK(!try_catch.HasCaught() || result.IsEmpty());
 
3061
  return v8::Boolean::New(try_catch.HasCaught());
 
3062
}
 
3063
 
 
3064
 
 
3065
THREADED_TEST(APICatch) {
 
3066
  v8::HandleScope scope;
 
3067
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3068
  templ->Set(v8_str("ThrowFromC"),
 
3069
             v8::FunctionTemplate::New(ThrowFromC));
 
3070
  LocalContext context(0, templ);
 
3071
  CompileRun(
 
3072
    "var thrown = false;"
 
3073
    "try {"
 
3074
    "  ThrowFromC();"
 
3075
    "} catch (e) {"
 
3076
    "  thrown = true;"
 
3077
    "}");
 
3078
  Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
 
3079
  CHECK(thrown->BooleanValue());
 
3080
}
 
3081
 
 
3082
 
 
3083
THREADED_TEST(APIThrowTryCatch) {
 
3084
  v8::HandleScope scope;
 
3085
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3086
  templ->Set(v8_str("ThrowFromC"),
 
3087
             v8::FunctionTemplate::New(ThrowFromC));
 
3088
  LocalContext context(0, templ);
 
3089
  v8::TryCatch try_catch;
 
3090
  CompileRun("ThrowFromC();");
 
3091
  CHECK(try_catch.HasCaught());
 
3092
}
 
3093
 
 
3094
 
 
3095
// Test that a try-finally block doesn't shadow a try-catch block
 
3096
// when setting up an external handler.
 
3097
//
 
3098
// BUG(271): Some of the exception propagation does not work on the
 
3099
// ARM simulator because the simulator separates the C++ stack and the
 
3100
// JS stack.  This test therefore fails on the simulator.  The test is
 
3101
// not threaded to allow the threading tests to run on the simulator.
 
3102
TEST(TryCatchInTryFinally) {
 
3103
  v8::HandleScope scope;
 
3104
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3105
  templ->Set(v8_str("CCatcher"),
 
3106
             v8::FunctionTemplate::New(CCatcher));
 
3107
  LocalContext context(0, templ);
 
3108
  Local<Value> result = CompileRun("try {"
 
3109
                                   "  try {"
 
3110
                                   "    CCatcher('throw 7;');"
 
3111
                                   "  } finally {"
 
3112
                                   "  }"
 
3113
                                   "} catch (e) {"
 
3114
                                   "}");
 
3115
  CHECK(result->IsTrue());
 
3116
}
 
3117
 
 
3118
 
 
3119
static void check_reference_error_message(
 
3120
    v8::Handle<v8::Message> message,
 
3121
    v8::Handle<v8::Value> data) {
 
3122
  const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
 
3123
  CHECK(message->Get()->Equals(v8_str(reference_error)));
 
3124
}
 
3125
 
 
3126
 
 
3127
static v8::Handle<Value> Fail(const v8::Arguments& args) {
 
3128
  ApiTestFuzzer::Fuzz();
 
3129
  CHECK(false);
 
3130
  return v8::Undefined();
 
3131
}
 
3132
 
 
3133
 
 
3134
// Test that overwritten methods are not invoked on uncaught exception
 
3135
// formatting. However, they are invoked when performing normal error
 
3136
// string conversions.
 
3137
TEST(APIThrowMessageOverwrittenToString) {
 
3138
  v8::HandleScope scope;
 
3139
  v8::V8::AddMessageListener(check_reference_error_message);
 
3140
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3141
  templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
 
3142
  LocalContext context(NULL, templ);
 
3143
  CompileRun("asdf;");
 
3144
  CompileRun("var limit = {};"
 
3145
             "limit.valueOf = fail;"
 
3146
             "Error.stackTraceLimit = limit;");
 
3147
  CompileRun("asdf");
 
3148
  CompileRun("Array.prototype.pop = fail;");
 
3149
  CompileRun("Object.prototype.hasOwnProperty = fail;");
 
3150
  CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
 
3151
  CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
 
3152
  CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
 
3153
  CompileRun("ReferenceError.prototype.toString ="
 
3154
             "  function() { return 'Whoops' }");
 
3155
  CompileRun("asdf;");
 
3156
  CompileRun("ReferenceError.prototype.constructor.name = void 0;");
 
3157
  CompileRun("asdf;");
 
3158
  CompileRun("ReferenceError.prototype.constructor = void 0;");
 
3159
  CompileRun("asdf;");
 
3160
  CompileRun("ReferenceError.prototype.__proto__ = new Object();");
 
3161
  CompileRun("asdf;");
 
3162
  CompileRun("ReferenceError.prototype = new Object();");
 
3163
  CompileRun("asdf;");
 
3164
  v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
 
3165
  CHECK(string->Equals(v8_str("Whoops")));
 
3166
  CompileRun("ReferenceError.prototype.constructor = new Object();"
 
3167
             "ReferenceError.prototype.constructor.name = 1;"
 
3168
             "Number.prototype.toString = function() { return 'Whoops'; };"
 
3169
             "ReferenceError.prototype.toString = Object.prototype.toString;");
 
3170
  CompileRun("asdf;");
 
3171
  v8::V8::RemoveMessageListeners(check_reference_error_message);
 
3172
}
 
3173
 
 
3174
 
 
3175
static void check_custom_error_message(
 
3176
    v8::Handle<v8::Message> message,
 
3177
    v8::Handle<v8::Value> data) {
 
3178
  const char* uncaught_error = "Uncaught MyError toString";
 
3179
  CHECK(message->Get()->Equals(v8_str(uncaught_error)));
 
3180
}
 
3181
 
 
3182
 
 
3183
TEST(CustomErrorToString) {
 
3184
  v8::HandleScope scope;
 
3185
  v8::V8::AddMessageListener(check_custom_error_message);
 
3186
  LocalContext context;
 
3187
  CompileRun(
 
3188
    "function MyError(name, message) {                   "
 
3189
    "  this.name = name;                                 "
 
3190
    "  this.message = message;                           "
 
3191
    "}                                                   "
 
3192
    "MyError.prototype = Object.create(Error.prototype); "
 
3193
    "MyError.prototype.toString = function() {           "
 
3194
    "  return 'MyError toString';                        "
 
3195
    "};                                                  "
 
3196
    "throw new MyError('my name', 'my message');         ");
 
3197
  v8::V8::RemoveMessageListeners(check_custom_error_message);
 
3198
}
 
3199
 
 
3200
 
 
3201
static void receive_message(v8::Handle<v8::Message> message,
 
3202
                            v8::Handle<v8::Value> data) {
 
3203
  message->Get();
 
3204
  message_received = true;
 
3205
}
 
3206
 
 
3207
 
 
3208
TEST(APIThrowMessage) {
 
3209
  message_received = false;
 
3210
  v8::HandleScope scope;
 
3211
  v8::V8::AddMessageListener(receive_message);
 
3212
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3213
  templ->Set(v8_str("ThrowFromC"),
 
3214
             v8::FunctionTemplate::New(ThrowFromC));
 
3215
  LocalContext context(0, templ);
 
3216
  CompileRun("ThrowFromC();");
 
3217
  CHECK(message_received);
 
3218
  v8::V8::RemoveMessageListeners(receive_message);
 
3219
}
 
3220
 
 
3221
 
 
3222
TEST(APIThrowMessageAndVerboseTryCatch) {
 
3223
  message_received = false;
 
3224
  v8::HandleScope scope;
 
3225
  v8::V8::AddMessageListener(receive_message);
 
3226
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3227
  templ->Set(v8_str("ThrowFromC"),
 
3228
             v8::FunctionTemplate::New(ThrowFromC));
 
3229
  LocalContext context(0, templ);
 
3230
  v8::TryCatch try_catch;
 
3231
  try_catch.SetVerbose(true);
 
3232
  Local<Value> result = CompileRun("ThrowFromC();");
 
3233
  CHECK(try_catch.HasCaught());
 
3234
  CHECK(result.IsEmpty());
 
3235
  CHECK(message_received);
 
3236
  v8::V8::RemoveMessageListeners(receive_message);
 
3237
}
 
3238
 
 
3239
 
 
3240
TEST(APIStackOverflowAndVerboseTryCatch) {
 
3241
  message_received = false;
 
3242
  v8::HandleScope scope;
 
3243
  v8::V8::AddMessageListener(receive_message);
 
3244
  LocalContext context;
 
3245
  v8::TryCatch try_catch;
 
3246
  try_catch.SetVerbose(true);
 
3247
  Local<Value> result = CompileRun("function foo() { foo(); } foo();");
 
3248
  CHECK(try_catch.HasCaught());
 
3249
  CHECK(result.IsEmpty());
 
3250
  CHECK(message_received);
 
3251
  v8::V8::RemoveMessageListeners(receive_message);
 
3252
}
 
3253
 
 
3254
 
 
3255
THREADED_TEST(ExternalScriptException) {
 
3256
  v8::HandleScope scope;
 
3257
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3258
  templ->Set(v8_str("ThrowFromC"),
 
3259
             v8::FunctionTemplate::New(ThrowFromC));
 
3260
  LocalContext context(0, templ);
 
3261
 
 
3262
  v8::TryCatch try_catch;
 
3263
  Local<Script> script
 
3264
      = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
 
3265
  Local<Value> result = script->Run();
 
3266
  CHECK(result.IsEmpty());
 
3267
  CHECK(try_catch.HasCaught());
 
3268
  String::AsciiValue exception_value(try_catch.Exception());
 
3269
  CHECK_EQ("konto", *exception_value);
 
3270
}
 
3271
 
 
3272
 
 
3273
 
 
3274
v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
 
3275
  ApiTestFuzzer::Fuzz();
 
3276
  CHECK_EQ(4, args.Length());
 
3277
  int count = args[0]->Int32Value();
 
3278
  int cInterval = args[2]->Int32Value();
 
3279
  if (count == 0) {
 
3280
    return v8::ThrowException(v8_str("FromC"));
 
3281
  } else {
 
3282
    Local<v8::Object> global = Context::GetCurrent()->Global();
 
3283
    Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
 
3284
    v8::Handle<Value> argv[] = { v8_num(count - 1),
 
3285
                                 args[1],
 
3286
                                 args[2],
 
3287
                                 args[3] };
 
3288
    if (count % cInterval == 0) {
 
3289
      v8::TryCatch try_catch;
 
3290
      Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
 
3291
      int expected = args[3]->Int32Value();
 
3292
      if (try_catch.HasCaught()) {
 
3293
        CHECK_EQ(expected, count);
 
3294
        CHECK(result.IsEmpty());
 
3295
        CHECK(!i::Isolate::Current()->has_scheduled_exception());
 
3296
      } else {
 
3297
        CHECK_NE(expected, count);
 
3298
      }
 
3299
      return result;
 
3300
    } else {
 
3301
      return fun.As<Function>()->Call(global, 4, argv);
 
3302
    }
 
3303
  }
 
3304
}
 
3305
 
 
3306
 
 
3307
v8::Handle<Value> JSCheck(const v8::Arguments& args) {
 
3308
  ApiTestFuzzer::Fuzz();
 
3309
  CHECK_EQ(3, args.Length());
 
3310
  bool equality = args[0]->BooleanValue();
 
3311
  int count = args[1]->Int32Value();
 
3312
  int expected = args[2]->Int32Value();
 
3313
  if (equality) {
 
3314
    CHECK_EQ(count, expected);
 
3315
  } else {
 
3316
    CHECK_NE(count, expected);
 
3317
  }
 
3318
  return v8::Undefined();
 
3319
}
 
3320
 
 
3321
 
 
3322
THREADED_TEST(EvalInTryFinally) {
 
3323
  v8::HandleScope scope;
 
3324
  LocalContext context;
 
3325
  v8::TryCatch try_catch;
 
3326
  CompileRun("(function() {"
 
3327
             "  try {"
 
3328
             "    eval('asldkf (*&^&*^');"
 
3329
             "  } finally {"
 
3330
             "    return;"
 
3331
             "  }"
 
3332
             "})()");
 
3333
  CHECK(!try_catch.HasCaught());
 
3334
}
 
3335
 
 
3336
 
 
3337
// This test works by making a stack of alternating JavaScript and C
 
3338
// activations.  These activations set up exception handlers with regular
 
3339
// intervals, one interval for C activations and another for JavaScript
 
3340
// activations.  When enough activations have been created an exception is
 
3341
// thrown and we check that the right activation catches the exception and that
 
3342
// no other activations do.  The right activation is always the topmost one with
 
3343
// a handler, regardless of whether it is in JavaScript or C.
 
3344
//
 
3345
// The notation used to describe a test case looks like this:
 
3346
//
 
3347
//    *JS[4] *C[3] @JS[2] C[1] JS[0]
 
3348
//
 
3349
// Each entry is an activation, either JS or C.  The index is the count at that
 
3350
// level.  Stars identify activations with exception handlers, the @ identifies
 
3351
// the exception handler that should catch the exception.
 
3352
//
 
3353
// BUG(271): Some of the exception propagation does not work on the
 
3354
// ARM simulator because the simulator separates the C++ stack and the
 
3355
// JS stack.  This test therefore fails on the simulator.  The test is
 
3356
// not threaded to allow the threading tests to run on the simulator.
 
3357
TEST(ExceptionOrder) {
 
3358
  v8::HandleScope scope;
 
3359
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3360
  templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
 
3361
  templ->Set(v8_str("CThrowCountDown"),
 
3362
             v8::FunctionTemplate::New(CThrowCountDown));
 
3363
  LocalContext context(0, templ);
 
3364
  CompileRun(
 
3365
    "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
 
3366
    "  if (count == 0) throw 'FromJS';"
 
3367
    "  if (count % jsInterval == 0) {"
 
3368
    "    try {"
 
3369
    "      var value = CThrowCountDown(count - 1,"
 
3370
    "                                  jsInterval,"
 
3371
    "                                  cInterval,"
 
3372
    "                                  expected);"
 
3373
    "      check(false, count, expected);"
 
3374
    "      return value;"
 
3375
    "    } catch (e) {"
 
3376
    "      check(true, count, expected);"
 
3377
    "    }"
 
3378
    "  } else {"
 
3379
    "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
 
3380
    "  }"
 
3381
    "}");
 
3382
  Local<Function> fun =
 
3383
      Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
 
3384
 
 
3385
  const int argc = 4;
 
3386
  //                             count      jsInterval cInterval  expected
 
3387
 
 
3388
  // *JS[4] *C[3] @JS[2] C[1] JS[0]
 
3389
  v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
 
3390
  fun->Call(fun, argc, a0);
 
3391
 
 
3392
  // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
 
3393
  v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
 
3394
  fun->Call(fun, argc, a1);
 
3395
 
 
3396
  // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
 
3397
  v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
 
3398
  fun->Call(fun, argc, a2);
 
3399
 
 
3400
  // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
 
3401
  v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
 
3402
  fun->Call(fun, argc, a3);
 
3403
 
 
3404
  // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
 
3405
  v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
 
3406
  fun->Call(fun, argc, a4);
 
3407
 
 
3408
  // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
 
3409
  v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
 
3410
  fun->Call(fun, argc, a5);
 
3411
}
 
3412
 
 
3413
 
 
3414
v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
 
3415
  ApiTestFuzzer::Fuzz();
 
3416
  CHECK_EQ(1, args.Length());
 
3417
  return v8::ThrowException(args[0]);
 
3418
}
 
3419
 
 
3420
 
 
3421
THREADED_TEST(ThrowValues) {
 
3422
  v8::HandleScope scope;
 
3423
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3424
  templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
 
3425
  LocalContext context(0, templ);
 
3426
  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
 
3427
    "function Run(obj) {"
 
3428
    "  try {"
 
3429
    "    Throw(obj);"
 
3430
    "  } catch (e) {"
 
3431
    "    return e;"
 
3432
    "  }"
 
3433
    "  return 'no exception';"
 
3434
    "}"
 
3435
    "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
 
3436
  CHECK_EQ(5, result->Length());
 
3437
  CHECK(result->Get(v8::Integer::New(0))->IsString());
 
3438
  CHECK(result->Get(v8::Integer::New(1))->IsNumber());
 
3439
  CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
 
3440
  CHECK(result->Get(v8::Integer::New(2))->IsNumber());
 
3441
  CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
 
3442
  CHECK(result->Get(v8::Integer::New(3))->IsNull());
 
3443
  CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
 
3444
}
 
3445
 
 
3446
 
 
3447
THREADED_TEST(CatchZero) {
 
3448
  v8::HandleScope scope;
 
3449
  LocalContext context;
 
3450
  v8::TryCatch try_catch;
 
3451
  CHECK(!try_catch.HasCaught());
 
3452
  Script::Compile(v8_str("throw 10"))->Run();
 
3453
  CHECK(try_catch.HasCaught());
 
3454
  CHECK_EQ(10, try_catch.Exception()->Int32Value());
 
3455
  try_catch.Reset();
 
3456
  CHECK(!try_catch.HasCaught());
 
3457
  Script::Compile(v8_str("throw 0"))->Run();
 
3458
  CHECK(try_catch.HasCaught());
 
3459
  CHECK_EQ(0, try_catch.Exception()->Int32Value());
 
3460
}
 
3461
 
 
3462
 
 
3463
THREADED_TEST(CatchExceptionFromWith) {
 
3464
  v8::HandleScope scope;
 
3465
  LocalContext context;
 
3466
  v8::TryCatch try_catch;
 
3467
  CHECK(!try_catch.HasCaught());
 
3468
  Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
 
3469
  CHECK(try_catch.HasCaught());
 
3470
}
 
3471
 
 
3472
 
 
3473
THREADED_TEST(TryCatchAndFinallyHidingException) {
 
3474
  v8::HandleScope scope;
 
3475
  LocalContext context;
 
3476
  v8::TryCatch try_catch;
 
3477
  CHECK(!try_catch.HasCaught());
 
3478
  CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
 
3479
  CompileRun("f({toString: function() { throw 42; }});");
 
3480
  CHECK(!try_catch.HasCaught());
 
3481
}
 
3482
 
 
3483
 
 
3484
v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
 
3485
  v8::TryCatch try_catch;
 
3486
  return v8::Undefined();
 
3487
}
 
3488
 
 
3489
 
 
3490
THREADED_TEST(TryCatchAndFinally) {
 
3491
  v8::HandleScope scope;
 
3492
  LocalContext context;
 
3493
  context->Global()->Set(
 
3494
      v8_str("native_with_try_catch"),
 
3495
      v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
 
3496
  v8::TryCatch try_catch;
 
3497
  CHECK(!try_catch.HasCaught());
 
3498
  CompileRun(
 
3499
      "try {\n"
 
3500
      "  throw new Error('a');\n"
 
3501
      "} finally {\n"
 
3502
      "  native_with_try_catch();\n"
 
3503
      "}\n");
 
3504
  CHECK(try_catch.HasCaught());
 
3505
}
 
3506
 
 
3507
 
 
3508
THREADED_TEST(Equality) {
 
3509
  v8::HandleScope scope;
 
3510
  LocalContext context;
 
3511
  // Check that equality works at all before relying on CHECK_EQ
 
3512
  CHECK(v8_str("a")->Equals(v8_str("a")));
 
3513
  CHECK(!v8_str("a")->Equals(v8_str("b")));
 
3514
 
 
3515
  CHECK_EQ(v8_str("a"), v8_str("a"));
 
3516
  CHECK_NE(v8_str("a"), v8_str("b"));
 
3517
  CHECK_EQ(v8_num(1), v8_num(1));
 
3518
  CHECK_EQ(v8_num(1.00), v8_num(1));
 
3519
  CHECK_NE(v8_num(1), v8_num(2));
 
3520
 
 
3521
  // Assume String is not symbol.
 
3522
  CHECK(v8_str("a")->StrictEquals(v8_str("a")));
 
3523
  CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
 
3524
  CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
 
3525
  CHECK(v8_num(1)->StrictEquals(v8_num(1)));
 
3526
  CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
 
3527
  CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
 
3528
  Local<Value> not_a_number = v8_num(i::OS::nan_value());
 
3529
  CHECK(!not_a_number->StrictEquals(not_a_number));
 
3530
  CHECK(v8::False()->StrictEquals(v8::False()));
 
3531
  CHECK(!v8::False()->StrictEquals(v8::Undefined()));
 
3532
 
 
3533
  v8::Handle<v8::Object> obj = v8::Object::New();
 
3534
  v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
 
3535
  CHECK(alias->StrictEquals(obj));
 
3536
  alias.Dispose();
 
3537
}
 
3538
 
 
3539
 
 
3540
THREADED_TEST(MultiRun) {
 
3541
  v8::HandleScope scope;
 
3542
  LocalContext context;
 
3543
  Local<Script> script = Script::Compile(v8_str("x"));
 
3544
  for (int i = 0; i < 10; i++)
 
3545
    script->Run();
 
3546
}
 
3547
 
 
3548
 
 
3549
static v8::Handle<Value> GetXValue(Local<String> name,
 
3550
                                   const AccessorInfo& info) {
 
3551
  ApiTestFuzzer::Fuzz();
 
3552
  CHECK_EQ(info.Data(), v8_str("donut"));
 
3553
  CHECK_EQ(name, v8_str("x"));
 
3554
  return name;
 
3555
}
 
3556
 
 
3557
 
 
3558
THREADED_TEST(SimplePropertyRead) {
 
3559
  v8::HandleScope scope;
 
3560
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3561
  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
 
3562
  LocalContext context;
 
3563
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3564
  Local<Script> script = Script::Compile(v8_str("obj.x"));
 
3565
  for (int i = 0; i < 10; i++) {
 
3566
    Local<Value> result = script->Run();
 
3567
    CHECK_EQ(result, v8_str("x"));
 
3568
  }
 
3569
}
 
3570
 
 
3571
THREADED_TEST(DefinePropertyOnAPIAccessor) {
 
3572
  v8::HandleScope scope;
 
3573
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3574
  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
 
3575
  LocalContext context;
 
3576
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3577
 
 
3578
  // Uses getOwnPropertyDescriptor to check the configurable status
 
3579
  Local<Script> script_desc
 
3580
    = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
 
3581
                             "obj, 'x');"
 
3582
                             "prop.configurable;"));
 
3583
  Local<Value> result = script_desc->Run();
 
3584
  CHECK_EQ(result->BooleanValue(), true);
 
3585
 
 
3586
  // Redefine get - but still configurable
 
3587
  Local<Script> script_define
 
3588
    = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
 
3589
                             "            configurable: true };"
 
3590
                             "Object.defineProperty(obj, 'x', desc);"
 
3591
                             "obj.x"));
 
3592
  result = script_define->Run();
 
3593
  CHECK_EQ(result, v8_num(42));
 
3594
 
 
3595
  // Check that the accessor is still configurable
 
3596
  result = script_desc->Run();
 
3597
  CHECK_EQ(result->BooleanValue(), true);
 
3598
 
 
3599
  // Redefine to a non-configurable
 
3600
  script_define
 
3601
    = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
 
3602
                             "             configurable: false };"
 
3603
                             "Object.defineProperty(obj, 'x', desc);"
 
3604
                             "obj.x"));
 
3605
  result = script_define->Run();
 
3606
  CHECK_EQ(result, v8_num(43));
 
3607
  result = script_desc->Run();
 
3608
  CHECK_EQ(result->BooleanValue(), false);
 
3609
 
 
3610
  // Make sure that it is not possible to redefine again
 
3611
  v8::TryCatch try_catch;
 
3612
  result = script_define->Run();
 
3613
  CHECK(try_catch.HasCaught());
 
3614
  String::AsciiValue exception_value(try_catch.Exception());
 
3615
  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
 
3616
}
 
3617
 
 
3618
THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
 
3619
  v8::HandleScope scope;
 
3620
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3621
  templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
 
3622
  LocalContext context;
 
3623
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3624
 
 
3625
  Local<Script> script_desc = Script::Compile(v8_str("var prop ="
 
3626
                                    "Object.getOwnPropertyDescriptor( "
 
3627
                                    "obj, 'x');"
 
3628
                                    "prop.configurable;"));
 
3629
  Local<Value> result = script_desc->Run();
 
3630
  CHECK_EQ(result->BooleanValue(), true);
 
3631
 
 
3632
  Local<Script> script_define =
 
3633
    Script::Compile(v8_str("var desc = {get: function(){return 42; },"
 
3634
                           "            configurable: true };"
 
3635
                           "Object.defineProperty(obj, 'x', desc);"
 
3636
                           "obj.x"));
 
3637
  result = script_define->Run();
 
3638
  CHECK_EQ(result, v8_num(42));
 
3639
 
 
3640
 
 
3641
  result = script_desc->Run();
 
3642
  CHECK_EQ(result->BooleanValue(), true);
 
3643
 
 
3644
 
 
3645
  script_define =
 
3646
    Script::Compile(v8_str("var desc = {get: function(){return 43; },"
 
3647
                           "            configurable: false };"
 
3648
                           "Object.defineProperty(obj, 'x', desc);"
 
3649
                           "obj.x"));
 
3650
  result = script_define->Run();
 
3651
  CHECK_EQ(result, v8_num(43));
 
3652
  result = script_desc->Run();
 
3653
 
 
3654
  CHECK_EQ(result->BooleanValue(), false);
 
3655
 
 
3656
  v8::TryCatch try_catch;
 
3657
  result = script_define->Run();
 
3658
  CHECK(try_catch.HasCaught());
 
3659
  String::AsciiValue exception_value(try_catch.Exception());
 
3660
  CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
 
3661
}
 
3662
 
 
3663
 
 
3664
static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
 
3665
                                                char const* name) {
 
3666
  return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
 
3667
}
 
3668
 
 
3669
 
 
3670
THREADED_TEST(DefineAPIAccessorOnObject) {
 
3671
  v8::HandleScope scope;
 
3672
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3673
  LocalContext context;
 
3674
 
 
3675
  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
 
3676
  CompileRun("var obj2 = {};");
 
3677
 
 
3678
  CHECK(CompileRun("obj1.x")->IsUndefined());
 
3679
  CHECK(CompileRun("obj2.x")->IsUndefined());
 
3680
 
 
3681
  CHECK(GetGlobalProperty(&context, "obj1")->
 
3682
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3683
 
 
3684
  ExpectString("obj1.x", "x");
 
3685
  CHECK(CompileRun("obj2.x")->IsUndefined());
 
3686
 
 
3687
  CHECK(GetGlobalProperty(&context, "obj2")->
 
3688
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3689
 
 
3690
  ExpectString("obj1.x", "x");
 
3691
  ExpectString("obj2.x", "x");
 
3692
 
 
3693
  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
 
3694
  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
 
3695
 
 
3696
  CompileRun("Object.defineProperty(obj1, 'x',"
 
3697
             "{ get: function() { return 'y'; }, configurable: true })");
 
3698
 
 
3699
  ExpectString("obj1.x", "y");
 
3700
  ExpectString("obj2.x", "x");
 
3701
 
 
3702
  CompileRun("Object.defineProperty(obj2, 'x',"
 
3703
             "{ get: function() { return 'y'; }, configurable: true })");
 
3704
 
 
3705
  ExpectString("obj1.x", "y");
 
3706
  ExpectString("obj2.x", "y");
 
3707
 
 
3708
  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
 
3709
  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
 
3710
 
 
3711
  CHECK(GetGlobalProperty(&context, "obj1")->
 
3712
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3713
  CHECK(GetGlobalProperty(&context, "obj2")->
 
3714
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3715
 
 
3716
  ExpectString("obj1.x", "x");
 
3717
  ExpectString("obj2.x", "x");
 
3718
 
 
3719
  ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
 
3720
  ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
 
3721
 
 
3722
  // Define getters/setters, but now make them not configurable.
 
3723
  CompileRun("Object.defineProperty(obj1, 'x',"
 
3724
             "{ get: function() { return 'z'; }, configurable: false })");
 
3725
  CompileRun("Object.defineProperty(obj2, 'x',"
 
3726
             "{ get: function() { return 'z'; }, configurable: false })");
 
3727
 
 
3728
  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
 
3729
  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
 
3730
 
 
3731
  ExpectString("obj1.x", "z");
 
3732
  ExpectString("obj2.x", "z");
 
3733
 
 
3734
  CHECK(!GetGlobalProperty(&context, "obj1")->
 
3735
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3736
  CHECK(!GetGlobalProperty(&context, "obj2")->
 
3737
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3738
 
 
3739
  ExpectString("obj1.x", "z");
 
3740
  ExpectString("obj2.x", "z");
 
3741
}
 
3742
 
 
3743
 
 
3744
THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
 
3745
  v8::HandleScope scope;
 
3746
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3747
  LocalContext context;
 
3748
 
 
3749
  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
 
3750
  CompileRun("var obj2 = {};");
 
3751
 
 
3752
  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
 
3753
        v8_str("x"),
 
3754
        GetXValue, NULL,
 
3755
        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
 
3756
  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
 
3757
        v8_str("x"),
 
3758
        GetXValue, NULL,
 
3759
        v8_str("donut"), v8::DEFAULT, v8::DontDelete));
 
3760
 
 
3761
  ExpectString("obj1.x", "x");
 
3762
  ExpectString("obj2.x", "x");
 
3763
 
 
3764
  ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
 
3765
  ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
 
3766
 
 
3767
  CHECK(!GetGlobalProperty(&context, "obj1")->
 
3768
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3769
  CHECK(!GetGlobalProperty(&context, "obj2")->
 
3770
      SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
 
3771
 
 
3772
  {
 
3773
    v8::TryCatch try_catch;
 
3774
    CompileRun("Object.defineProperty(obj1, 'x',"
 
3775
        "{get: function() { return 'func'; }})");
 
3776
    CHECK(try_catch.HasCaught());
 
3777
    String::AsciiValue exception_value(try_catch.Exception());
 
3778
    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
 
3779
  }
 
3780
  {
 
3781
    v8::TryCatch try_catch;
 
3782
    CompileRun("Object.defineProperty(obj2, 'x',"
 
3783
        "{get: function() { return 'func'; }})");
 
3784
    CHECK(try_catch.HasCaught());
 
3785
    String::AsciiValue exception_value(try_catch.Exception());
 
3786
    CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
 
3787
  }
 
3788
}
 
3789
 
 
3790
 
 
3791
static v8::Handle<Value> Get239Value(Local<String> name,
 
3792
                                     const AccessorInfo& info) {
 
3793
  ApiTestFuzzer::Fuzz();
 
3794
  CHECK_EQ(info.Data(), v8_str("donut"));
 
3795
  CHECK_EQ(name, v8_str("239"));
 
3796
  return name;
 
3797
}
 
3798
 
 
3799
 
 
3800
THREADED_TEST(ElementAPIAccessor) {
 
3801
  v8::HandleScope scope;
 
3802
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3803
  LocalContext context;
 
3804
 
 
3805
  context->Global()->Set(v8_str("obj1"), templ->NewInstance());
 
3806
  CompileRun("var obj2 = {};");
 
3807
 
 
3808
  CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
 
3809
        v8_str("239"),
 
3810
        Get239Value, NULL,
 
3811
        v8_str("donut")));
 
3812
  CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
 
3813
        v8_str("239"),
 
3814
        Get239Value, NULL,
 
3815
        v8_str("donut")));
 
3816
 
 
3817
  ExpectString("obj1[239]", "239");
 
3818
  ExpectString("obj2[239]", "239");
 
3819
  ExpectString("obj1['239']", "239");
 
3820
  ExpectString("obj2['239']", "239");
 
3821
}
 
3822
 
 
3823
 
 
3824
v8::Persistent<Value> xValue;
 
3825
 
 
3826
 
 
3827
static void SetXValue(Local<String> name,
 
3828
                      Local<Value> value,
 
3829
                      const AccessorInfo& info) {
 
3830
  CHECK_EQ(value, v8_num(4));
 
3831
  CHECK_EQ(info.Data(), v8_str("donut"));
 
3832
  CHECK_EQ(name, v8_str("x"));
 
3833
  CHECK(xValue.IsEmpty());
 
3834
  xValue = v8::Persistent<Value>::New(value);
 
3835
}
 
3836
 
 
3837
 
 
3838
THREADED_TEST(SimplePropertyWrite) {
 
3839
  v8::HandleScope scope;
 
3840
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3841
  templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
 
3842
  LocalContext context;
 
3843
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3844
  Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
 
3845
  for (int i = 0; i < 10; i++) {
 
3846
    CHECK(xValue.IsEmpty());
 
3847
    script->Run();
 
3848
    CHECK_EQ(v8_num(4), xValue);
 
3849
    xValue.Dispose();
 
3850
    xValue = v8::Persistent<Value>();
 
3851
  }
 
3852
}
 
3853
 
 
3854
 
 
3855
THREADED_TEST(SetterOnly) {
 
3856
  v8::HandleScope scope;
 
3857
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3858
  templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
 
3859
  LocalContext context;
 
3860
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3861
  Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
 
3862
  for (int i = 0; i < 10; i++) {
 
3863
    CHECK(xValue.IsEmpty());
 
3864
    script->Run();
 
3865
    CHECK_EQ(v8_num(4), xValue);
 
3866
    xValue.Dispose();
 
3867
    xValue = v8::Persistent<Value>();
 
3868
  }
 
3869
}
 
3870
 
 
3871
 
 
3872
THREADED_TEST(NoAccessors) {
 
3873
  v8::HandleScope scope;
 
3874
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3875
  templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
 
3876
  LocalContext context;
 
3877
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3878
  Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
 
3879
  for (int i = 0; i < 10; i++) {
 
3880
    script->Run();
 
3881
  }
 
3882
}
 
3883
 
 
3884
 
 
3885
static v8::Handle<Value> XPropertyGetter(Local<String> property,
 
3886
                                         const AccessorInfo& info) {
 
3887
  ApiTestFuzzer::Fuzz();
 
3888
  CHECK(info.Data()->IsUndefined());
 
3889
  return property;
 
3890
}
 
3891
 
 
3892
 
 
3893
THREADED_TEST(NamedInterceptorPropertyRead) {
 
3894
  v8::HandleScope scope;
 
3895
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3896
  templ->SetNamedPropertyHandler(XPropertyGetter);
 
3897
  LocalContext context;
 
3898
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
3899
  Local<Script> script = Script::Compile(v8_str("obj.x"));
 
3900
  for (int i = 0; i < 10; i++) {
 
3901
    Local<Value> result = script->Run();
 
3902
    CHECK_EQ(result, v8_str("x"));
 
3903
  }
 
3904
}
 
3905
 
 
3906
 
 
3907
THREADED_TEST(NamedInterceptorDictionaryIC) {
 
3908
  v8::HandleScope scope;
 
3909
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3910
  templ->SetNamedPropertyHandler(XPropertyGetter);
 
3911
  LocalContext context;
 
3912
  // Create an object with a named interceptor.
 
3913
  context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
 
3914
  Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
 
3915
  for (int i = 0; i < 10; i++) {
 
3916
    Local<Value> result = script->Run();
 
3917
    CHECK_EQ(result, v8_str("x"));
 
3918
  }
 
3919
  // Create a slow case object and a function accessing a property in
 
3920
  // that slow case object (with dictionary probing in generated
 
3921
  // code). Then force object with a named interceptor into slow-case,
 
3922
  // pass it to the function, and check that the interceptor is called
 
3923
  // instead of accessing the local property.
 
3924
  Local<Value> result =
 
3925
      CompileRun("function get_x(o) { return o.x; };"
 
3926
                 "var obj = { x : 42, y : 0 };"
 
3927
                 "delete obj.y;"
 
3928
                 "for (var i = 0; i < 10; i++) get_x(obj);"
 
3929
                 "interceptor_obj.x = 42;"
 
3930
                 "interceptor_obj.y = 10;"
 
3931
                 "delete interceptor_obj.y;"
 
3932
                 "get_x(interceptor_obj)");
 
3933
  CHECK_EQ(result, v8_str("x"));
 
3934
}
 
3935
 
 
3936
 
 
3937
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
 
3938
  v8::HandleScope scope;
 
3939
 
 
3940
  v8::Persistent<Context> context1 = Context::New();
 
3941
 
 
3942
  context1->Enter();
 
3943
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
3944
  templ->SetNamedPropertyHandler(XPropertyGetter);
 
3945
  // Create an object with a named interceptor.
 
3946
  v8::Local<v8::Object> object = templ->NewInstance();
 
3947
  context1->Global()->Set(v8_str("interceptor_obj"), object);
 
3948
 
 
3949
  // Force the object into the slow case.
 
3950
  CompileRun("interceptor_obj.y = 0;"
 
3951
             "delete interceptor_obj.y;");
 
3952
  context1->Exit();
 
3953
 
 
3954
  {
 
3955
    // Introduce the object into a different context.
 
3956
    // Repeat named loads to exercise ICs.
 
3957
    LocalContext context2;
 
3958
    context2->Global()->Set(v8_str("interceptor_obj"), object);
 
3959
    Local<Value> result =
 
3960
      CompileRun("function get_x(o) { return o.x; }"
 
3961
                 "interceptor_obj.x = 42;"
 
3962
                 "for (var i=0; i != 10; i++) {"
 
3963
                 "  get_x(interceptor_obj);"
 
3964
                 "}"
 
3965
                 "get_x(interceptor_obj)");
 
3966
    // Check that the interceptor was actually invoked.
 
3967
    CHECK_EQ(result, v8_str("x"));
 
3968
  }
 
3969
 
 
3970
  // Return to the original context and force some object to the slow case
 
3971
  // to cause the NormalizedMapCache to verify.
 
3972
  context1->Enter();
 
3973
  CompileRun("var obj = { x : 0 }; delete obj.x;");
 
3974
  context1->Exit();
 
3975
 
 
3976
  context1.Dispose();
 
3977
}
 
3978
 
 
3979
 
 
3980
static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
 
3981
                                               const AccessorInfo& info) {
 
3982
  // Set x on the prototype object and do not handle the get request.
 
3983
  v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
 
3984
  proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
 
3985
  return v8::Handle<Value>();
 
3986
}
 
3987
 
 
3988
 
 
3989
// This is a regression test for http://crbug.com/20104. Map
 
3990
// transitions should not interfere with post interceptor lookup.
 
3991
THREADED_TEST(NamedInterceptorMapTransitionRead) {
 
3992
  v8::HandleScope scope;
 
3993
  Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
 
3994
  Local<v8::ObjectTemplate> instance_template
 
3995
      = function_template->InstanceTemplate();
 
3996
  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
 
3997
  LocalContext context;
 
3998
  context->Global()->Set(v8_str("F"), function_template->GetFunction());
 
3999
  // Create an instance of F and introduce a map transition for x.
 
4000
  CompileRun("var o = new F(); o.x = 23;");
 
4001
  // Create an instance of F and invoke the getter. The result should be 23.
 
4002
  Local<Value> result = CompileRun("o = new F(); o.x");
 
4003
  CHECK_EQ(result->Int32Value(), 23);
 
4004
}
 
4005
 
 
4006
 
 
4007
static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
 
4008
                                               const AccessorInfo& info) {
 
4009
  ApiTestFuzzer::Fuzz();
 
4010
  if (index == 37) {
 
4011
    return v8::Handle<Value>(v8_num(625));
 
4012
  }
 
4013
  return v8::Handle<Value>();
 
4014
}
 
4015
 
 
4016
 
 
4017
static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
 
4018
                                               Local<Value> value,
 
4019
                                               const AccessorInfo& info) {
 
4020
  ApiTestFuzzer::Fuzz();
 
4021
  if (index == 39) {
 
4022
    return value;
 
4023
  }
 
4024
  return v8::Handle<Value>();
 
4025
}
 
4026
 
 
4027
 
 
4028
THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
 
4029
  v8::HandleScope scope;
 
4030
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4031
  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
 
4032
                                   IndexedPropertySetter);
 
4033
  LocalContext context;
 
4034
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
4035
  Local<Script> getter_script = Script::Compile(v8_str(
 
4036
      "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
 
4037
  Local<Script> setter_script = Script::Compile(v8_str(
 
4038
      "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
 
4039
      "obj[17] = 23;"
 
4040
      "obj.foo;"));
 
4041
  Local<Script> interceptor_setter_script = Script::Compile(v8_str(
 
4042
      "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
 
4043
      "obj[39] = 47;"
 
4044
      "obj.foo;"));  // This setter should not run, due to the interceptor.
 
4045
  Local<Script> interceptor_getter_script = Script::Compile(v8_str(
 
4046
      "obj[37];"));
 
4047
  Local<Value> result = getter_script->Run();
 
4048
  CHECK_EQ(v8_num(5), result);
 
4049
  result = setter_script->Run();
 
4050
  CHECK_EQ(v8_num(23), result);
 
4051
  result = interceptor_setter_script->Run();
 
4052
  CHECK_EQ(v8_num(23), result);
 
4053
  result = interceptor_getter_script->Run();
 
4054
  CHECK_EQ(v8_num(625), result);
 
4055
}
 
4056
 
 
4057
 
 
4058
static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
 
4059
    uint32_t index,
 
4060
    const AccessorInfo& info) {
 
4061
  ApiTestFuzzer::Fuzz();
 
4062
  if (index < 25) {
 
4063
    return v8::Handle<Value>(v8_num(index));
 
4064
  }
 
4065
  return v8::Handle<Value>();
 
4066
}
 
4067
 
 
4068
 
 
4069
static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
 
4070
    uint32_t index,
 
4071
    Local<Value> value,
 
4072
    const AccessorInfo& info) {
 
4073
  ApiTestFuzzer::Fuzz();
 
4074
  if (index < 25) {
 
4075
    return v8::Handle<Value>(v8_num(index));
 
4076
  }
 
4077
  return v8::Handle<Value>();
 
4078
}
 
4079
 
 
4080
 
 
4081
Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
 
4082
    const AccessorInfo& info) {
 
4083
  // Force the list of returned keys to be stored in a FastDoubleArray.
 
4084
  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
 
4085
      "keys = new Array(); keys[125000] = 1;"
 
4086
      "for(i = 0; i < 80000; i++) { keys[i] = i; };"
 
4087
      "keys.length = 25; keys;"));
 
4088
  Local<Value> result = indexed_property_names_script->Run();
 
4089
  return Local<v8::Array>(::v8::Array::Cast(*result));
 
4090
}
 
4091
 
 
4092
 
 
4093
// Make sure that the the interceptor code in the runtime properly handles
 
4094
// merging property name lists for double-array-backed arrays.
 
4095
THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
 
4096
  v8::HandleScope scope;
 
4097
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4098
  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
 
4099
                                   UnboxedDoubleIndexedPropertySetter,
 
4100
                                   0,
 
4101
                                   0,
 
4102
                                   UnboxedDoubleIndexedPropertyEnumerator);
 
4103
  LocalContext context;
 
4104
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
4105
  // When obj is created, force it to be Stored in a FastDoubleArray.
 
4106
  Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
 
4107
      "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
 
4108
      "key_count = 0; "
 
4109
      "for (x in obj) {key_count++;};"
 
4110
      "obj;"));
 
4111
  Local<Value> result = create_unboxed_double_script->Run();
 
4112
  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
 
4113
  Local<Script> key_count_check = Script::Compile(v8_str(
 
4114
      "key_count;"));
 
4115
  result = key_count_check->Run();
 
4116
  CHECK_EQ(v8_num(40013), result);
 
4117
}
 
4118
 
 
4119
 
 
4120
Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
 
4121
    const AccessorInfo& info) {
 
4122
  // Force the list of returned keys to be stored in a Arguments object.
 
4123
  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
 
4124
      "function f(w,x) {"
 
4125
      " return arguments;"
 
4126
      "}"
 
4127
      "keys = f(0, 1, 2, 3);"
 
4128
      "keys;"));
 
4129
  Local<Value> result = indexed_property_names_script->Run();
 
4130
  return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
 
4131
}
 
4132
 
 
4133
 
 
4134
static v8::Handle<Value> NonStrictIndexedPropertyGetter(
 
4135
    uint32_t index,
 
4136
    const AccessorInfo& info) {
 
4137
  ApiTestFuzzer::Fuzz();
 
4138
  if (index < 4) {
 
4139
    return v8::Handle<Value>(v8_num(index));
 
4140
  }
 
4141
  return v8::Handle<Value>();
 
4142
}
 
4143
 
 
4144
 
 
4145
// Make sure that the the interceptor code in the runtime properly handles
 
4146
// merging property name lists for non-string arguments arrays.
 
4147
THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
 
4148
  v8::HandleScope scope;
 
4149
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4150
  templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
 
4151
                                   0,
 
4152
                                   0,
 
4153
                                   0,
 
4154
                                   NonStrictArgsIndexedPropertyEnumerator);
 
4155
  LocalContext context;
 
4156
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
4157
  Local<Script> create_args_script =
 
4158
      Script::Compile(v8_str(
 
4159
          "var key_count = 0;"
 
4160
          "for (x in obj) {key_count++;} key_count;"));
 
4161
  Local<Value> result = create_args_script->Run();
 
4162
  CHECK_EQ(v8_num(4), result);
 
4163
}
 
4164
 
 
4165
 
 
4166
static v8::Handle<Value> IdentityIndexedPropertyGetter(
 
4167
    uint32_t index,
 
4168
    const AccessorInfo& info) {
 
4169
  return v8::Integer::NewFromUnsigned(index);
 
4170
}
 
4171
 
 
4172
 
 
4173
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
 
4174
  v8::HandleScope scope;
 
4175
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4176
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4177
 
 
4178
  LocalContext context;
 
4179
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
4180
 
 
4181
  // Check fast object case.
 
4182
  const char* fast_case_code =
 
4183
      "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
 
4184
  ExpectString(fast_case_code, "0");
 
4185
 
 
4186
  // Check slow case.
 
4187
  const char* slow_case_code =
 
4188
      "obj.x = 1; delete obj.x;"
 
4189
      "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
 
4190
  ExpectString(slow_case_code, "1");
 
4191
}
 
4192
 
 
4193
 
 
4194
THREADED_TEST(IndexedInterceptorWithNoSetter) {
 
4195
  v8::HandleScope scope;
 
4196
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4197
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4198
 
 
4199
  LocalContext context;
 
4200
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
4201
 
 
4202
  const char* code =
 
4203
      "try {"
 
4204
      "  obj[0] = 239;"
 
4205
      "  for (var i = 0; i < 100; i++) {"
 
4206
      "    var v = obj[0];"
 
4207
      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4208
      "  }"
 
4209
      "  'PASSED'"
 
4210
      "} catch(e) {"
 
4211
      "  e"
 
4212
      "}";
 
4213
  ExpectString(code, "PASSED");
 
4214
}
 
4215
 
 
4216
 
 
4217
THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
 
4218
  v8::HandleScope scope;
 
4219
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4220
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4221
 
 
4222
  LocalContext context;
 
4223
  Local<v8::Object> obj = templ->NewInstance();
 
4224
  obj->TurnOnAccessCheck();
 
4225
  context->Global()->Set(v8_str("obj"), obj);
 
4226
 
 
4227
  const char* code =
 
4228
      "try {"
 
4229
      "  for (var i = 0; i < 100; i++) {"
 
4230
      "    var v = obj[0];"
 
4231
      "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4232
      "  }"
 
4233
      "  'PASSED'"
 
4234
      "} catch(e) {"
 
4235
      "  e"
 
4236
      "}";
 
4237
  ExpectString(code, "PASSED");
 
4238
}
 
4239
 
 
4240
 
 
4241
THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
 
4242
  i::FLAG_allow_natives_syntax = true;
 
4243
  v8::HandleScope scope;
 
4244
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4245
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4246
 
 
4247
  LocalContext context;
 
4248
  Local<v8::Object> obj = templ->NewInstance();
 
4249
  context->Global()->Set(v8_str("obj"), obj);
 
4250
 
 
4251
  const char* code =
 
4252
      "try {"
 
4253
      "  for (var i = 0; i < 100; i++) {"
 
4254
      "    var expected = i;"
 
4255
      "    if (i == 5) {"
 
4256
      "      %EnableAccessChecks(obj);"
 
4257
      "      expected = undefined;"
 
4258
      "    }"
 
4259
      "    var v = obj[i];"
 
4260
      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4261
      "    if (i == 5) %DisableAccessChecks(obj);"
 
4262
      "  }"
 
4263
      "  'PASSED'"
 
4264
      "} catch(e) {"
 
4265
      "  e"
 
4266
      "}";
 
4267
  ExpectString(code, "PASSED");
 
4268
}
 
4269
 
 
4270
 
 
4271
THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
 
4272
  v8::HandleScope scope;
 
4273
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4274
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4275
 
 
4276
  LocalContext context;
 
4277
  Local<v8::Object> obj = templ->NewInstance();
 
4278
  context->Global()->Set(v8_str("obj"), obj);
 
4279
 
 
4280
  const char* code =
 
4281
      "try {"
 
4282
      "  for (var i = 0; i < 100; i++) {"
 
4283
      "    var v = obj[i];"
 
4284
      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4285
      "  }"
 
4286
      "  'PASSED'"
 
4287
      "} catch(e) {"
 
4288
      "  e"
 
4289
      "}";
 
4290
  ExpectString(code, "PASSED");
 
4291
}
 
4292
 
 
4293
 
 
4294
THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
 
4295
  v8::HandleScope scope;
 
4296
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4297
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4298
 
 
4299
  LocalContext context;
 
4300
  Local<v8::Object> obj = templ->NewInstance();
 
4301
  context->Global()->Set(v8_str("obj"), obj);
 
4302
 
 
4303
  const char* code =
 
4304
      "try {"
 
4305
      "  for (var i = 0; i < 100; i++) {"
 
4306
      "    var expected = i;"
 
4307
      "    var key = i;"
 
4308
      "    if (i == 25) {"
 
4309
      "       key = -1;"
 
4310
      "       expected = undefined;"
 
4311
      "    }"
 
4312
      "    if (i == 50) {"
 
4313
      "       /* probe minimal Smi number on 32-bit platforms */"
 
4314
      "       key = -(1 << 30);"
 
4315
      "       expected = undefined;"
 
4316
      "    }"
 
4317
      "    if (i == 75) {"
 
4318
      "       /* probe minimal Smi number on 64-bit platforms */"
 
4319
      "       key = 1 << 31;"
 
4320
      "       expected = undefined;"
 
4321
      "    }"
 
4322
      "    var v = obj[key];"
 
4323
      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4324
      "  }"
 
4325
      "  'PASSED'"
 
4326
      "} catch(e) {"
 
4327
      "  e"
 
4328
      "}";
 
4329
  ExpectString(code, "PASSED");
 
4330
}
 
4331
 
 
4332
 
 
4333
THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
 
4334
  v8::HandleScope scope;
 
4335
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4336
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4337
 
 
4338
  LocalContext context;
 
4339
  Local<v8::Object> obj = templ->NewInstance();
 
4340
  context->Global()->Set(v8_str("obj"), obj);
 
4341
 
 
4342
  const char* code =
 
4343
      "try {"
 
4344
      "  for (var i = 0; i < 100; i++) {"
 
4345
      "    var expected = i;"
 
4346
      "    var key = i;"
 
4347
      "    if (i == 50) {"
 
4348
      "       key = 'foobar';"
 
4349
      "       expected = undefined;"
 
4350
      "    }"
 
4351
      "    var v = obj[key];"
 
4352
      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4353
      "  }"
 
4354
      "  'PASSED'"
 
4355
      "} catch(e) {"
 
4356
      "  e"
 
4357
      "}";
 
4358
  ExpectString(code, "PASSED");
 
4359
}
 
4360
 
 
4361
 
 
4362
THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
 
4363
  v8::HandleScope scope;
 
4364
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4365
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4366
 
 
4367
  LocalContext context;
 
4368
  Local<v8::Object> obj = templ->NewInstance();
 
4369
  context->Global()->Set(v8_str("obj"), obj);
 
4370
 
 
4371
  const char* code =
 
4372
      "var original = obj;"
 
4373
      "try {"
 
4374
      "  for (var i = 0; i < 100; i++) {"
 
4375
      "    var expected = i;"
 
4376
      "    if (i == 50) {"
 
4377
      "       obj = {50: 'foobar'};"
 
4378
      "       expected = 'foobar';"
 
4379
      "    }"
 
4380
      "    var v = obj[i];"
 
4381
      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4382
      "    if (i == 50) obj = original;"
 
4383
      "  }"
 
4384
      "  'PASSED'"
 
4385
      "} catch(e) {"
 
4386
      "  e"
 
4387
      "}";
 
4388
  ExpectString(code, "PASSED");
 
4389
}
 
4390
 
 
4391
 
 
4392
THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
 
4393
  v8::HandleScope scope;
 
4394
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4395
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4396
 
 
4397
  LocalContext context;
 
4398
  Local<v8::Object> obj = templ->NewInstance();
 
4399
  context->Global()->Set(v8_str("obj"), obj);
 
4400
 
 
4401
  const char* code =
 
4402
      "var original = obj;"
 
4403
      "try {"
 
4404
      "  for (var i = 0; i < 100; i++) {"
 
4405
      "    var expected = i;"
 
4406
      "    if (i == 5) {"
 
4407
      "       obj = 239;"
 
4408
      "       expected = undefined;"
 
4409
      "    }"
 
4410
      "    var v = obj[i];"
 
4411
      "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4412
      "    if (i == 5) obj = original;"
 
4413
      "  }"
 
4414
      "  'PASSED'"
 
4415
      "} catch(e) {"
 
4416
      "  e"
 
4417
      "}";
 
4418
  ExpectString(code, "PASSED");
 
4419
}
 
4420
 
 
4421
 
 
4422
THREADED_TEST(IndexedInterceptorOnProto) {
 
4423
  v8::HandleScope scope;
 
4424
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4425
  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
 
4426
 
 
4427
  LocalContext context;
 
4428
  Local<v8::Object> obj = templ->NewInstance();
 
4429
  context->Global()->Set(v8_str("obj"), obj);
 
4430
 
 
4431
  const char* code =
 
4432
      "var o = {__proto__: obj};"
 
4433
      "try {"
 
4434
      "  for (var i = 0; i < 100; i++) {"
 
4435
      "    var v = o[i];"
 
4436
      "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
 
4437
      "  }"
 
4438
      "  'PASSED'"
 
4439
      "} catch(e) {"
 
4440
      "  e"
 
4441
      "}";
 
4442
  ExpectString(code, "PASSED");
 
4443
}
 
4444
 
 
4445
 
 
4446
THREADED_TEST(MultiContexts) {
 
4447
  v8::HandleScope scope;
 
4448
  v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
4449
  templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
 
4450
 
 
4451
  Local<String> password = v8_str("Password");
 
4452
 
 
4453
  // Create an environment
 
4454
  LocalContext context0(0, templ);
 
4455
  context0->SetSecurityToken(password);
 
4456
  v8::Handle<v8::Object> global0 = context0->Global();
 
4457
  global0->Set(v8_str("custom"), v8_num(1234));
 
4458
  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
 
4459
 
 
4460
  // Create an independent environment
 
4461
  LocalContext context1(0, templ);
 
4462
  context1->SetSecurityToken(password);
 
4463
  v8::Handle<v8::Object> global1 = context1->Global();
 
4464
  global1->Set(v8_str("custom"), v8_num(1234));
 
4465
  CHECK_NE(global0, global1);
 
4466
  CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
 
4467
  CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
 
4468
 
 
4469
  // Now create a new context with the old global
 
4470
  LocalContext context2(0, templ, global1);
 
4471
  context2->SetSecurityToken(password);
 
4472
  v8::Handle<v8::Object> global2 = context2->Global();
 
4473
  CHECK_EQ(global1, global2);
 
4474
  CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
 
4475
  CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
 
4476
}
 
4477
 
 
4478
 
 
4479
THREADED_TEST(FunctionPrototypeAcrossContexts) {
 
4480
  // Make sure that functions created by cloning boilerplates cannot
 
4481
  // communicate through their __proto__ field.
 
4482
 
 
4483
  v8::HandleScope scope;
 
4484
 
 
4485
  LocalContext env0;
 
4486
  v8::Handle<v8::Object> global0 =
 
4487
      env0->Global();
 
4488
  v8::Handle<v8::Object> object0 =
 
4489
      global0->Get(v8_str("Object")).As<v8::Object>();
 
4490
  v8::Handle<v8::Object> tostring0 =
 
4491
      object0->Get(v8_str("toString")).As<v8::Object>();
 
4492
  v8::Handle<v8::Object> proto0 =
 
4493
      tostring0->Get(v8_str("__proto__")).As<v8::Object>();
 
4494
  proto0->Set(v8_str("custom"), v8_num(1234));
 
4495
 
 
4496
  LocalContext env1;
 
4497
  v8::Handle<v8::Object> global1 =
 
4498
      env1->Global();
 
4499
  v8::Handle<v8::Object> object1 =
 
4500
      global1->Get(v8_str("Object")).As<v8::Object>();
 
4501
  v8::Handle<v8::Object> tostring1 =
 
4502
      object1->Get(v8_str("toString")).As<v8::Object>();
 
4503
  v8::Handle<v8::Object> proto1 =
 
4504
      tostring1->Get(v8_str("__proto__")).As<v8::Object>();
 
4505
  CHECK(!proto1->Has(v8_str("custom")));
 
4506
}
 
4507
 
 
4508
 
 
4509
THREADED_TEST(Regress892105) {
 
4510
  // Make sure that object and array literals created by cloning
 
4511
  // boilerplates cannot communicate through their __proto__
 
4512
  // field. This is rather difficult to check, but we try to add stuff
 
4513
  // to Object.prototype and Array.prototype and create a new
 
4514
  // environment. This should succeed.
 
4515
 
 
4516
  v8::HandleScope scope;
 
4517
 
 
4518
  Local<String> source = v8_str("Object.prototype.obj = 1234;"
 
4519
                                "Array.prototype.arr = 4567;"
 
4520
                                "8901");
 
4521
 
 
4522
  LocalContext env0;
 
4523
  Local<Script> script0 = Script::Compile(source);
 
4524
  CHECK_EQ(8901.0, script0->Run()->NumberValue());
 
4525
 
 
4526
  LocalContext env1;
 
4527
  Local<Script> script1 = Script::Compile(source);
 
4528
  CHECK_EQ(8901.0, script1->Run()->NumberValue());
 
4529
}
 
4530
 
 
4531
 
 
4532
THREADED_TEST(UndetectableObject) {
 
4533
  v8::HandleScope scope;
 
4534
  LocalContext env;
 
4535
 
 
4536
  Local<v8::FunctionTemplate> desc =
 
4537
      v8::FunctionTemplate::New(0, v8::Handle<Value>());
 
4538
  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
4539
 
 
4540
  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
 
4541
  env->Global()->Set(v8_str("undetectable"), obj);
 
4542
 
 
4543
  ExpectString("undetectable.toString()", "[object Object]");
 
4544
  ExpectString("typeof undetectable", "undefined");
 
4545
  ExpectString("typeof(undetectable)", "undefined");
 
4546
  ExpectBoolean("typeof undetectable == 'undefined'", true);
 
4547
  ExpectBoolean("typeof undetectable == 'object'", false);
 
4548
  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
 
4549
  ExpectBoolean("!undetectable", true);
 
4550
 
 
4551
  ExpectObject("true&&undetectable", obj);
 
4552
  ExpectBoolean("false&&undetectable", false);
 
4553
  ExpectBoolean("true||undetectable", true);
 
4554
  ExpectObject("false||undetectable", obj);
 
4555
 
 
4556
  ExpectObject("undetectable&&true", obj);
 
4557
  ExpectObject("undetectable&&false", obj);
 
4558
  ExpectBoolean("undetectable||true", true);
 
4559
  ExpectBoolean("undetectable||false", false);
 
4560
 
 
4561
  ExpectBoolean("undetectable==null", true);
 
4562
  ExpectBoolean("null==undetectable", true);
 
4563
  ExpectBoolean("undetectable==undefined", true);
 
4564
  ExpectBoolean("undefined==undetectable", true);
 
4565
  ExpectBoolean("undetectable==undetectable", true);
 
4566
 
 
4567
 
 
4568
  ExpectBoolean("undetectable===null", false);
 
4569
  ExpectBoolean("null===undetectable", false);
 
4570
  ExpectBoolean("undetectable===undefined", false);
 
4571
  ExpectBoolean("undefined===undetectable", false);
 
4572
  ExpectBoolean("undetectable===undetectable", true);
 
4573
}
 
4574
 
 
4575
 
 
4576
THREADED_TEST(VoidLiteral) {
 
4577
  v8::HandleScope scope;
 
4578
  LocalContext env;
 
4579
 
 
4580
  Local<v8::FunctionTemplate> desc =
 
4581
      v8::FunctionTemplate::New(0, v8::Handle<Value>());
 
4582
  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
4583
 
 
4584
  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
 
4585
  env->Global()->Set(v8_str("undetectable"), obj);
 
4586
 
 
4587
  ExpectBoolean("undefined == void 0", true);
 
4588
  ExpectBoolean("undetectable == void 0", true);
 
4589
  ExpectBoolean("null == void 0", true);
 
4590
  ExpectBoolean("undefined === void 0", true);
 
4591
  ExpectBoolean("undetectable === void 0", false);
 
4592
  ExpectBoolean("null === void 0", false);
 
4593
 
 
4594
  ExpectBoolean("void 0 == undefined", true);
 
4595
  ExpectBoolean("void 0 == undetectable", true);
 
4596
  ExpectBoolean("void 0 == null", true);
 
4597
  ExpectBoolean("void 0 === undefined", true);
 
4598
  ExpectBoolean("void 0 === undetectable", false);
 
4599
  ExpectBoolean("void 0 === null", false);
 
4600
 
 
4601
  ExpectString("(function() {"
 
4602
               "  try {"
 
4603
               "    return x === void 0;"
 
4604
               "  } catch(e) {"
 
4605
               "    return e.toString();"
 
4606
               "  }"
 
4607
               "})()",
 
4608
               "ReferenceError: x is not defined");
 
4609
  ExpectString("(function() {"
 
4610
               "  try {"
 
4611
               "    return void 0 === x;"
 
4612
               "  } catch(e) {"
 
4613
               "    return e.toString();"
 
4614
               "  }"
 
4615
               "})()",
 
4616
               "ReferenceError: x is not defined");
 
4617
}
 
4618
 
 
4619
 
 
4620
THREADED_TEST(ExtensibleOnUndetectable) {
 
4621
  v8::HandleScope scope;
 
4622
  LocalContext env;
 
4623
 
 
4624
  Local<v8::FunctionTemplate> desc =
 
4625
      v8::FunctionTemplate::New(0, v8::Handle<Value>());
 
4626
  desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
4627
 
 
4628
  Local<v8::Object> obj = desc->GetFunction()->NewInstance();
 
4629
  env->Global()->Set(v8_str("undetectable"), obj);
 
4630
 
 
4631
  Local<String> source = v8_str("undetectable.x = 42;"
 
4632
                                "undetectable.x");
 
4633
 
 
4634
  Local<Script> script = Script::Compile(source);
 
4635
 
 
4636
  CHECK_EQ(v8::Integer::New(42), script->Run());
 
4637
 
 
4638
  ExpectBoolean("Object.isExtensible(undetectable)", true);
 
4639
 
 
4640
  source = v8_str("Object.preventExtensions(undetectable);");
 
4641
  script = Script::Compile(source);
 
4642
  script->Run();
 
4643
  ExpectBoolean("Object.isExtensible(undetectable)", false);
 
4644
 
 
4645
  source = v8_str("undetectable.y = 2000;");
 
4646
  script = Script::Compile(source);
 
4647
  script->Run();
 
4648
  ExpectBoolean("undetectable.y == undefined", true);
 
4649
}
 
4650
 
 
4651
 
 
4652
 
 
4653
THREADED_TEST(UndetectableString) {
 
4654
  v8::HandleScope scope;
 
4655
  LocalContext env;
 
4656
 
 
4657
  Local<String> obj = String::NewUndetectable("foo");
 
4658
  env->Global()->Set(v8_str("undetectable"), obj);
 
4659
 
 
4660
  ExpectString("undetectable", "foo");
 
4661
  ExpectString("typeof undetectable", "undefined");
 
4662
  ExpectString("typeof(undetectable)", "undefined");
 
4663
  ExpectBoolean("typeof undetectable == 'undefined'", true);
 
4664
  ExpectBoolean("typeof undetectable == 'string'", false);
 
4665
  ExpectBoolean("if (undetectable) { true; } else { false; }", false);
 
4666
  ExpectBoolean("!undetectable", true);
 
4667
 
 
4668
  ExpectObject("true&&undetectable", obj);
 
4669
  ExpectBoolean("false&&undetectable", false);
 
4670
  ExpectBoolean("true||undetectable", true);
 
4671
  ExpectObject("false||undetectable", obj);
 
4672
 
 
4673
  ExpectObject("undetectable&&true", obj);
 
4674
  ExpectObject("undetectable&&false", obj);
 
4675
  ExpectBoolean("undetectable||true", true);
 
4676
  ExpectBoolean("undetectable||false", false);
 
4677
 
 
4678
  ExpectBoolean("undetectable==null", true);
 
4679
  ExpectBoolean("null==undetectable", true);
 
4680
  ExpectBoolean("undetectable==undefined", true);
 
4681
  ExpectBoolean("undefined==undetectable", true);
 
4682
  ExpectBoolean("undetectable==undetectable", true);
 
4683
 
 
4684
 
 
4685
  ExpectBoolean("undetectable===null", false);
 
4686
  ExpectBoolean("null===undetectable", false);
 
4687
  ExpectBoolean("undetectable===undefined", false);
 
4688
  ExpectBoolean("undefined===undetectable", false);
 
4689
  ExpectBoolean("undetectable===undetectable", true);
 
4690
}
 
4691
 
 
4692
 
 
4693
TEST(UndetectableOptimized) {
 
4694
  i::FLAG_allow_natives_syntax = true;
 
4695
  v8::HandleScope scope;
 
4696
  LocalContext env;
 
4697
 
 
4698
  Local<String> obj = String::NewUndetectable("foo");
 
4699
  env->Global()->Set(v8_str("undetectable"), obj);
 
4700
  env->Global()->Set(v8_str("detectable"), v8_str("bar"));
 
4701
 
 
4702
  ExpectString(
 
4703
      "function testBranch() {"
 
4704
      "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
 
4705
      "  if (%_IsUndetectableObject(detectable)) throw 2;"
 
4706
      "}\n"
 
4707
      "function testBool() {"
 
4708
      "  var b1 = !%_IsUndetectableObject(undetectable);"
 
4709
      "  var b2 = %_IsUndetectableObject(detectable);"
 
4710
      "  if (b1) throw 3;"
 
4711
      "  if (b2) throw 4;"
 
4712
      "  return b1 == b2;"
 
4713
      "}\n"
 
4714
      "%OptimizeFunctionOnNextCall(testBranch);"
 
4715
      "%OptimizeFunctionOnNextCall(testBool);"
 
4716
      "for (var i = 0; i < 10; i++) {"
 
4717
      "  testBranch();"
 
4718
      "  testBool();"
 
4719
      "}\n"
 
4720
      "\"PASS\"",
 
4721
      "PASS");
 
4722
}
 
4723
 
 
4724
 
 
4725
template <typename T> static void USE(T) { }
 
4726
 
 
4727
 
 
4728
// This test is not intended to be run, just type checked.
 
4729
static inline void PersistentHandles() {
 
4730
  USE(PersistentHandles);
 
4731
  Local<String> str = v8_str("foo");
 
4732
  v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
 
4733
  USE(p_str);
 
4734
  Local<Script> scr = Script::Compile(v8_str(""));
 
4735
  v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
 
4736
  USE(p_scr);
 
4737
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
4738
  v8::Persistent<ObjectTemplate> p_templ =
 
4739
    v8::Persistent<ObjectTemplate>::New(templ);
 
4740
  USE(p_templ);
 
4741
}
 
4742
 
 
4743
 
 
4744
static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
 
4745
  ApiTestFuzzer::Fuzz();
 
4746
  return v8::Undefined();
 
4747
}
 
4748
 
 
4749
 
 
4750
THREADED_TEST(GlobalObjectTemplate) {
 
4751
  v8::HandleScope handle_scope;
 
4752
  Local<ObjectTemplate> global_template = ObjectTemplate::New();
 
4753
  global_template->Set(v8_str("JSNI_Log"),
 
4754
                       v8::FunctionTemplate::New(HandleLogDelegator));
 
4755
  v8::Persistent<Context> context = Context::New(0, global_template);
 
4756
  Context::Scope context_scope(context);
 
4757
  Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
 
4758
  context.Dispose();
 
4759
}
 
4760
 
 
4761
 
 
4762
static const char* kSimpleExtensionSource =
 
4763
  "function Foo() {"
 
4764
  "  return 4;"
 
4765
  "}";
 
4766
 
 
4767
 
 
4768
THREADED_TEST(SimpleExtensions) {
 
4769
  v8::HandleScope handle_scope;
 
4770
  v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
 
4771
  const char* extension_names[] = { "simpletest" };
 
4772
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4773
  v8::Handle<Context> context = Context::New(&extensions);
 
4774
  Context::Scope lock(context);
 
4775
  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
 
4776
  CHECK_EQ(result, v8::Integer::New(4));
 
4777
}
 
4778
 
 
4779
 
 
4780
THREADED_TEST(NullExtensions) {
 
4781
  v8::HandleScope handle_scope;
 
4782
  v8::RegisterExtension(new Extension("nulltest", NULL));
 
4783
  const char* extension_names[] = { "nulltest" };
 
4784
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4785
  v8::Handle<Context> context = Context::New(&extensions);
 
4786
  Context::Scope lock(context);
 
4787
  v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
 
4788
  CHECK_EQ(result, v8::Integer::New(4));
 
4789
}
 
4790
 
 
4791
 
 
4792
static const char* kEmbeddedExtensionSource =
 
4793
    "function Ret54321(){return 54321;}~~@@$"
 
4794
    "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
 
4795
static const int kEmbeddedExtensionSourceValidLen = 34;
 
4796
 
 
4797
 
 
4798
THREADED_TEST(ExtensionMissingSourceLength) {
 
4799
  v8::HandleScope handle_scope;
 
4800
  v8::RegisterExtension(new Extension("srclentest_fail",
 
4801
                                      kEmbeddedExtensionSource));
 
4802
  const char* extension_names[] = { "srclentest_fail" };
 
4803
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4804
  v8::Handle<Context> context = Context::New(&extensions);
 
4805
  CHECK_EQ(0, *context);
 
4806
}
 
4807
 
 
4808
 
 
4809
THREADED_TEST(ExtensionWithSourceLength) {
 
4810
  for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
 
4811
       source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
 
4812
    v8::HandleScope handle_scope;
 
4813
    i::ScopedVector<char> extension_name(32);
 
4814
    i::OS::SNPrintF(extension_name, "ext #%d", source_len);
 
4815
    v8::RegisterExtension(new Extension(extension_name.start(),
 
4816
                                        kEmbeddedExtensionSource, 0, 0,
 
4817
                                        source_len));
 
4818
    const char* extension_names[1] = { extension_name.start() };
 
4819
    v8::ExtensionConfiguration extensions(1, extension_names);
 
4820
    v8::Handle<Context> context = Context::New(&extensions);
 
4821
    if (source_len == kEmbeddedExtensionSourceValidLen) {
 
4822
      Context::Scope lock(context);
 
4823
      v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
 
4824
      CHECK_EQ(v8::Integer::New(54321), result);
 
4825
    } else {
 
4826
      // Anything but exactly the right length should fail to compile.
 
4827
      CHECK_EQ(0, *context);
 
4828
    }
 
4829
  }
 
4830
}
 
4831
 
 
4832
 
 
4833
static const char* kEvalExtensionSource1 =
 
4834
  "function UseEval1() {"
 
4835
  "  var x = 42;"
 
4836
  "  return eval('x');"
 
4837
  "}";
 
4838
 
 
4839
 
 
4840
static const char* kEvalExtensionSource2 =
 
4841
  "(function() {"
 
4842
  "  var x = 42;"
 
4843
  "  function e() {"
 
4844
  "    return eval('x');"
 
4845
  "  }"
 
4846
  "  this.UseEval2 = e;"
 
4847
  "})()";
 
4848
 
 
4849
 
 
4850
THREADED_TEST(UseEvalFromExtension) {
 
4851
  v8::HandleScope handle_scope;
 
4852
  v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
 
4853
  v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
 
4854
  const char* extension_names[] = { "evaltest1", "evaltest2" };
 
4855
  v8::ExtensionConfiguration extensions(2, extension_names);
 
4856
  v8::Handle<Context> context = Context::New(&extensions);
 
4857
  Context::Scope lock(context);
 
4858
  v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
 
4859
  CHECK_EQ(result, v8::Integer::New(42));
 
4860
  result = Script::Compile(v8_str("UseEval2()"))->Run();
 
4861
  CHECK_EQ(result, v8::Integer::New(42));
 
4862
}
 
4863
 
 
4864
 
 
4865
static const char* kWithExtensionSource1 =
 
4866
  "function UseWith1() {"
 
4867
  "  var x = 42;"
 
4868
  "  with({x:87}) { return x; }"
 
4869
  "}";
 
4870
 
 
4871
 
 
4872
 
 
4873
static const char* kWithExtensionSource2 =
 
4874
  "(function() {"
 
4875
  "  var x = 42;"
 
4876
  "  function e() {"
 
4877
  "    with ({x:87}) { return x; }"
 
4878
  "  }"
 
4879
  "  this.UseWith2 = e;"
 
4880
  "})()";
 
4881
 
 
4882
 
 
4883
THREADED_TEST(UseWithFromExtension) {
 
4884
  v8::HandleScope handle_scope;
 
4885
  v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
 
4886
  v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
 
4887
  const char* extension_names[] = { "withtest1", "withtest2" };
 
4888
  v8::ExtensionConfiguration extensions(2, extension_names);
 
4889
  v8::Handle<Context> context = Context::New(&extensions);
 
4890
  Context::Scope lock(context);
 
4891
  v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
 
4892
  CHECK_EQ(result, v8::Integer::New(87));
 
4893
  result = Script::Compile(v8_str("UseWith2()"))->Run();
 
4894
  CHECK_EQ(result, v8::Integer::New(87));
 
4895
}
 
4896
 
 
4897
 
 
4898
THREADED_TEST(AutoExtensions) {
 
4899
  v8::HandleScope handle_scope;
 
4900
  Extension* extension = new Extension("autotest", kSimpleExtensionSource);
 
4901
  extension->set_auto_enable(true);
 
4902
  v8::RegisterExtension(extension);
 
4903
  v8::Handle<Context> context = Context::New();
 
4904
  Context::Scope lock(context);
 
4905
  v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
 
4906
  CHECK_EQ(result, v8::Integer::New(4));
 
4907
}
 
4908
 
 
4909
 
 
4910
static const char* kSyntaxErrorInExtensionSource =
 
4911
    "[";
 
4912
 
 
4913
 
 
4914
// Test that a syntax error in an extension does not cause a fatal
 
4915
// error but results in an empty context.
 
4916
THREADED_TEST(SyntaxErrorExtensions) {
 
4917
  v8::HandleScope handle_scope;
 
4918
  v8::RegisterExtension(new Extension("syntaxerror",
 
4919
                                      kSyntaxErrorInExtensionSource));
 
4920
  const char* extension_names[] = { "syntaxerror" };
 
4921
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4922
  v8::Handle<Context> context = Context::New(&extensions);
 
4923
  CHECK(context.IsEmpty());
 
4924
}
 
4925
 
 
4926
 
 
4927
static const char* kExceptionInExtensionSource =
 
4928
    "throw 42";
 
4929
 
 
4930
 
 
4931
// Test that an exception when installing an extension does not cause
 
4932
// a fatal error but results in an empty context.
 
4933
THREADED_TEST(ExceptionExtensions) {
 
4934
  v8::HandleScope handle_scope;
 
4935
  v8::RegisterExtension(new Extension("exception",
 
4936
                                      kExceptionInExtensionSource));
 
4937
  const char* extension_names[] = { "exception" };
 
4938
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4939
  v8::Handle<Context> context = Context::New(&extensions);
 
4940
  CHECK(context.IsEmpty());
 
4941
}
 
4942
 
 
4943
 
 
4944
static const char* kNativeCallInExtensionSource =
 
4945
    "function call_runtime_last_index_of(x) {"
 
4946
    "  return %StringLastIndexOf(x, 'bob', 10);"
 
4947
    "}";
 
4948
 
 
4949
 
 
4950
static const char* kNativeCallTest =
 
4951
    "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
 
4952
 
 
4953
// Test that a native runtime calls are supported in extensions.
 
4954
THREADED_TEST(NativeCallInExtensions) {
 
4955
  v8::HandleScope handle_scope;
 
4956
  v8::RegisterExtension(new Extension("nativecall",
 
4957
                                      kNativeCallInExtensionSource));
 
4958
  const char* extension_names[] = { "nativecall" };
 
4959
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4960
  v8::Handle<Context> context = Context::New(&extensions);
 
4961
  Context::Scope lock(context);
 
4962
  v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
 
4963
  CHECK_EQ(result, v8::Integer::New(3));
 
4964
}
 
4965
 
 
4966
 
 
4967
class NativeFunctionExtension : public Extension {
 
4968
 public:
 
4969
  NativeFunctionExtension(const char* name,
 
4970
                          const char* source,
 
4971
                          v8::InvocationCallback fun = &Echo)
 
4972
      : Extension(name, source),
 
4973
        function_(fun) { }
 
4974
 
 
4975
  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
 
4976
      v8::Handle<v8::String> name) {
 
4977
    return v8::FunctionTemplate::New(function_);
 
4978
  }
 
4979
 
 
4980
  static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
 
4981
    if (args.Length() >= 1) return (args[0]);
 
4982
    return v8::Undefined();
 
4983
  }
 
4984
 private:
 
4985
  v8::InvocationCallback function_;
 
4986
};
 
4987
 
 
4988
 
 
4989
THREADED_TEST(NativeFunctionDeclaration) {
 
4990
  v8::HandleScope handle_scope;
 
4991
  const char* name = "nativedecl";
 
4992
  v8::RegisterExtension(new NativeFunctionExtension(name,
 
4993
                                                    "native function foo();"));
 
4994
  const char* extension_names[] = { name };
 
4995
  v8::ExtensionConfiguration extensions(1, extension_names);
 
4996
  v8::Handle<Context> context = Context::New(&extensions);
 
4997
  Context::Scope lock(context);
 
4998
  v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
 
4999
  CHECK_EQ(result, v8::Integer::New(42));
 
5000
}
 
5001
 
 
5002
 
 
5003
THREADED_TEST(NativeFunctionDeclarationError) {
 
5004
  v8::HandleScope handle_scope;
 
5005
  const char* name = "nativedeclerr";
 
5006
  // Syntax error in extension code.
 
5007
  v8::RegisterExtension(new NativeFunctionExtension(name,
 
5008
                                                    "native\nfunction foo();"));
 
5009
  const char* extension_names[] = { name };
 
5010
  v8::ExtensionConfiguration extensions(1, extension_names);
 
5011
  v8::Handle<Context> context(Context::New(&extensions));
 
5012
  CHECK(context.IsEmpty());
 
5013
}
 
5014
 
 
5015
 
 
5016
THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
 
5017
  v8::HandleScope handle_scope;
 
5018
  const char* name = "nativedeclerresc";
 
5019
  // Syntax error in extension code - escape code in "native" means that
 
5020
  // it's not treated as a keyword.
 
5021
  v8::RegisterExtension(new NativeFunctionExtension(
 
5022
      name,
 
5023
      "nativ\\u0065 function foo();"));
 
5024
  const char* extension_names[] = { name };
 
5025
  v8::ExtensionConfiguration extensions(1, extension_names);
 
5026
  v8::Handle<Context> context(Context::New(&extensions));
 
5027
  CHECK(context.IsEmpty());
 
5028
}
 
5029
 
 
5030
 
 
5031
static void CheckDependencies(const char* name, const char* expected) {
 
5032
  v8::HandleScope handle_scope;
 
5033
  v8::ExtensionConfiguration config(1, &name);
 
5034
  LocalContext context(&config);
 
5035
  CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
 
5036
}
 
5037
 
 
5038
 
 
5039
/*
 
5040
 * Configuration:
 
5041
 *
 
5042
 *     /-- B <--\
 
5043
 * A <-          -- D <-- E
 
5044
 *     \-- C <--/
 
5045
 */
 
5046
THREADED_TEST(ExtensionDependency) {
 
5047
  static const char* kEDeps[] = { "D" };
 
5048
  v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
 
5049
  static const char* kDDeps[] = { "B", "C" };
 
5050
  v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
 
5051
  static const char* kBCDeps[] = { "A" };
 
5052
  v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
 
5053
  v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
 
5054
  v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
 
5055
  CheckDependencies("A", "undefinedA");
 
5056
  CheckDependencies("B", "undefinedAB");
 
5057
  CheckDependencies("C", "undefinedAC");
 
5058
  CheckDependencies("D", "undefinedABCD");
 
5059
  CheckDependencies("E", "undefinedABCDE");
 
5060
  v8::HandleScope handle_scope;
 
5061
  static const char* exts[2] = { "C", "E" };
 
5062
  v8::ExtensionConfiguration config(2, exts);
 
5063
  LocalContext context(&config);
 
5064
  CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
 
5065
}
 
5066
 
 
5067
 
 
5068
static const char* kExtensionTestScript =
 
5069
  "native function A();"
 
5070
  "native function B();"
 
5071
  "native function C();"
 
5072
  "function Foo(i) {"
 
5073
  "  if (i == 0) return A();"
 
5074
  "  if (i == 1) return B();"
 
5075
  "  if (i == 2) return C();"
 
5076
  "}";
 
5077
 
 
5078
 
 
5079
static v8::Handle<Value> CallFun(const v8::Arguments& args) {
 
5080
  ApiTestFuzzer::Fuzz();
 
5081
  if (args.IsConstructCall()) {
 
5082
    args.This()->Set(v8_str("data"), args.Data());
 
5083
    return v8::Null();
 
5084
  }
 
5085
  return args.Data();
 
5086
}
 
5087
 
 
5088
 
 
5089
class FunctionExtension : public Extension {
 
5090
 public:
 
5091
  FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
 
5092
  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
 
5093
      v8::Handle<String> name);
 
5094
};
 
5095
 
 
5096
 
 
5097
static int lookup_count = 0;
 
5098
v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
 
5099
      v8::Handle<String> name) {
 
5100
  lookup_count++;
 
5101
  if (name->Equals(v8_str("A"))) {
 
5102
    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
 
5103
  } else if (name->Equals(v8_str("B"))) {
 
5104
    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
 
5105
  } else if (name->Equals(v8_str("C"))) {
 
5106
    return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
 
5107
  } else {
 
5108
    return v8::Handle<v8::FunctionTemplate>();
 
5109
  }
 
5110
}
 
5111
 
 
5112
 
 
5113
THREADED_TEST(FunctionLookup) {
 
5114
  v8::RegisterExtension(new FunctionExtension());
 
5115
  v8::HandleScope handle_scope;
 
5116
  static const char* exts[1] = { "functiontest" };
 
5117
  v8::ExtensionConfiguration config(1, exts);
 
5118
  LocalContext context(&config);
 
5119
  CHECK_EQ(3, lookup_count);
 
5120
  CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
 
5121
  CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
 
5122
  CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
 
5123
}
 
5124
 
 
5125
 
 
5126
THREADED_TEST(NativeFunctionConstructCall) {
 
5127
  v8::RegisterExtension(new FunctionExtension());
 
5128
  v8::HandleScope handle_scope;
 
5129
  static const char* exts[1] = { "functiontest" };
 
5130
  v8::ExtensionConfiguration config(1, exts);
 
5131
  LocalContext context(&config);
 
5132
  for (int i = 0; i < 10; i++) {
 
5133
    // Run a few times to ensure that allocation of objects doesn't
 
5134
    // change behavior of a constructor function.
 
5135
    CHECK_EQ(v8::Integer::New(8),
 
5136
             Script::Compile(v8_str("(new A()).data"))->Run());
 
5137
    CHECK_EQ(v8::Integer::New(7),
 
5138
             Script::Compile(v8_str("(new B()).data"))->Run());
 
5139
    CHECK_EQ(v8::Integer::New(6),
 
5140
             Script::Compile(v8_str("(new C()).data"))->Run());
 
5141
  }
 
5142
}
 
5143
 
 
5144
 
 
5145
static const char* last_location;
 
5146
static const char* last_message;
 
5147
void StoringErrorCallback(const char* location, const char* message) {
 
5148
  if (last_location == NULL) {
 
5149
    last_location = location;
 
5150
    last_message = message;
 
5151
  }
 
5152
}
 
5153
 
 
5154
 
 
5155
// ErrorReporting creates a circular extensions configuration and
 
5156
// tests that the fatal error handler gets called.  This renders V8
 
5157
// unusable and therefore this test cannot be run in parallel.
 
5158
TEST(ErrorReporting) {
 
5159
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
5160
  static const char* aDeps[] = { "B" };
 
5161
  v8::RegisterExtension(new Extension("A", "", 1, aDeps));
 
5162
  static const char* bDeps[] = { "A" };
 
5163
  v8::RegisterExtension(new Extension("B", "", 1, bDeps));
 
5164
  last_location = NULL;
 
5165
  v8::ExtensionConfiguration config(1, bDeps);
 
5166
  v8::Handle<Context> context = Context::New(&config);
 
5167
  CHECK(context.IsEmpty());
 
5168
  CHECK_NE(last_location, NULL);
 
5169
}
 
5170
 
 
5171
 
 
5172
static const char* js_code_causing_huge_string_flattening =
 
5173
    "var str = 'X';"
 
5174
    "for (var i = 0; i < 30; i++) {"
 
5175
    "  str = str + str;"
 
5176
    "}"
 
5177
    "str.match(/X/);";
 
5178
 
 
5179
 
 
5180
void OOMCallback(const char* location, const char* message) {
 
5181
  exit(0);
 
5182
}
 
5183
 
 
5184
 
 
5185
TEST(RegexpOutOfMemory) {
 
5186
  // Execute a script that causes out of memory when flattening a string.
 
5187
  v8::HandleScope scope;
 
5188
  v8::V8::SetFatalErrorHandler(OOMCallback);
 
5189
  LocalContext context;
 
5190
  Local<Script> script =
 
5191
      Script::Compile(String::New(js_code_causing_huge_string_flattening));
 
5192
  last_location = NULL;
 
5193
  script->Run();
 
5194
 
 
5195
  CHECK(false);  // Should not return.
 
5196
}
 
5197
 
 
5198
 
 
5199
static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
 
5200
                                             v8::Handle<Value> data) {
 
5201
  CHECK(message->GetScriptResourceName()->IsUndefined());
 
5202
  CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
 
5203
  message->GetLineNumber();
 
5204
  message->GetSourceLine();
 
5205
}
 
5206
 
 
5207
 
 
5208
THREADED_TEST(ErrorWithMissingScriptInfo) {
 
5209
  v8::HandleScope scope;
 
5210
  LocalContext context;
 
5211
  v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
 
5212
  Script::Compile(v8_str("throw Error()"))->Run();
 
5213
  v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
 
5214
}
 
5215
 
 
5216
 
 
5217
int global_index = 0;
 
5218
 
 
5219
class Snorkel {
 
5220
 public:
 
5221
  Snorkel() { index_ = global_index++; }
 
5222
  int index_;
 
5223
};
 
5224
 
 
5225
class Whammy {
 
5226
 public:
 
5227
  Whammy() {
 
5228
    cursor_ = 0;
 
5229
  }
 
5230
  ~Whammy() {
 
5231
    script_.Dispose();
 
5232
  }
 
5233
  v8::Handle<Script> getScript() {
 
5234
    if (script_.IsEmpty())
 
5235
      script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
 
5236
    return Local<Script>(*script_);
 
5237
  }
 
5238
 
 
5239
 public:
 
5240
  static const int kObjectCount = 256;
 
5241
  int cursor_;
 
5242
  v8::Persistent<v8::Object> objects_[kObjectCount];
 
5243
  v8::Persistent<Script> script_;
 
5244
};
 
5245
 
 
5246
static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
 
5247
  Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
 
5248
  delete snorkel;
 
5249
  obj.ClearWeak();
 
5250
}
 
5251
 
 
5252
v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
 
5253
                                       const AccessorInfo& info) {
 
5254
  Whammy* whammy =
 
5255
    static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
 
5256
 
 
5257
  v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
 
5258
 
 
5259
  v8::Handle<v8::Object> obj = v8::Object::New();
 
5260
  v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
 
5261
  if (!prev.IsEmpty()) {
 
5262
    prev->Set(v8_str("next"), obj);
 
5263
    prev.MakeWeak(new Snorkel(), &HandleWeakReference);
 
5264
    whammy->objects_[whammy->cursor_].Clear();
 
5265
  }
 
5266
  whammy->objects_[whammy->cursor_] = global;
 
5267
  whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
 
5268
  return whammy->getScript()->Run();
 
5269
}
 
5270
 
 
5271
THREADED_TEST(WeakReference) {
 
5272
  v8::HandleScope handle_scope;
 
5273
  v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
 
5274
  Whammy* whammy = new Whammy();
 
5275
  templ->SetNamedPropertyHandler(WhammyPropertyGetter,
 
5276
                                 0, 0, 0, 0,
 
5277
                                 v8::External::New(whammy));
 
5278
  const char* extension_list[] = { "v8/gc" };
 
5279
  v8::ExtensionConfiguration extensions(1, extension_list);
 
5280
  v8::Persistent<Context> context = Context::New(&extensions);
 
5281
  Context::Scope context_scope(context);
 
5282
 
 
5283
  v8::Handle<v8::Object> interceptor = templ->NewInstance();
 
5284
  context->Global()->Set(v8_str("whammy"), interceptor);
 
5285
  const char* code =
 
5286
      "var last;"
 
5287
      "for (var i = 0; i < 10000; i++) {"
 
5288
      "  var obj = whammy.length;"
 
5289
      "  if (last) last.next = obj;"
 
5290
      "  last = obj;"
 
5291
      "}"
 
5292
      "gc();"
 
5293
      "4";
 
5294
  v8::Handle<Value> result = CompileRun(code);
 
5295
  CHECK_EQ(4.0, result->NumberValue());
 
5296
  delete whammy;
 
5297
  context.Dispose();
 
5298
}
 
5299
 
 
5300
 
 
5301
static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
 
5302
  obj.Dispose();
 
5303
  obj.Clear();
 
5304
  *(reinterpret_cast<bool*>(data)) = true;
 
5305
}
 
5306
 
 
5307
 
 
5308
THREADED_TEST(IndependentWeakHandle) {
 
5309
  v8::Persistent<Context> context = Context::New();
 
5310
  Context::Scope context_scope(context);
 
5311
 
 
5312
  v8::Persistent<v8::Object> object_a;
 
5313
 
 
5314
  {
 
5315
    v8::HandleScope handle_scope;
 
5316
    object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
 
5317
  }
 
5318
 
 
5319
  bool object_a_disposed = false;
 
5320
  object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
 
5321
  CHECK(!object_a.IsIndependent());
 
5322
  object_a.MarkIndependent();
 
5323
  CHECK(object_a.IsIndependent());
 
5324
  HEAP->PerformScavenge();
 
5325
  CHECK(object_a_disposed);
 
5326
}
 
5327
 
 
5328
 
 
5329
static void InvokeScavenge() {
 
5330
  HEAP->PerformScavenge();
 
5331
}
 
5332
 
 
5333
 
 
5334
static void InvokeMarkSweep() {
 
5335
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
5336
}
 
5337
 
 
5338
 
 
5339
static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
 
5340
  obj.Dispose();
 
5341
  obj.Clear();
 
5342
  *(reinterpret_cast<bool*>(data)) = true;
 
5343
  InvokeScavenge();
 
5344
}
 
5345
 
 
5346
 
 
5347
static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
 
5348
  obj.Dispose();
 
5349
  obj.Clear();
 
5350
  *(reinterpret_cast<bool*>(data)) = true;
 
5351
  InvokeMarkSweep();
 
5352
}
 
5353
 
 
5354
 
 
5355
THREADED_TEST(GCFromWeakCallbacks) {
 
5356
  v8::Persistent<Context> context = Context::New();
 
5357
  Context::Scope context_scope(context);
 
5358
 
 
5359
  static const int kNumberOfGCTypes = 2;
 
5360
  v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
 
5361
      {&ForceScavenge, &ForceMarkSweep};
 
5362
 
 
5363
  typedef void (*GCInvoker)();
 
5364
  GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
 
5365
 
 
5366
  for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
 
5367
    for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
 
5368
      v8::Persistent<v8::Object> object;
 
5369
      {
 
5370
        v8::HandleScope handle_scope;
 
5371
        object = v8::Persistent<v8::Object>::New(v8::Object::New());
 
5372
      }
 
5373
      bool disposed = false;
 
5374
      object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
 
5375
      object.MarkIndependent();
 
5376
      invoke_gc[outer_gc]();
 
5377
      CHECK(disposed);
 
5378
    }
 
5379
  }
 
5380
}
 
5381
 
 
5382
 
 
5383
static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
 
5384
  obj.ClearWeak();
 
5385
  *(reinterpret_cast<bool*>(data)) = true;
 
5386
}
 
5387
 
 
5388
 
 
5389
THREADED_TEST(IndependentHandleRevival) {
 
5390
  v8::Persistent<Context> context = Context::New();
 
5391
  Context::Scope context_scope(context);
 
5392
 
 
5393
  v8::Persistent<v8::Object> object;
 
5394
  {
 
5395
    v8::HandleScope handle_scope;
 
5396
    object = v8::Persistent<v8::Object>::New(v8::Object::New());
 
5397
    object->Set(v8_str("x"), v8::Integer::New(1));
 
5398
    v8::Local<String> y_str = v8_str("y");
 
5399
    object->Set(y_str, y_str);
 
5400
  }
 
5401
  bool revived = false;
 
5402
  object.MakeWeak(&revived, &RevivingCallback);
 
5403
  object.MarkIndependent();
 
5404
  HEAP->PerformScavenge();
 
5405
  CHECK(revived);
 
5406
  HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
5407
  {
 
5408
    v8::HandleScope handle_scope;
 
5409
    v8::Local<String> y_str = v8_str("y");
 
5410
    CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
 
5411
    CHECK(object->Get(y_str)->Equals(y_str));
 
5412
  }
 
5413
}
 
5414
 
 
5415
 
 
5416
v8::Handle<Function> args_fun;
 
5417
 
 
5418
 
 
5419
static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
 
5420
  ApiTestFuzzer::Fuzz();
 
5421
  CHECK_EQ(args_fun, args.Callee());
 
5422
  CHECK_EQ(3, args.Length());
 
5423
  CHECK_EQ(v8::Integer::New(1), args[0]);
 
5424
  CHECK_EQ(v8::Integer::New(2), args[1]);
 
5425
  CHECK_EQ(v8::Integer::New(3), args[2]);
 
5426
  CHECK_EQ(v8::Undefined(), args[3]);
 
5427
  v8::HandleScope scope;
 
5428
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
5429
  return v8::Undefined();
 
5430
}
 
5431
 
 
5432
 
 
5433
THREADED_TEST(Arguments) {
 
5434
  v8::HandleScope scope;
 
5435
  v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
 
5436
  global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
 
5437
  LocalContext context(NULL, global);
 
5438
  args_fun = context->Global()->Get(v8_str("f")).As<Function>();
 
5439
  v8_compile("f(1, 2, 3)")->Run();
 
5440
}
 
5441
 
 
5442
 
 
5443
static v8::Handle<Value> NoBlockGetterX(Local<String> name,
 
5444
                                        const AccessorInfo&) {
 
5445
  return v8::Handle<Value>();
 
5446
}
 
5447
 
 
5448
 
 
5449
static v8::Handle<Value> NoBlockGetterI(uint32_t index,
 
5450
                                        const AccessorInfo&) {
 
5451
  return v8::Handle<Value>();
 
5452
}
 
5453
 
 
5454
 
 
5455
static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
 
5456
                                        const AccessorInfo&) {
 
5457
  if (!name->Equals(v8_str("foo"))) {
 
5458
    return v8::Handle<v8::Boolean>();  // not intercepted
 
5459
  }
 
5460
 
 
5461
  return v8::False();  // intercepted, and don't delete the property
 
5462
}
 
5463
 
 
5464
 
 
5465
static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
 
5466
  if (index != 2) {
 
5467
    return v8::Handle<v8::Boolean>();  // not intercepted
 
5468
  }
 
5469
 
 
5470
  return v8::False();  // intercepted, and don't delete the property
 
5471
}
 
5472
 
 
5473
 
 
5474
THREADED_TEST(Deleter) {
 
5475
  v8::HandleScope scope;
 
5476
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
5477
  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
 
5478
  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
 
5479
  LocalContext context;
 
5480
  context->Global()->Set(v8_str("k"), obj->NewInstance());
 
5481
  CompileRun(
 
5482
    "k.foo = 'foo';"
 
5483
    "k.bar = 'bar';"
 
5484
    "k[2] = 2;"
 
5485
    "k[4] = 4;");
 
5486
  CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
 
5487
  CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
 
5488
 
 
5489
  CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
 
5490
  CHECK(v8_compile("k.bar")->Run()->IsUndefined());
 
5491
 
 
5492
  CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
 
5493
  CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
 
5494
 
 
5495
  CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
 
5496
  CHECK(v8_compile("k[4]")->Run()->IsUndefined());
 
5497
}
 
5498
 
 
5499
 
 
5500
static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
 
5501
  ApiTestFuzzer::Fuzz();
 
5502
  if (name->Equals(v8_str("foo")) ||
 
5503
      name->Equals(v8_str("bar")) ||
 
5504
      name->Equals(v8_str("baz"))) {
 
5505
    return v8::Undefined();
 
5506
  }
 
5507
  return v8::Handle<Value>();
 
5508
}
 
5509
 
 
5510
 
 
5511
static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
 
5512
  ApiTestFuzzer::Fuzz();
 
5513
  if (index == 0 || index == 1) return v8::Undefined();
 
5514
  return v8::Handle<Value>();
 
5515
}
 
5516
 
 
5517
 
 
5518
static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
 
5519
  ApiTestFuzzer::Fuzz();
 
5520
  v8::Handle<v8::Array> result = v8::Array::New(3);
 
5521
  result->Set(v8::Integer::New(0), v8_str("foo"));
 
5522
  result->Set(v8::Integer::New(1), v8_str("bar"));
 
5523
  result->Set(v8::Integer::New(2), v8_str("baz"));
 
5524
  return result;
 
5525
}
 
5526
 
 
5527
 
 
5528
static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
 
5529
  ApiTestFuzzer::Fuzz();
 
5530
  v8::Handle<v8::Array> result = v8::Array::New(2);
 
5531
  result->Set(v8::Integer::New(0), v8_str("0"));
 
5532
  result->Set(v8::Integer::New(1), v8_str("1"));
 
5533
  return result;
 
5534
}
 
5535
 
 
5536
 
 
5537
THREADED_TEST(Enumerators) {
 
5538
  v8::HandleScope scope;
 
5539
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
5540
  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
 
5541
  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
 
5542
  LocalContext context;
 
5543
  context->Global()->Set(v8_str("k"), obj->NewInstance());
 
5544
  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
 
5545
    "k[10] = 0;"
 
5546
    "k.a = 0;"
 
5547
    "k[5] = 0;"
 
5548
    "k.b = 0;"
 
5549
    "k[4294967295] = 0;"
 
5550
    "k.c = 0;"
 
5551
    "k[4294967296] = 0;"
 
5552
    "k.d = 0;"
 
5553
    "k[140000] = 0;"
 
5554
    "k.e = 0;"
 
5555
    "k[30000000000] = 0;"
 
5556
    "k.f = 0;"
 
5557
    "var result = [];"
 
5558
    "for (var prop in k) {"
 
5559
    "  result.push(prop);"
 
5560
    "}"
 
5561
    "result"));
 
5562
  // Check that we get all the property names returned including the
 
5563
  // ones from the enumerators in the right order: indexed properties
 
5564
  // in numerical order, indexed interceptor properties, named
 
5565
  // properties in insertion order, named interceptor properties.
 
5566
  // This order is not mandated by the spec, so this test is just
 
5567
  // documenting our behavior.
 
5568
  CHECK_EQ(17, result->Length());
 
5569
  // Indexed properties in numerical order.
 
5570
  CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
 
5571
  CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
 
5572
  CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
 
5573
  CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
 
5574
  // Indexed interceptor properties in the order they are returned
 
5575
  // from the enumerator interceptor.
 
5576
  CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
 
5577
  CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
 
5578
  // Named properties in insertion order.
 
5579
  CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
 
5580
  CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
 
5581
  CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
 
5582
  CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
 
5583
  CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
 
5584
  CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
 
5585
  CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
 
5586
  CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
 
5587
  // Named interceptor properties.
 
5588
  CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
 
5589
  CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
 
5590
  CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
 
5591
}
 
5592
 
 
5593
 
 
5594
int p_getter_count;
 
5595
int p_getter_count2;
 
5596
 
 
5597
 
 
5598
static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
 
5599
  ApiTestFuzzer::Fuzz();
 
5600
  p_getter_count++;
 
5601
  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
 
5602
  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
 
5603
  if (name->Equals(v8_str("p1"))) {
 
5604
    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
 
5605
  } else if (name->Equals(v8_str("p2"))) {
 
5606
    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
 
5607
  } else if (name->Equals(v8_str("p3"))) {
 
5608
    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
 
5609
  } else if (name->Equals(v8_str("p4"))) {
 
5610
    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
 
5611
  }
 
5612
  return v8::Undefined();
 
5613
}
 
5614
 
 
5615
 
 
5616
static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
 
5617
  ApiTestFuzzer::Fuzz();
 
5618
  LocalContext context;
 
5619
  context->Global()->Set(v8_str("o1"), obj->NewInstance());
 
5620
  CompileRun(
 
5621
    "o1.__proto__ = { };"
 
5622
    "var o2 = { __proto__: o1 };"
 
5623
    "var o3 = { __proto__: o2 };"
 
5624
    "var o4 = { __proto__: o3 };"
 
5625
    "for (var i = 0; i < 10; i++) o4.p4;"
 
5626
    "for (var i = 0; i < 10; i++) o3.p3;"
 
5627
    "for (var i = 0; i < 10; i++) o2.p2;"
 
5628
    "for (var i = 0; i < 10; i++) o1.p1;");
 
5629
}
 
5630
 
 
5631
 
 
5632
static v8::Handle<Value> PGetter2(Local<String> name,
 
5633
                                  const AccessorInfo& info) {
 
5634
  ApiTestFuzzer::Fuzz();
 
5635
  p_getter_count2++;
 
5636
  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
 
5637
  CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
 
5638
  if (name->Equals(v8_str("p1"))) {
 
5639
    CHECK_EQ(info.This(), global->Get(v8_str("o1")));
 
5640
  } else if (name->Equals(v8_str("p2"))) {
 
5641
    CHECK_EQ(info.This(), global->Get(v8_str("o2")));
 
5642
  } else if (name->Equals(v8_str("p3"))) {
 
5643
    CHECK_EQ(info.This(), global->Get(v8_str("o3")));
 
5644
  } else if (name->Equals(v8_str("p4"))) {
 
5645
    CHECK_EQ(info.This(), global->Get(v8_str("o4")));
 
5646
  }
 
5647
  return v8::Undefined();
 
5648
}
 
5649
 
 
5650
 
 
5651
THREADED_TEST(GetterHolders) {
 
5652
  v8::HandleScope scope;
 
5653
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
5654
  obj->SetAccessor(v8_str("p1"), PGetter);
 
5655
  obj->SetAccessor(v8_str("p2"), PGetter);
 
5656
  obj->SetAccessor(v8_str("p3"), PGetter);
 
5657
  obj->SetAccessor(v8_str("p4"), PGetter);
 
5658
  p_getter_count = 0;
 
5659
  RunHolderTest(obj);
 
5660
  CHECK_EQ(40, p_getter_count);
 
5661
}
 
5662
 
 
5663
 
 
5664
THREADED_TEST(PreInterceptorHolders) {
 
5665
  v8::HandleScope scope;
 
5666
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
5667
  obj->SetNamedPropertyHandler(PGetter2);
 
5668
  p_getter_count2 = 0;
 
5669
  RunHolderTest(obj);
 
5670
  CHECK_EQ(40, p_getter_count2);
 
5671
}
 
5672
 
 
5673
 
 
5674
THREADED_TEST(ObjectInstantiation) {
 
5675
  v8::HandleScope scope;
 
5676
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
5677
  templ->SetAccessor(v8_str("t"), PGetter2);
 
5678
  LocalContext context;
 
5679
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
5680
  for (int i = 0; i < 100; i++) {
 
5681
    v8::HandleScope inner_scope;
 
5682
    v8::Handle<v8::Object> obj = templ->NewInstance();
 
5683
    CHECK_NE(obj, context->Global()->Get(v8_str("o")));
 
5684
    context->Global()->Set(v8_str("o2"), obj);
 
5685
    v8::Handle<Value> value =
 
5686
        Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
 
5687
    CHECK_EQ(v8::True(), value);
 
5688
    context->Global()->Set(v8_str("o"), obj);
 
5689
  }
 
5690
}
 
5691
 
 
5692
 
 
5693
static int StrCmp16(uint16_t* a, uint16_t* b) {
 
5694
  while (true) {
 
5695
    if (*a == 0 && *b == 0) return 0;
 
5696
    if (*a != *b) return 0 + *a - *b;
 
5697
    a++;
 
5698
    b++;
 
5699
  }
 
5700
}
 
5701
 
 
5702
 
 
5703
static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
 
5704
  while (true) {
 
5705
    if (n-- == 0) return 0;
 
5706
    if (*a == 0 && *b == 0) return 0;
 
5707
    if (*a != *b) return 0 + *a - *b;
 
5708
    a++;
 
5709
    b++;
 
5710
  }
 
5711
}
 
5712
 
 
5713
 
 
5714
int GetUtf8Length(Handle<String> str) {
 
5715
  int len = str->Utf8Length();
 
5716
  if (len < 0) {
 
5717
    i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
 
5718
    i::FlattenString(istr);
 
5719
    len = str->Utf8Length();
 
5720
  }
 
5721
  return len;
 
5722
}
 
5723
 
 
5724
 
 
5725
THREADED_TEST(StringWrite) {
 
5726
  LocalContext context;
 
5727
  v8::HandleScope scope;
 
5728
  v8::Handle<String> str = v8_str("abcde");
 
5729
  // abc<Icelandic eth><Unicode snowman>.
 
5730
  v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
 
5731
  v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
 
5732
  const int kStride = 4;  // Must match stride in for loops in JS below.
 
5733
  CompileRun(
 
5734
      "var left = '';"
 
5735
      "for (var i = 0; i < 0xd800; i += 4) {"
 
5736
      "  left = left + String.fromCharCode(i);"
 
5737
      "}");
 
5738
  CompileRun(
 
5739
      "var right = '';"
 
5740
      "for (var i = 0; i < 0xd800; i += 4) {"
 
5741
      "  right = String.fromCharCode(i) + right;"
 
5742
      "}");
 
5743
  v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
 
5744
  Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
 
5745
  Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
 
5746
 
 
5747
  CHECK_EQ(5, str2->Length());
 
5748
  CHECK_EQ(0xd800 / kStride, left_tree->Length());
 
5749
  CHECK_EQ(0xd800 / kStride, right_tree->Length());
 
5750
 
 
5751
  char buf[100];
 
5752
  char utf8buf[0xd800 * 3];
 
5753
  uint16_t wbuf[100];
 
5754
  int len;
 
5755
  int charlen;
 
5756
 
 
5757
  memset(utf8buf, 0x1, 1000);
 
5758
  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
 
5759
  CHECK_EQ(9, len);
 
5760
  CHECK_EQ(5, charlen);
 
5761
  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
 
5762
 
 
5763
  memset(utf8buf, 0x1, 1000);
 
5764
  len = str2->WriteUtf8(utf8buf, 8, &charlen);
 
5765
  CHECK_EQ(8, len);
 
5766
  CHECK_EQ(5, charlen);
 
5767
  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
 
5768
 
 
5769
  memset(utf8buf, 0x1, 1000);
 
5770
  len = str2->WriteUtf8(utf8buf, 7, &charlen);
 
5771
  CHECK_EQ(5, len);
 
5772
  CHECK_EQ(4, charlen);
 
5773
  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
 
5774
 
 
5775
  memset(utf8buf, 0x1, 1000);
 
5776
  len = str2->WriteUtf8(utf8buf, 6, &charlen);
 
5777
  CHECK_EQ(5, len);
 
5778
  CHECK_EQ(4, charlen);
 
5779
  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
 
5780
 
 
5781
  memset(utf8buf, 0x1, 1000);
 
5782
  len = str2->WriteUtf8(utf8buf, 5, &charlen);
 
5783
  CHECK_EQ(5, len);
 
5784
  CHECK_EQ(4, charlen);
 
5785
  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
 
5786
 
 
5787
  memset(utf8buf, 0x1, 1000);
 
5788
  len = str2->WriteUtf8(utf8buf, 4, &charlen);
 
5789
  CHECK_EQ(3, len);
 
5790
  CHECK_EQ(3, charlen);
 
5791
  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
 
5792
 
 
5793
  memset(utf8buf, 0x1, 1000);
 
5794
  len = str2->WriteUtf8(utf8buf, 3, &charlen);
 
5795
  CHECK_EQ(3, len);
 
5796
  CHECK_EQ(3, charlen);
 
5797
  CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
 
5798
 
 
5799
  memset(utf8buf, 0x1, 1000);
 
5800
  len = str2->WriteUtf8(utf8buf, 2, &charlen);
 
5801
  CHECK_EQ(2, len);
 
5802
  CHECK_EQ(2, charlen);
 
5803
  CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
 
5804
 
 
5805
  memset(utf8buf, 0x1, sizeof(utf8buf));
 
5806
  len = GetUtf8Length(left_tree);
 
5807
  int utf8_expected =
 
5808
      (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
 
5809
  CHECK_EQ(utf8_expected, len);
 
5810
  len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
 
5811
  CHECK_EQ(utf8_expected, len);
 
5812
  CHECK_EQ(0xd800 / kStride, charlen);
 
5813
  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
 
5814
  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
 
5815
  CHECK_EQ(0xc0 - kStride,
 
5816
           static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
 
5817
  CHECK_EQ(1, utf8buf[utf8_expected]);
 
5818
 
 
5819
  memset(utf8buf, 0x1, sizeof(utf8buf));
 
5820
  len = GetUtf8Length(right_tree);
 
5821
  CHECK_EQ(utf8_expected, len);
 
5822
  len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
 
5823
  CHECK_EQ(utf8_expected, len);
 
5824
  CHECK_EQ(0xd800 / kStride, charlen);
 
5825
  CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
 
5826
  CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
 
5827
  CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
 
5828
  CHECK_EQ(1, utf8buf[utf8_expected]);
 
5829
 
 
5830
  memset(buf, 0x1, sizeof(buf));
 
5831
  memset(wbuf, 0x1, sizeof(wbuf));
 
5832
  len = str->WriteAscii(buf);
 
5833
  CHECK_EQ(5, len);
 
5834
  len = str->Write(wbuf);
 
5835
  CHECK_EQ(5, len);
 
5836
  CHECK_EQ(0, strcmp("abcde", buf));
 
5837
  uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
 
5838
  CHECK_EQ(0, StrCmp16(answer1, wbuf));
 
5839
 
 
5840
  memset(buf, 0x1, sizeof(buf));
 
5841
  memset(wbuf, 0x1, sizeof(wbuf));
 
5842
  len = str->WriteAscii(buf, 0, 4);
 
5843
  CHECK_EQ(4, len);
 
5844
  len = str->Write(wbuf, 0, 4);
 
5845
  CHECK_EQ(4, len);
 
5846
  CHECK_EQ(0, strncmp("abcd\1", buf, 5));
 
5847
  uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
 
5848
  CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
 
5849
 
 
5850
  memset(buf, 0x1, sizeof(buf));
 
5851
  memset(wbuf, 0x1, sizeof(wbuf));
 
5852
  len = str->WriteAscii(buf, 0, 5);
 
5853
  CHECK_EQ(5, len);
 
5854
  len = str->Write(wbuf, 0, 5);
 
5855
  CHECK_EQ(5, len);
 
5856
  CHECK_EQ(0, strncmp("abcde\1", buf, 6));
 
5857
  uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
 
5858
  CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
 
5859
 
 
5860
  memset(buf, 0x1, sizeof(buf));
 
5861
  memset(wbuf, 0x1, sizeof(wbuf));
 
5862
  len = str->WriteAscii(buf, 0, 6);
 
5863
  CHECK_EQ(5, len);
 
5864
  len = str->Write(wbuf, 0, 6);
 
5865
  CHECK_EQ(5, len);
 
5866
  CHECK_EQ(0, strcmp("abcde", buf));
 
5867
  uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
 
5868
  CHECK_EQ(0, StrCmp16(answer4, wbuf));
 
5869
 
 
5870
  memset(buf, 0x1, sizeof(buf));
 
5871
  memset(wbuf, 0x1, sizeof(wbuf));
 
5872
  len = str->WriteAscii(buf, 4, -1);
 
5873
  CHECK_EQ(1, len);
 
5874
  len = str->Write(wbuf, 4, -1);
 
5875
  CHECK_EQ(1, len);
 
5876
  CHECK_EQ(0, strcmp("e", buf));
 
5877
  uint16_t answer5[] = {'e', '\0'};
 
5878
  CHECK_EQ(0, StrCmp16(answer5, wbuf));
 
5879
 
 
5880
  memset(buf, 0x1, sizeof(buf));
 
5881
  memset(wbuf, 0x1, sizeof(wbuf));
 
5882
  len = str->WriteAscii(buf, 4, 6);
 
5883
  CHECK_EQ(1, len);
 
5884
  len = str->Write(wbuf, 4, 6);
 
5885
  CHECK_EQ(1, len);
 
5886
  CHECK_EQ(0, strcmp("e", buf));
 
5887
  CHECK_EQ(0, StrCmp16(answer5, wbuf));
 
5888
 
 
5889
  memset(buf, 0x1, sizeof(buf));
 
5890
  memset(wbuf, 0x1, sizeof(wbuf));
 
5891
  len = str->WriteAscii(buf, 4, 1);
 
5892
  CHECK_EQ(1, len);
 
5893
  len = str->Write(wbuf, 4, 1);
 
5894
  CHECK_EQ(1, len);
 
5895
  CHECK_EQ(0, strncmp("e\1", buf, 2));
 
5896
  uint16_t answer6[] = {'e', 0x101};
 
5897
  CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
 
5898
 
 
5899
  memset(buf, 0x1, sizeof(buf));
 
5900
  memset(wbuf, 0x1, sizeof(wbuf));
 
5901
  len = str->WriteAscii(buf, 3, 1);
 
5902
  CHECK_EQ(1, len);
 
5903
  len = str->Write(wbuf, 3, 1);
 
5904
  CHECK_EQ(1, len);
 
5905
  CHECK_EQ(0, strncmp("d\1", buf, 2));
 
5906
  uint16_t answer7[] = {'d', 0x101};
 
5907
  CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
 
5908
 
 
5909
  memset(wbuf, 0x1, sizeof(wbuf));
 
5910
  wbuf[5] = 'X';
 
5911
  len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
 
5912
  CHECK_EQ(5, len);
 
5913
  CHECK_EQ('X', wbuf[5]);
 
5914
  uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
 
5915
  uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
 
5916
  CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
 
5917
  CHECK_NE(0, StrCmp16(answer8b, wbuf));
 
5918
  wbuf[5] = '\0';
 
5919
  CHECK_EQ(0, StrCmp16(answer8b, wbuf));
 
5920
 
 
5921
  memset(buf, 0x1, sizeof(buf));
 
5922
  buf[5] = 'X';
 
5923
  len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
 
5924
  CHECK_EQ(5, len);
 
5925
  CHECK_EQ('X', buf[5]);
 
5926
  CHECK_EQ(0, strncmp("abcde", buf, 5));
 
5927
  CHECK_NE(0, strcmp("abcde", buf));
 
5928
  buf[5] = '\0';
 
5929
  CHECK_EQ(0, strcmp("abcde", buf));
 
5930
 
 
5931
  memset(utf8buf, 0x1, sizeof(utf8buf));
 
5932
  utf8buf[8] = 'X';
 
5933
  len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
 
5934
                        String::NO_NULL_TERMINATION);
 
5935
  CHECK_EQ(8, len);
 
5936
  CHECK_EQ('X', utf8buf[8]);
 
5937
  CHECK_EQ(5, charlen);
 
5938
  CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
 
5939
  CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
 
5940
  utf8buf[8] = '\0';
 
5941
  CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
 
5942
 
 
5943
  memset(utf8buf, 0x1, sizeof(utf8buf));
 
5944
  utf8buf[5] = 'X';
 
5945
  len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
 
5946
                        String::NO_NULL_TERMINATION);
 
5947
  CHECK_EQ(5, len);
 
5948
  CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
 
5949
  CHECK_EQ(5, charlen);
 
5950
  utf8buf[5] = '\0';
 
5951
  CHECK_EQ(0, strcmp(utf8buf, "abcde"));
 
5952
 
 
5953
  memset(buf, 0x1, sizeof(buf));
 
5954
  len = str3->WriteAscii(buf);
 
5955
  CHECK_EQ(7, len);
 
5956
  CHECK_EQ(0, strcmp("abc def", buf));
 
5957
 
 
5958
  memset(buf, 0x1, sizeof(buf));
 
5959
  len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
 
5960
  CHECK_EQ(7, len);
 
5961
  CHECK_EQ(0, strcmp("abc", buf));
 
5962
  CHECK_EQ(0, buf[3]);
 
5963
  CHECK_EQ(0, strcmp("def", buf + 4));
 
5964
}
 
5965
 
 
5966
 
 
5967
static void Utf16Helper(
 
5968
    LocalContext& context,
 
5969
    const char* name,
 
5970
    const char* lengths_name,
 
5971
    int len) {
 
5972
  Local<v8::Array> a =
 
5973
      Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
 
5974
  Local<v8::Array> alens =
 
5975
      Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
 
5976
  for (int i = 0; i < len; i++) {
 
5977
    Local<v8::String> string =
 
5978
      Local<v8::String>::Cast(a->Get(i));
 
5979
    Local<v8::Number> expected_len =
 
5980
      Local<v8::Number>::Cast(alens->Get(i));
 
5981
    CHECK_EQ(expected_len->Value() != string->Length(),
 
5982
             string->MayContainNonAscii());
 
5983
    int length = GetUtf8Length(string);
 
5984
    CHECK_EQ(static_cast<int>(expected_len->Value()), length);
 
5985
  }
 
5986
}
 
5987
 
 
5988
 
 
5989
static uint16_t StringGet(Handle<String> str, int index) {
 
5990
  i::Handle<i::String> istring =
 
5991
      v8::Utils::OpenHandle(String::Cast(*str));
 
5992
  return istring->Get(index);
 
5993
}
 
5994
 
 
5995
 
 
5996
static void WriteUtf8Helper(
 
5997
    LocalContext& context,
 
5998
    const char* name,
 
5999
    const char* lengths_name,
 
6000
    int len) {
 
6001
  Local<v8::Array> b =
 
6002
      Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
 
6003
  Local<v8::Array> alens =
 
6004
      Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
 
6005
  char buffer[1000];
 
6006
  char buffer2[1000];
 
6007
  for (int i = 0; i < len; i++) {
 
6008
    Local<v8::String> string =
 
6009
      Local<v8::String>::Cast(b->Get(i));
 
6010
    Local<v8::Number> expected_len =
 
6011
      Local<v8::Number>::Cast(alens->Get(i));
 
6012
    int utf8_length = static_cast<int>(expected_len->Value());
 
6013
    for (int j = utf8_length + 1; j >= 0; j--) {
 
6014
      memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
 
6015
      memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
 
6016
      int nchars;
 
6017
      int utf8_written =
 
6018
          string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
 
6019
      int utf8_written2 =
 
6020
          string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
 
6021
      CHECK_GE(utf8_length + 1, utf8_written);
 
6022
      CHECK_GE(utf8_length, utf8_written2);
 
6023
      for (int k = 0; k < utf8_written2; k++) {
 
6024
        CHECK_EQ(buffer[k], buffer2[k]);
 
6025
      }
 
6026
      CHECK(nchars * 3 >= utf8_written - 1);
 
6027
      CHECK(nchars <= utf8_written);
 
6028
      if (j == utf8_length + 1) {
 
6029
        CHECK_EQ(utf8_written2, utf8_length);
 
6030
        CHECK_EQ(utf8_written2 + 1, utf8_written);
 
6031
      }
 
6032
      CHECK_EQ(buffer[utf8_written], 42);
 
6033
      if (j > utf8_length) {
 
6034
        if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
 
6035
        if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
 
6036
        Handle<String> roundtrip = v8_str(buffer);
 
6037
        CHECK(roundtrip->Equals(string));
 
6038
      } else {
 
6039
        if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
 
6040
      }
 
6041
      if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
 
6042
      if (nchars >= 2) {
 
6043
        uint16_t trail = StringGet(string, nchars - 1);
 
6044
        uint16_t lead = StringGet(string, nchars - 2);
 
6045
        if (((lead & 0xfc00) == 0xd800) &&
 
6046
            ((trail & 0xfc00) == 0xdc00)) {
 
6047
          unsigned char u1 = buffer2[utf8_written2 - 4];
 
6048
          unsigned char u2 = buffer2[utf8_written2 - 3];
 
6049
          unsigned char u3 = buffer2[utf8_written2 - 2];
 
6050
          unsigned char u4 = buffer2[utf8_written2 - 1];
 
6051
          CHECK_EQ((u1 & 0xf8), 0xf0);
 
6052
          CHECK_EQ((u2 & 0xc0), 0x80);
 
6053
          CHECK_EQ((u3 & 0xc0), 0x80);
 
6054
          CHECK_EQ((u4 & 0xc0), 0x80);
 
6055
          uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
 
6056
          CHECK_EQ((u4 & 0x3f), (c & 0x3f));
 
6057
          CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
 
6058
          CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
 
6059
          CHECK_EQ((u1 & 0x3), c >> 18);
 
6060
        }
 
6061
      }
 
6062
    }
 
6063
  }
 
6064
}
 
6065
 
 
6066
 
 
6067
THREADED_TEST(Utf16) {
 
6068
  LocalContext context;
 
6069
  v8::HandleScope scope;
 
6070
  CompileRun(
 
6071
      "var pad = '01234567890123456789';"
 
6072
      "var p = [];"
 
6073
      "var plens = [20, 3, 3];"
 
6074
      "p.push('01234567890123456789');"
 
6075
      "var lead = 0xd800;"
 
6076
      "var trail = 0xdc00;"
 
6077
      "p.push(String.fromCharCode(0xd800));"
 
6078
      "p.push(String.fromCharCode(0xdc00));"
 
6079
      "var a = [];"
 
6080
      "var b = [];"
 
6081
      "var c = [];"
 
6082
      "var alens = [];"
 
6083
      "for (var i = 0; i < 3; i++) {"
 
6084
      "  p[1] = String.fromCharCode(lead++);"
 
6085
      "  for (var j = 0; j < 3; j++) {"
 
6086
      "    p[2] = String.fromCharCode(trail++);"
 
6087
      "    a.push(p[i] + p[j]);"
 
6088
      "    b.push(p[i] + p[j]);"
 
6089
      "    c.push(p[i] + p[j]);"
 
6090
      "    alens.push(plens[i] + plens[j]);"
 
6091
      "  }"
 
6092
      "}"
 
6093
      "alens[5] -= 2;"  // Here the surrogate pairs match up.
 
6094
      "var a2 = [];"
 
6095
      "var b2 = [];"
 
6096
      "var c2 = [];"
 
6097
      "var a2lens = [];"
 
6098
      "for (var m = 0; m < 9; m++) {"
 
6099
      "  for (var n = 0; n < 9; n++) {"
 
6100
      "    a2.push(a[m] + a[n]);"
 
6101
      "    b2.push(b[m] + b[n]);"
 
6102
      "    var newc = 'x' + c[m] + c[n] + 'y';"
 
6103
      "    c2.push(newc.substring(1, newc.length - 1));"
 
6104
      "    var utf = alens[m] + alens[n];"  // And here.
 
6105
           // The 'n's that start with 0xdc.. are 6-8
 
6106
           // The 'm's that end with 0xd8.. are 1, 4 and 7
 
6107
      "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
 
6108
      "    a2lens.push(utf);"
 
6109
      "  }"
 
6110
      "}");
 
6111
  Utf16Helper(context, "a", "alens", 9);
 
6112
  Utf16Helper(context, "a2", "a2lens", 81);
 
6113
  WriteUtf8Helper(context, "b", "alens", 9);
 
6114
  WriteUtf8Helper(context, "b2", "a2lens", 81);
 
6115
  WriteUtf8Helper(context, "c2", "a2lens", 81);
 
6116
}
 
6117
 
 
6118
 
 
6119
static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
 
6120
  i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
 
6121
  i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
 
6122
  return *is1 == *is2;
 
6123
}
 
6124
 
 
6125
 
 
6126
static void SameSymbolHelper(const char* a, const char* b) {
 
6127
  Handle<String> symbol1 = v8::String::NewSymbol(a);
 
6128
  Handle<String> symbol2 = v8::String::NewSymbol(b);
 
6129
  CHECK(SameSymbol(symbol1, symbol2));
 
6130
}
 
6131
 
 
6132
 
 
6133
THREADED_TEST(Utf16Symbol) {
 
6134
  LocalContext context;
 
6135
  v8::HandleScope scope;
 
6136
 
 
6137
  Handle<String> symbol1 = v8::String::NewSymbol("abc");
 
6138
  Handle<String> symbol2 = v8::String::NewSymbol("abc");
 
6139
  CHECK(SameSymbol(symbol1, symbol2));
 
6140
 
 
6141
  SameSymbolHelper("\360\220\220\205",  // 4 byte encoding.
 
6142
                   "\355\240\201\355\260\205");  // 2 3-byte surrogates.
 
6143
  SameSymbolHelper("\355\240\201\355\260\206",  // 2 3-byte surrogates.
 
6144
                   "\360\220\220\206");  // 4 byte encoding.
 
6145
  SameSymbolHelper("x\360\220\220\205",  // 4 byte encoding.
 
6146
                   "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
 
6147
  SameSymbolHelper("x\355\240\201\355\260\206",  // 2 3-byte surrogates.
 
6148
                   "x\360\220\220\206");  // 4 byte encoding.
 
6149
  CompileRun(
 
6150
      "var sym0 = 'benedictus';"
 
6151
      "var sym0b = 'S\303\270ren';"
 
6152
      "var sym1 = '\355\240\201\355\260\207';"
 
6153
      "var sym2 = '\360\220\220\210';"
 
6154
      "var sym3 = 'x\355\240\201\355\260\207';"
 
6155
      "var sym4 = 'x\360\220\220\210';"
 
6156
      "if (sym1.length != 2) throw sym1;"
 
6157
      "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
 
6158
      "if (sym2.length != 2) throw sym2;"
 
6159
      "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
 
6160
      "if (sym3.length != 3) throw sym3;"
 
6161
      "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
 
6162
      "if (sym4.length != 3) throw sym4;"
 
6163
      "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
 
6164
  Handle<String> sym0 = v8::String::NewSymbol("benedictus");
 
6165
  Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
 
6166
  Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
 
6167
  Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
 
6168
  Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
 
6169
  Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
 
6170
  v8::Local<v8::Object> global = context->Global();
 
6171
  Local<Value> s0 = global->Get(v8_str("sym0"));
 
6172
  Local<Value> s0b = global->Get(v8_str("sym0b"));
 
6173
  Local<Value> s1 = global->Get(v8_str("sym1"));
 
6174
  Local<Value> s2 = global->Get(v8_str("sym2"));
 
6175
  Local<Value> s3 = global->Get(v8_str("sym3"));
 
6176
  Local<Value> s4 = global->Get(v8_str("sym4"));
 
6177
  CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
 
6178
  CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
 
6179
  CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
 
6180
  CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
 
6181
  CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
 
6182
  CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
 
6183
}
 
6184
 
 
6185
 
 
6186
THREADED_TEST(ToArrayIndex) {
 
6187
  v8::HandleScope scope;
 
6188
  LocalContext context;
 
6189
 
 
6190
  v8::Handle<String> str = v8_str("42");
 
6191
  v8::Handle<v8::Uint32> index = str->ToArrayIndex();
 
6192
  CHECK(!index.IsEmpty());
 
6193
  CHECK_EQ(42.0, index->Uint32Value());
 
6194
  str = v8_str("42asdf");
 
6195
  index = str->ToArrayIndex();
 
6196
  CHECK(index.IsEmpty());
 
6197
  str = v8_str("-42");
 
6198
  index = str->ToArrayIndex();
 
6199
  CHECK(index.IsEmpty());
 
6200
  str = v8_str("4294967295");
 
6201
  index = str->ToArrayIndex();
 
6202
  CHECK(!index.IsEmpty());
 
6203
  CHECK_EQ(4294967295.0, index->Uint32Value());
 
6204
  v8::Handle<v8::Number> num = v8::Number::New(1);
 
6205
  index = num->ToArrayIndex();
 
6206
  CHECK(!index.IsEmpty());
 
6207
  CHECK_EQ(1.0, index->Uint32Value());
 
6208
  num = v8::Number::New(-1);
 
6209
  index = num->ToArrayIndex();
 
6210
  CHECK(index.IsEmpty());
 
6211
  v8::Handle<v8::Object> obj = v8::Object::New();
 
6212
  index = obj->ToArrayIndex();
 
6213
  CHECK(index.IsEmpty());
 
6214
}
 
6215
 
 
6216
 
 
6217
THREADED_TEST(ErrorConstruction) {
 
6218
  v8::HandleScope scope;
 
6219
  LocalContext context;
 
6220
 
 
6221
  v8::Handle<String> foo = v8_str("foo");
 
6222
  v8::Handle<String> message = v8_str("message");
 
6223
  v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
 
6224
  CHECK(range_error->IsObject());
 
6225
  CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
 
6226
  v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
 
6227
  CHECK(reference_error->IsObject());
 
6228
  CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
 
6229
  v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
 
6230
  CHECK(syntax_error->IsObject());
 
6231
  CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
 
6232
  v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
 
6233
  CHECK(type_error->IsObject());
 
6234
  CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
 
6235
  v8::Handle<Value> error = v8::Exception::Error(foo);
 
6236
  CHECK(error->IsObject());
 
6237
  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
 
6238
}
 
6239
 
 
6240
 
 
6241
static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
 
6242
  ApiTestFuzzer::Fuzz();
 
6243
  return v8_num(10);
 
6244
}
 
6245
 
 
6246
 
 
6247
static void YSetter(Local<String> name,
 
6248
                    Local<Value> value,
 
6249
                    const AccessorInfo& info) {
 
6250
  if (info.This()->Has(name)) {
 
6251
    info.This()->Delete(name);
 
6252
  }
 
6253
  info.This()->Set(name, value);
 
6254
}
 
6255
 
 
6256
 
 
6257
THREADED_TEST(DeleteAccessor) {
 
6258
  v8::HandleScope scope;
 
6259
  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
 
6260
  obj->SetAccessor(v8_str("y"), YGetter, YSetter);
 
6261
  LocalContext context;
 
6262
  v8::Handle<v8::Object> holder = obj->NewInstance();
 
6263
  context->Global()->Set(v8_str("holder"), holder);
 
6264
  v8::Handle<Value> result = CompileRun(
 
6265
      "holder.y = 11; holder.y = 12; holder.y");
 
6266
  CHECK_EQ(12, result->Uint32Value());
 
6267
}
 
6268
 
 
6269
 
 
6270
THREADED_TEST(TypeSwitch) {
 
6271
  v8::HandleScope scope;
 
6272
  v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
 
6273
  v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
 
6274
  v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
 
6275
  v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
 
6276
  v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
 
6277
  LocalContext context;
 
6278
  v8::Handle<v8::Object> obj0 = v8::Object::New();
 
6279
  v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
 
6280
  v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
 
6281
  v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
 
6282
  for (int i = 0; i < 10; i++) {
 
6283
    CHECK_EQ(0, type_switch->match(obj0));
 
6284
    CHECK_EQ(1, type_switch->match(obj1));
 
6285
    CHECK_EQ(2, type_switch->match(obj2));
 
6286
    CHECK_EQ(3, type_switch->match(obj3));
 
6287
    CHECK_EQ(3, type_switch->match(obj3));
 
6288
    CHECK_EQ(2, type_switch->match(obj2));
 
6289
    CHECK_EQ(1, type_switch->match(obj1));
 
6290
    CHECK_EQ(0, type_switch->match(obj0));
 
6291
  }
 
6292
}
 
6293
 
 
6294
 
 
6295
// For use within the TestSecurityHandler() test.
 
6296
static bool g_security_callback_result = false;
 
6297
static bool NamedSecurityTestCallback(Local<v8::Object> global,
 
6298
                                      Local<Value> name,
 
6299
                                      v8::AccessType type,
 
6300
                                      Local<Value> data) {
 
6301
  // Always allow read access.
 
6302
  if (type == v8::ACCESS_GET)
 
6303
    return true;
 
6304
 
 
6305
  // Sometimes allow other access.
 
6306
  return g_security_callback_result;
 
6307
}
 
6308
 
 
6309
 
 
6310
static bool IndexedSecurityTestCallback(Local<v8::Object> global,
 
6311
                                        uint32_t key,
 
6312
                                        v8::AccessType type,
 
6313
                                        Local<Value> data) {
 
6314
  // Always allow read access.
 
6315
  if (type == v8::ACCESS_GET)
 
6316
    return true;
 
6317
 
 
6318
  // Sometimes allow other access.
 
6319
  return g_security_callback_result;
 
6320
}
 
6321
 
 
6322
 
 
6323
static int trouble_nesting = 0;
 
6324
static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
 
6325
  ApiTestFuzzer::Fuzz();
 
6326
  trouble_nesting++;
 
6327
 
 
6328
  // Call a JS function that throws an uncaught exception.
 
6329
  Local<v8::Object> arg_this = Context::GetCurrent()->Global();
 
6330
  Local<Value> trouble_callee = (trouble_nesting == 3) ?
 
6331
    arg_this->Get(v8_str("trouble_callee")) :
 
6332
    arg_this->Get(v8_str("trouble_caller"));
 
6333
  CHECK(trouble_callee->IsFunction());
 
6334
  return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
 
6335
}
 
6336
 
 
6337
 
 
6338
static int report_count = 0;
 
6339
static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
 
6340
                                             v8::Handle<Value>) {
 
6341
  report_count++;
 
6342
}
 
6343
 
 
6344
 
 
6345
// Counts uncaught exceptions, but other tests running in parallel
 
6346
// also have uncaught exceptions.
 
6347
TEST(ApiUncaughtException) {
 
6348
  report_count = 0;
 
6349
  v8::HandleScope scope;
 
6350
  LocalContext env;
 
6351
  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
 
6352
 
 
6353
  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
 
6354
  v8::Local<v8::Object> global = env->Global();
 
6355
  global->Set(v8_str("trouble"), fun->GetFunction());
 
6356
 
 
6357
  Script::Compile(v8_str("function trouble_callee() {"
 
6358
                         "  var x = null;"
 
6359
                         "  return x.foo;"
 
6360
                         "};"
 
6361
                         "function trouble_caller() {"
 
6362
                         "  trouble();"
 
6363
                         "};"))->Run();
 
6364
  Local<Value> trouble = global->Get(v8_str("trouble"));
 
6365
  CHECK(trouble->IsFunction());
 
6366
  Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
 
6367
  CHECK(trouble_callee->IsFunction());
 
6368
  Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
 
6369
  CHECK(trouble_caller->IsFunction());
 
6370
  Function::Cast(*trouble_caller)->Call(global, 0, NULL);
 
6371
  CHECK_EQ(1, report_count);
 
6372
  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
 
6373
}
 
6374
 
 
6375
static const char* script_resource_name = "ExceptionInNativeScript.js";
 
6376
static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
 
6377
                                                v8::Handle<Value>) {
 
6378
  v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
 
6379
  CHECK(!name_val.IsEmpty() && name_val->IsString());
 
6380
  v8::String::AsciiValue name(message->GetScriptResourceName());
 
6381
  CHECK_EQ(script_resource_name, *name);
 
6382
  CHECK_EQ(3, message->GetLineNumber());
 
6383
  v8::String::AsciiValue source_line(message->GetSourceLine());
 
6384
  CHECK_EQ("  new o.foo();", *source_line);
 
6385
}
 
6386
 
 
6387
TEST(ExceptionInNativeScript) {
 
6388
  v8::HandleScope scope;
 
6389
  LocalContext env;
 
6390
  v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
 
6391
 
 
6392
  Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
 
6393
  v8::Local<v8::Object> global = env->Global();
 
6394
  global->Set(v8_str("trouble"), fun->GetFunction());
 
6395
 
 
6396
  Script::Compile(v8_str("function trouble() {\n"
 
6397
                         "  var o = {};\n"
 
6398
                         "  new o.foo();\n"
 
6399
                         "};"), v8::String::New(script_resource_name))->Run();
 
6400
  Local<Value> trouble = global->Get(v8_str("trouble"));
 
6401
  CHECK(trouble->IsFunction());
 
6402
  Function::Cast(*trouble)->Call(global, 0, NULL);
 
6403
  v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
 
6404
}
 
6405
 
 
6406
 
 
6407
TEST(CompilationErrorUsingTryCatchHandler) {
 
6408
  v8::HandleScope scope;
 
6409
  LocalContext env;
 
6410
  v8::TryCatch try_catch;
 
6411
  Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
 
6412
  CHECK_NE(NULL, *try_catch.Exception());
 
6413
  CHECK(try_catch.HasCaught());
 
6414
}
 
6415
 
 
6416
 
 
6417
TEST(TryCatchFinallyUsingTryCatchHandler) {
 
6418
  v8::HandleScope scope;
 
6419
  LocalContext env;
 
6420
  v8::TryCatch try_catch;
 
6421
  Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
 
6422
  CHECK(!try_catch.HasCaught());
 
6423
  Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
 
6424
  CHECK(try_catch.HasCaught());
 
6425
  try_catch.Reset();
 
6426
  Script::Compile(v8_str("(function() {"
 
6427
                         "try { throw ''; } finally { return; }"
 
6428
                         "})()"))->Run();
 
6429
  CHECK(!try_catch.HasCaught());
 
6430
  Script::Compile(v8_str("(function()"
 
6431
                         "  { try { throw ''; } finally { throw 0; }"
 
6432
                         "})()"))->Run();
 
6433
  CHECK(try_catch.HasCaught());
 
6434
}
 
6435
 
 
6436
 
 
6437
// SecurityHandler can't be run twice
 
6438
TEST(SecurityHandler) {
 
6439
  v8::HandleScope scope0;
 
6440
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
6441
  global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
 
6442
                                           IndexedSecurityTestCallback);
 
6443
  // Create an environment
 
6444
  v8::Persistent<Context> context0 =
 
6445
    Context::New(NULL, global_template);
 
6446
  context0->Enter();
 
6447
 
 
6448
  v8::Handle<v8::Object> global0 = context0->Global();
 
6449
  v8::Handle<Script> script0 = v8_compile("foo = 111");
 
6450
  script0->Run();
 
6451
  global0->Set(v8_str("0"), v8_num(999));
 
6452
  v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
 
6453
  CHECK_EQ(111, foo0->Int32Value());
 
6454
  v8::Handle<Value> z0 = global0->Get(v8_str("0"));
 
6455
  CHECK_EQ(999, z0->Int32Value());
 
6456
 
 
6457
  // Create another environment, should fail security checks.
 
6458
  v8::HandleScope scope1;
 
6459
 
 
6460
  v8::Persistent<Context> context1 =
 
6461
    Context::New(NULL, global_template);
 
6462
  context1->Enter();
 
6463
 
 
6464
  v8::Handle<v8::Object> global1 = context1->Global();
 
6465
  global1->Set(v8_str("othercontext"), global0);
 
6466
  // This set will fail the security check.
 
6467
  v8::Handle<Script> script1 =
 
6468
    v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
 
6469
  script1->Run();
 
6470
  // This read will pass the security check.
 
6471
  v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
 
6472
  CHECK_EQ(111, foo1->Int32Value());
 
6473
  // This read will pass the security check.
 
6474
  v8::Handle<Value> z1 = global0->Get(v8_str("0"));
 
6475
  CHECK_EQ(999, z1->Int32Value());
 
6476
 
 
6477
  // Create another environment, should pass security checks.
 
6478
  { g_security_callback_result = true;  // allow security handler to pass.
 
6479
    v8::HandleScope scope2;
 
6480
    LocalContext context2;
 
6481
    v8::Handle<v8::Object> global2 = context2->Global();
 
6482
    global2->Set(v8_str("othercontext"), global0);
 
6483
    v8::Handle<Script> script2 =
 
6484
        v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
 
6485
    script2->Run();
 
6486
    v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
 
6487
    CHECK_EQ(333, foo2->Int32Value());
 
6488
    v8::Handle<Value> z2 = global0->Get(v8_str("0"));
 
6489
    CHECK_EQ(888, z2->Int32Value());
 
6490
  }
 
6491
 
 
6492
  context1->Exit();
 
6493
  context1.Dispose();
 
6494
 
 
6495
  context0->Exit();
 
6496
  context0.Dispose();
 
6497
}
 
6498
 
 
6499
 
 
6500
THREADED_TEST(SecurityChecks) {
 
6501
  v8::HandleScope handle_scope;
 
6502
  LocalContext env1;
 
6503
  v8::Persistent<Context> env2 = Context::New();
 
6504
 
 
6505
  Local<Value> foo = v8_str("foo");
 
6506
  Local<Value> bar = v8_str("bar");
 
6507
 
 
6508
  // Set to the same domain.
 
6509
  env1->SetSecurityToken(foo);
 
6510
 
 
6511
  // Create a function in env1.
 
6512
  Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
 
6513
  Local<Value> spy = env1->Global()->Get(v8_str("spy"));
 
6514
  CHECK(spy->IsFunction());
 
6515
 
 
6516
  // Create another function accessing global objects.
 
6517
  Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
 
6518
  Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
 
6519
  CHECK(spy2->IsFunction());
 
6520
 
 
6521
  // Switch to env2 in the same domain and invoke spy on env2.
 
6522
  {
 
6523
    env2->SetSecurityToken(foo);
 
6524
    // Enter env2
 
6525
    Context::Scope scope_env2(env2);
 
6526
    Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
 
6527
    CHECK(result->IsFunction());
 
6528
  }
 
6529
 
 
6530
  {
 
6531
    env2->SetSecurityToken(bar);
 
6532
    Context::Scope scope_env2(env2);
 
6533
 
 
6534
    // Call cross_domain_call, it should throw an exception
 
6535
    v8::TryCatch try_catch;
 
6536
    Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
 
6537
    CHECK(try_catch.HasCaught());
 
6538
  }
 
6539
 
 
6540
  env2.Dispose();
 
6541
}
 
6542
 
 
6543
 
 
6544
// Regression test case for issue 1183439.
 
6545
THREADED_TEST(SecurityChecksForPrototypeChain) {
 
6546
  v8::HandleScope scope;
 
6547
  LocalContext current;
 
6548
  v8::Persistent<Context> other = Context::New();
 
6549
 
 
6550
  // Change context to be able to get to the Object function in the
 
6551
  // other context without hitting the security checks.
 
6552
  v8::Local<Value> other_object;
 
6553
  { Context::Scope scope(other);
 
6554
    other_object = other->Global()->Get(v8_str("Object"));
 
6555
    other->Global()->Set(v8_num(42), v8_num(87));
 
6556
  }
 
6557
 
 
6558
  current->Global()->Set(v8_str("other"), other->Global());
 
6559
  CHECK(v8_compile("other")->Run()->Equals(other->Global()));
 
6560
 
 
6561
  // Make sure the security check fails here and we get an undefined
 
6562
  // result instead of getting the Object function. Repeat in a loop
 
6563
  // to make sure to exercise the IC code.
 
6564
  v8::Local<Script> access_other0 = v8_compile("other.Object");
 
6565
  v8::Local<Script> access_other1 = v8_compile("other[42]");
 
6566
  for (int i = 0; i < 5; i++) {
 
6567
    CHECK(!access_other0->Run()->Equals(other_object));
 
6568
    CHECK(access_other0->Run()->IsUndefined());
 
6569
    CHECK(!access_other1->Run()->Equals(v8_num(87)));
 
6570
    CHECK(access_other1->Run()->IsUndefined());
 
6571
  }
 
6572
 
 
6573
  // Create an object that has 'other' in its prototype chain and make
 
6574
  // sure we cannot access the Object function indirectly through
 
6575
  // that. Repeat in a loop to make sure to exercise the IC code.
 
6576
  v8_compile("function F() { };"
 
6577
             "F.prototype = other;"
 
6578
             "var f = new F();")->Run();
 
6579
  v8::Local<Script> access_f0 = v8_compile("f.Object");
 
6580
  v8::Local<Script> access_f1 = v8_compile("f[42]");
 
6581
  for (int j = 0; j < 5; j++) {
 
6582
    CHECK(!access_f0->Run()->Equals(other_object));
 
6583
    CHECK(access_f0->Run()->IsUndefined());
 
6584
    CHECK(!access_f1->Run()->Equals(v8_num(87)));
 
6585
    CHECK(access_f1->Run()->IsUndefined());
 
6586
  }
 
6587
 
 
6588
  // Now it gets hairy: Set the prototype for the other global object
 
6589
  // to be the current global object. The prototype chain for 'f' now
 
6590
  // goes through 'other' but ends up in the current global object.
 
6591
  { Context::Scope scope(other);
 
6592
    other->Global()->Set(v8_str("__proto__"), current->Global());
 
6593
  }
 
6594
  // Set a named and an index property on the current global
 
6595
  // object. To force the lookup to go through the other global object,
 
6596
  // the properties must not exist in the other global object.
 
6597
  current->Global()->Set(v8_str("foo"), v8_num(100));
 
6598
  current->Global()->Set(v8_num(99), v8_num(101));
 
6599
  // Try to read the properties from f and make sure that the access
 
6600
  // gets stopped by the security checks on the other global object.
 
6601
  Local<Script> access_f2 = v8_compile("f.foo");
 
6602
  Local<Script> access_f3 = v8_compile("f[99]");
 
6603
  for (int k = 0; k < 5; k++) {
 
6604
    CHECK(!access_f2->Run()->Equals(v8_num(100)));
 
6605
    CHECK(access_f2->Run()->IsUndefined());
 
6606
    CHECK(!access_f3->Run()->Equals(v8_num(101)));
 
6607
    CHECK(access_f3->Run()->IsUndefined());
 
6608
  }
 
6609
  other.Dispose();
 
6610
}
 
6611
 
 
6612
 
 
6613
THREADED_TEST(CrossDomainDelete) {
 
6614
  v8::HandleScope handle_scope;
 
6615
  LocalContext env1;
 
6616
  v8::Persistent<Context> env2 = Context::New();
 
6617
 
 
6618
  Local<Value> foo = v8_str("foo");
 
6619
  Local<Value> bar = v8_str("bar");
 
6620
 
 
6621
  // Set to the same domain.
 
6622
  env1->SetSecurityToken(foo);
 
6623
  env2->SetSecurityToken(foo);
 
6624
 
 
6625
  env1->Global()->Set(v8_str("prop"), v8_num(3));
 
6626
  env2->Global()->Set(v8_str("env1"), env1->Global());
 
6627
 
 
6628
  // Change env2 to a different domain and delete env1.prop.
 
6629
  env2->SetSecurityToken(bar);
 
6630
  {
 
6631
    Context::Scope scope_env2(env2);
 
6632
    Local<Value> result =
 
6633
        Script::Compile(v8_str("delete env1.prop"))->Run();
 
6634
    CHECK(result->IsFalse());
 
6635
  }
 
6636
 
 
6637
  // Check that env1.prop still exists.
 
6638
  Local<Value> v = env1->Global()->Get(v8_str("prop"));
 
6639
  CHECK(v->IsNumber());
 
6640
  CHECK_EQ(3, v->Int32Value());
 
6641
 
 
6642
  env2.Dispose();
 
6643
}
 
6644
 
 
6645
 
 
6646
THREADED_TEST(CrossDomainIsPropertyEnumerable) {
 
6647
  v8::HandleScope handle_scope;
 
6648
  LocalContext env1;
 
6649
  v8::Persistent<Context> env2 = Context::New();
 
6650
 
 
6651
  Local<Value> foo = v8_str("foo");
 
6652
  Local<Value> bar = v8_str("bar");
 
6653
 
 
6654
  // Set to the same domain.
 
6655
  env1->SetSecurityToken(foo);
 
6656
  env2->SetSecurityToken(foo);
 
6657
 
 
6658
  env1->Global()->Set(v8_str("prop"), v8_num(3));
 
6659
  env2->Global()->Set(v8_str("env1"), env1->Global());
 
6660
 
 
6661
  // env1.prop is enumerable in env2.
 
6662
  Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
 
6663
  {
 
6664
    Context::Scope scope_env2(env2);
 
6665
    Local<Value> result = Script::Compile(test)->Run();
 
6666
    CHECK(result->IsTrue());
 
6667
  }
 
6668
 
 
6669
  // Change env2 to a different domain and test again.
 
6670
  env2->SetSecurityToken(bar);
 
6671
  {
 
6672
    Context::Scope scope_env2(env2);
 
6673
    Local<Value> result = Script::Compile(test)->Run();
 
6674
    CHECK(result->IsFalse());
 
6675
  }
 
6676
 
 
6677
  env2.Dispose();
 
6678
}
 
6679
 
 
6680
 
 
6681
THREADED_TEST(CrossDomainForIn) {
 
6682
  v8::HandleScope handle_scope;
 
6683
  LocalContext env1;
 
6684
  v8::Persistent<Context> env2 = Context::New();
 
6685
 
 
6686
  Local<Value> foo = v8_str("foo");
 
6687
  Local<Value> bar = v8_str("bar");
 
6688
 
 
6689
  // Set to the same domain.
 
6690
  env1->SetSecurityToken(foo);
 
6691
  env2->SetSecurityToken(foo);
 
6692
 
 
6693
  env1->Global()->Set(v8_str("prop"), v8_num(3));
 
6694
  env2->Global()->Set(v8_str("env1"), env1->Global());
 
6695
 
 
6696
  // Change env2 to a different domain and set env1's global object
 
6697
  // as the __proto__ of an object in env2 and enumerate properties
 
6698
  // in for-in. It shouldn't enumerate properties on env1's global
 
6699
  // object.
 
6700
  env2->SetSecurityToken(bar);
 
6701
  {
 
6702
    Context::Scope scope_env2(env2);
 
6703
    Local<Value> result =
 
6704
        CompileRun("(function(){var obj = {'__proto__':env1};"
 
6705
                   "for (var p in obj)"
 
6706
                   "   if (p == 'prop') return false;"
 
6707
                   "return true;})()");
 
6708
    CHECK(result->IsTrue());
 
6709
  }
 
6710
  env2.Dispose();
 
6711
}
 
6712
 
 
6713
 
 
6714
TEST(ContextDetachGlobal) {
 
6715
  v8::HandleScope handle_scope;
 
6716
  LocalContext env1;
 
6717
  v8::Persistent<Context> env2 = Context::New();
 
6718
 
 
6719
  Local<v8::Object> global1 = env1->Global();
 
6720
 
 
6721
  Local<Value> foo = v8_str("foo");
 
6722
 
 
6723
  // Set to the same domain.
 
6724
  env1->SetSecurityToken(foo);
 
6725
  env2->SetSecurityToken(foo);
 
6726
 
 
6727
  // Enter env2
 
6728
  env2->Enter();
 
6729
 
 
6730
  // Create a function in env2 and add a reference to it in env1.
 
6731
  Local<v8::Object> global2 = env2->Global();
 
6732
  global2->Set(v8_str("prop"), v8::Integer::New(1));
 
6733
  CompileRun("function getProp() {return prop;}");
 
6734
 
 
6735
  env1->Global()->Set(v8_str("getProp"),
 
6736
                      global2->Get(v8_str("getProp")));
 
6737
 
 
6738
  // Detach env2's global, and reuse the global object of env2
 
6739
  env2->Exit();
 
6740
  env2->DetachGlobal();
 
6741
  // env2 has a new global object.
 
6742
  CHECK(!env2->Global()->Equals(global2));
 
6743
 
 
6744
  v8::Persistent<Context> env3 =
 
6745
      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
 
6746
  env3->SetSecurityToken(v8_str("bar"));
 
6747
  env3->Enter();
 
6748
 
 
6749
  Local<v8::Object> global3 = env3->Global();
 
6750
  CHECK_EQ(global2, global3);
 
6751
  CHECK(global3->Get(v8_str("prop"))->IsUndefined());
 
6752
  CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
 
6753
  global3->Set(v8_str("prop"), v8::Integer::New(-1));
 
6754
  global3->Set(v8_str("prop2"), v8::Integer::New(2));
 
6755
  env3->Exit();
 
6756
 
 
6757
  // Call getProp in env1, and it should return the value 1
 
6758
  {
 
6759
    Local<Value> get_prop = global1->Get(v8_str("getProp"));
 
6760
    CHECK(get_prop->IsFunction());
 
6761
    v8::TryCatch try_catch;
 
6762
    Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
 
6763
    CHECK(!try_catch.HasCaught());
 
6764
    CHECK_EQ(1, r->Int32Value());
 
6765
  }
 
6766
 
 
6767
  // Check that env3 is not accessible from env1
 
6768
  {
 
6769
    Local<Value> r = global3->Get(v8_str("prop2"));
 
6770
    CHECK(r->IsUndefined());
 
6771
  }
 
6772
 
 
6773
  env2.Dispose();
 
6774
  env3.Dispose();
 
6775
}
 
6776
 
 
6777
 
 
6778
TEST(DetachAndReattachGlobal) {
 
6779
  v8::HandleScope scope;
 
6780
  LocalContext env1;
 
6781
 
 
6782
  // Create second environment.
 
6783
  v8::Persistent<Context> env2 = Context::New();
 
6784
 
 
6785
  Local<Value> foo = v8_str("foo");
 
6786
 
 
6787
  // Set same security token for env1 and env2.
 
6788
  env1->SetSecurityToken(foo);
 
6789
  env2->SetSecurityToken(foo);
 
6790
 
 
6791
  // Create a property on the global object in env2.
 
6792
  {
 
6793
    v8::Context::Scope scope(env2);
 
6794
    env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
 
6795
  }
 
6796
 
 
6797
  // Create a reference to env2 global from env1 global.
 
6798
  env1->Global()->Set(v8_str("other"), env2->Global());
 
6799
 
 
6800
  // Check that we have access to other.p in env2 from env1.
 
6801
  Local<Value> result = CompileRun("other.p");
 
6802
  CHECK(result->IsInt32());
 
6803
  CHECK_EQ(42, result->Int32Value());
 
6804
 
 
6805
  // Hold on to global from env2 and detach global from env2.
 
6806
  Local<v8::Object> global2 = env2->Global();
 
6807
  env2->DetachGlobal();
 
6808
 
 
6809
  // Check that the global has been detached. No other.p property can
 
6810
  // be found.
 
6811
  result = CompileRun("other.p");
 
6812
  CHECK(result->IsUndefined());
 
6813
 
 
6814
  // Reuse global2 for env3.
 
6815
  v8::Persistent<Context> env3 =
 
6816
      Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
 
6817
  CHECK_EQ(global2, env3->Global());
 
6818
 
 
6819
  // Start by using the same security token for env3 as for env1 and env2.
 
6820
  env3->SetSecurityToken(foo);
 
6821
 
 
6822
  // Create a property on the global object in env3.
 
6823
  {
 
6824
    v8::Context::Scope scope(env3);
 
6825
    env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
 
6826
  }
 
6827
 
 
6828
  // Check that other.p is now the property in env3 and that we have access.
 
6829
  result = CompileRun("other.p");
 
6830
  CHECK(result->IsInt32());
 
6831
  CHECK_EQ(24, result->Int32Value());
 
6832
 
 
6833
  // Change security token for env3 to something different from env1 and env2.
 
6834
  env3->SetSecurityToken(v8_str("bar"));
 
6835
 
 
6836
  // Check that we do not have access to other.p in env1. |other| is now
 
6837
  // the global object for env3 which has a different security token,
 
6838
  // so access should be blocked.
 
6839
  result = CompileRun("other.p");
 
6840
  CHECK(result->IsUndefined());
 
6841
 
 
6842
  // Detach the global for env3 and reattach it to env2.
 
6843
  env3->DetachGlobal();
 
6844
  env2->ReattachGlobal(global2);
 
6845
 
 
6846
  // Check that we have access to other.p again in env1.  |other| is now
 
6847
  // the global object for env2 which has the same security token as env1.
 
6848
  result = CompileRun("other.p");
 
6849
  CHECK(result->IsInt32());
 
6850
  CHECK_EQ(42, result->Int32Value());
 
6851
 
 
6852
  env2.Dispose();
 
6853
  env3.Dispose();
 
6854
}
 
6855
 
 
6856
 
 
6857
static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
 
6858
static bool NamedAccessBlocker(Local<v8::Object> global,
 
6859
                               Local<Value> name,
 
6860
                               v8::AccessType type,
 
6861
                               Local<Value> data) {
 
6862
  return Context::GetCurrent()->Global()->Equals(global) ||
 
6863
      allowed_access_type[type];
 
6864
}
 
6865
 
 
6866
 
 
6867
static bool IndexedAccessBlocker(Local<v8::Object> global,
 
6868
                                 uint32_t key,
 
6869
                                 v8::AccessType type,
 
6870
                                 Local<Value> data) {
 
6871
  return Context::GetCurrent()->Global()->Equals(global) ||
 
6872
      allowed_access_type[type];
 
6873
}
 
6874
 
 
6875
 
 
6876
static int g_echo_value = -1;
 
6877
static v8::Handle<Value> EchoGetter(Local<String> name,
 
6878
                                    const AccessorInfo& info) {
 
6879
  return v8_num(g_echo_value);
 
6880
}
 
6881
 
 
6882
 
 
6883
static void EchoSetter(Local<String> name,
 
6884
                       Local<Value> value,
 
6885
                       const AccessorInfo&) {
 
6886
  if (value->IsNumber())
 
6887
    g_echo_value = value->Int32Value();
 
6888
}
 
6889
 
 
6890
 
 
6891
static v8::Handle<Value> UnreachableGetter(Local<String> name,
 
6892
                                           const AccessorInfo& info) {
 
6893
  CHECK(false);  // This function should not be called..
 
6894
  return v8::Undefined();
 
6895
}
 
6896
 
 
6897
 
 
6898
static void UnreachableSetter(Local<String>, Local<Value>,
 
6899
                              const AccessorInfo&) {
 
6900
  CHECK(false);  // This function should nto be called.
 
6901
}
 
6902
 
 
6903
 
 
6904
TEST(AccessControl) {
 
6905
  v8::HandleScope handle_scope;
 
6906
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
6907
 
 
6908
  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
 
6909
                                           IndexedAccessBlocker);
 
6910
 
 
6911
  // Add an accessor accessible by cross-domain JS code.
 
6912
  global_template->SetAccessor(
 
6913
      v8_str("accessible_prop"),
 
6914
      EchoGetter, EchoSetter,
 
6915
      v8::Handle<Value>(),
 
6916
      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
 
6917
 
 
6918
  // Add an accessor that is not accessible by cross-domain JS code.
 
6919
  global_template->SetAccessor(v8_str("blocked_prop"),
 
6920
                               UnreachableGetter, UnreachableSetter,
 
6921
                               v8::Handle<Value>(),
 
6922
                               v8::DEFAULT);
 
6923
 
 
6924
  // Create an environment
 
6925
  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
 
6926
  context0->Enter();
 
6927
 
 
6928
  v8::Handle<v8::Object> global0 = context0->Global();
 
6929
 
 
6930
  // Define a property with JS getter and setter.
 
6931
  CompileRun(
 
6932
      "function getter() { return 'getter'; };\n"
 
6933
      "function setter() { return 'setter'; }\n"
 
6934
      "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
 
6935
 
 
6936
  Local<Value> getter = global0->Get(v8_str("getter"));
 
6937
  Local<Value> setter = global0->Get(v8_str("setter"));
 
6938
 
 
6939
  // And define normal element.
 
6940
  global0->Set(239, v8_str("239"));
 
6941
 
 
6942
  // Define an element with JS getter and setter.
 
6943
  CompileRun(
 
6944
      "function el_getter() { return 'el_getter'; };\n"
 
6945
      "function el_setter() { return 'el_setter'; };\n"
 
6946
      "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
 
6947
 
 
6948
  Local<Value> el_getter = global0->Get(v8_str("el_getter"));
 
6949
  Local<Value> el_setter = global0->Get(v8_str("el_setter"));
 
6950
 
 
6951
  v8::HandleScope scope1;
 
6952
 
 
6953
  v8::Persistent<Context> context1 = Context::New();
 
6954
  context1->Enter();
 
6955
 
 
6956
  v8::Handle<v8::Object> global1 = context1->Global();
 
6957
  global1->Set(v8_str("other"), global0);
 
6958
 
 
6959
  // Access blocked property.
 
6960
  CompileRun("other.blocked_prop = 1");
 
6961
 
 
6962
  ExpectUndefined("other.blocked_prop");
 
6963
  ExpectUndefined(
 
6964
      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
 
6965
  ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
 
6966
 
 
6967
  // Enable ACCESS_HAS
 
6968
  allowed_access_type[v8::ACCESS_HAS] = true;
 
6969
  ExpectUndefined("other.blocked_prop");
 
6970
  // ... and now we can get the descriptor...
 
6971
  ExpectUndefined(
 
6972
      "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
 
6973
  // ... and enumerate the property.
 
6974
  ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
 
6975
  allowed_access_type[v8::ACCESS_HAS] = false;
 
6976
 
 
6977
  // Access blocked element.
 
6978
  CompileRun("other[239] = 1");
 
6979
 
 
6980
  ExpectUndefined("other[239]");
 
6981
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
 
6982
  ExpectFalse("propertyIsEnumerable.call(other, '239')");
 
6983
 
 
6984
  // Enable ACCESS_HAS
 
6985
  allowed_access_type[v8::ACCESS_HAS] = true;
 
6986
  ExpectUndefined("other[239]");
 
6987
  // ... and now we can get the descriptor...
 
6988
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
 
6989
  // ... and enumerate the property.
 
6990
  ExpectTrue("propertyIsEnumerable.call(other, '239')");
 
6991
  allowed_access_type[v8::ACCESS_HAS] = false;
 
6992
 
 
6993
  // Access a property with JS accessor.
 
6994
  CompileRun("other.js_accessor_p = 2");
 
6995
 
 
6996
  ExpectUndefined("other.js_accessor_p");
 
6997
  ExpectUndefined(
 
6998
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
 
6999
 
 
7000
  // Enable ACCESS_HAS.
 
7001
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7002
  ExpectUndefined("other.js_accessor_p");
 
7003
  ExpectUndefined(
 
7004
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
 
7005
  ExpectUndefined(
 
7006
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
 
7007
  ExpectUndefined(
 
7008
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
 
7009
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7010
 
 
7011
  // Enable both ACCESS_HAS and ACCESS_GET.
 
7012
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7013
  allowed_access_type[v8::ACCESS_GET] = true;
 
7014
 
 
7015
  ExpectString("other.js_accessor_p", "getter");
 
7016
  ExpectObject(
 
7017
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
 
7018
  ExpectUndefined(
 
7019
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
 
7020
  ExpectUndefined(
 
7021
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
 
7022
 
 
7023
  allowed_access_type[v8::ACCESS_GET] = false;
 
7024
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7025
 
 
7026
  // Enable both ACCESS_HAS and ACCESS_SET.
 
7027
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7028
  allowed_access_type[v8::ACCESS_SET] = true;
 
7029
 
 
7030
  ExpectUndefined("other.js_accessor_p");
 
7031
  ExpectUndefined(
 
7032
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
 
7033
  ExpectObject(
 
7034
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
 
7035
  ExpectUndefined(
 
7036
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
 
7037
 
 
7038
  allowed_access_type[v8::ACCESS_SET] = false;
 
7039
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7040
 
 
7041
  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
 
7042
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7043
  allowed_access_type[v8::ACCESS_GET] = true;
 
7044
  allowed_access_type[v8::ACCESS_SET] = true;
 
7045
 
 
7046
  ExpectString("other.js_accessor_p", "getter");
 
7047
  ExpectObject(
 
7048
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
 
7049
  ExpectObject(
 
7050
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
 
7051
  ExpectUndefined(
 
7052
      "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
 
7053
 
 
7054
  allowed_access_type[v8::ACCESS_SET] = false;
 
7055
  allowed_access_type[v8::ACCESS_GET] = false;
 
7056
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7057
 
 
7058
  // Access an element with JS accessor.
 
7059
  CompileRun("other[42] = 2");
 
7060
 
 
7061
  ExpectUndefined("other[42]");
 
7062
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
 
7063
 
 
7064
  // Enable ACCESS_HAS.
 
7065
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7066
  ExpectUndefined("other[42]");
 
7067
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
 
7068
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
 
7069
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
 
7070
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7071
 
 
7072
  // Enable both ACCESS_HAS and ACCESS_GET.
 
7073
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7074
  allowed_access_type[v8::ACCESS_GET] = true;
 
7075
 
 
7076
  ExpectString("other[42]", "el_getter");
 
7077
  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
 
7078
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
 
7079
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
 
7080
 
 
7081
  allowed_access_type[v8::ACCESS_GET] = false;
 
7082
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7083
 
 
7084
  // Enable both ACCESS_HAS and ACCESS_SET.
 
7085
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7086
  allowed_access_type[v8::ACCESS_SET] = true;
 
7087
 
 
7088
  ExpectUndefined("other[42]");
 
7089
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
 
7090
  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
 
7091
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
 
7092
 
 
7093
  allowed_access_type[v8::ACCESS_SET] = false;
 
7094
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7095
 
 
7096
  // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
 
7097
  allowed_access_type[v8::ACCESS_HAS] = true;
 
7098
  allowed_access_type[v8::ACCESS_GET] = true;
 
7099
  allowed_access_type[v8::ACCESS_SET] = true;
 
7100
 
 
7101
  ExpectString("other[42]", "el_getter");
 
7102
  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
 
7103
  ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
 
7104
  ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
 
7105
 
 
7106
  allowed_access_type[v8::ACCESS_SET] = false;
 
7107
  allowed_access_type[v8::ACCESS_GET] = false;
 
7108
  allowed_access_type[v8::ACCESS_HAS] = false;
 
7109
 
 
7110
  v8::Handle<Value> value;
 
7111
 
 
7112
  // Access accessible property
 
7113
  value = CompileRun("other.accessible_prop = 3");
 
7114
  CHECK(value->IsNumber());
 
7115
  CHECK_EQ(3, value->Int32Value());
 
7116
  CHECK_EQ(3, g_echo_value);
 
7117
 
 
7118
  value = CompileRun("other.accessible_prop");
 
7119
  CHECK(value->IsNumber());
 
7120
  CHECK_EQ(3, value->Int32Value());
 
7121
 
 
7122
  value = CompileRun(
 
7123
      "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
 
7124
  CHECK(value->IsNumber());
 
7125
  CHECK_EQ(3, value->Int32Value());
 
7126
 
 
7127
  value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
 
7128
  CHECK(value->IsTrue());
 
7129
 
 
7130
  // Enumeration doesn't enumerate accessors from inaccessible objects in
 
7131
  // the prototype chain even if the accessors are in themselves accessible.
 
7132
  value =
 
7133
      CompileRun("(function(){var obj = {'__proto__':other};"
 
7134
                 "for (var p in obj)"
 
7135
                 "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
 
7136
                 "     return false;"
 
7137
                 "   }"
 
7138
                 "return true;})()");
 
7139
  CHECK(value->IsTrue());
 
7140
 
 
7141
  context1->Exit();
 
7142
  context0->Exit();
 
7143
  context1.Dispose();
 
7144
  context0.Dispose();
 
7145
}
 
7146
 
 
7147
 
 
7148
TEST(AccessControlES5) {
 
7149
  v8::HandleScope handle_scope;
 
7150
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
7151
 
 
7152
  global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
 
7153
                                           IndexedAccessBlocker);
 
7154
 
 
7155
  // Add accessible accessor.
 
7156
  global_template->SetAccessor(
 
7157
      v8_str("accessible_prop"),
 
7158
      EchoGetter, EchoSetter,
 
7159
      v8::Handle<Value>(),
 
7160
      v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
 
7161
 
 
7162
 
 
7163
  // Add an accessor that is not accessible by cross-domain JS code.
 
7164
  global_template->SetAccessor(v8_str("blocked_prop"),
 
7165
                               UnreachableGetter, UnreachableSetter,
 
7166
                               v8::Handle<Value>(),
 
7167
                               v8::DEFAULT);
 
7168
 
 
7169
  // Create an environment
 
7170
  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
 
7171
  context0->Enter();
 
7172
 
 
7173
  v8::Handle<v8::Object> global0 = context0->Global();
 
7174
 
 
7175
  v8::Persistent<Context> context1 = Context::New();
 
7176
  context1->Enter();
 
7177
  v8::Handle<v8::Object> global1 = context1->Global();
 
7178
  global1->Set(v8_str("other"), global0);
 
7179
 
 
7180
  // Regression test for issue 1154.
 
7181
  ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
 
7182
 
 
7183
  ExpectUndefined("other.blocked_prop");
 
7184
 
 
7185
  // Regression test for issue 1027.
 
7186
  CompileRun("Object.defineProperty(\n"
 
7187
             "  other, 'blocked_prop', {configurable: false})");
 
7188
  ExpectUndefined("other.blocked_prop");
 
7189
  ExpectUndefined(
 
7190
      "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
 
7191
 
 
7192
  // Regression test for issue 1171.
 
7193
  ExpectTrue("Object.isExtensible(other)");
 
7194
  CompileRun("Object.preventExtensions(other)");
 
7195
  ExpectTrue("Object.isExtensible(other)");
 
7196
 
 
7197
  // Object.seal and Object.freeze.
 
7198
  CompileRun("Object.freeze(other)");
 
7199
  ExpectTrue("Object.isExtensible(other)");
 
7200
 
 
7201
  CompileRun("Object.seal(other)");
 
7202
  ExpectTrue("Object.isExtensible(other)");
 
7203
 
 
7204
  // Regression test for issue 1250.
 
7205
  // Make sure that we can set the accessible accessors value using normal
 
7206
  // assignment.
 
7207
  CompileRun("other.accessible_prop = 42");
 
7208
  CHECK_EQ(42, g_echo_value);
 
7209
 
 
7210
  v8::Handle<Value> value;
 
7211
  // We follow Safari in ignoring assignments to host object accessors.
 
7212
  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
 
7213
  value = CompileRun("other.accessible_prop == 42");
 
7214
  CHECK(value->IsTrue());
 
7215
}
 
7216
 
 
7217
 
 
7218
static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
 
7219
                                            Local<Value> name,
 
7220
                                            v8::AccessType type,
 
7221
                                            Local<Value> data) {
 
7222
  return false;
 
7223
}
 
7224
 
 
7225
 
 
7226
static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
 
7227
                                              uint32_t key,
 
7228
                                              v8::AccessType type,
 
7229
                                              Local<Value> data) {
 
7230
  return false;
 
7231
}
 
7232
 
 
7233
 
 
7234
THREADED_TEST(AccessControlGetOwnPropertyNames) {
 
7235
  v8::HandleScope handle_scope;
 
7236
  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
 
7237
 
 
7238
  obj_template->Set(v8_str("x"), v8::Integer::New(42));
 
7239
  obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
 
7240
                                        GetOwnPropertyNamesIndexedBlocker);
 
7241
 
 
7242
  // Create an environment
 
7243
  v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
 
7244
  context0->Enter();
 
7245
 
 
7246
  v8::Handle<v8::Object> global0 = context0->Global();
 
7247
 
 
7248
  v8::HandleScope scope1;
 
7249
 
 
7250
  v8::Persistent<Context> context1 = Context::New();
 
7251
  context1->Enter();
 
7252
 
 
7253
  v8::Handle<v8::Object> global1 = context1->Global();
 
7254
  global1->Set(v8_str("other"), global0);
 
7255
  global1->Set(v8_str("object"), obj_template->NewInstance());
 
7256
 
 
7257
  v8::Handle<Value> value;
 
7258
 
 
7259
  // Attempt to get the property names of the other global object and
 
7260
  // of an object that requires access checks.  Accessing the other
 
7261
  // global object should be blocked by access checks on the global
 
7262
  // proxy object.  Accessing the object that requires access checks
 
7263
  // is blocked by the access checks on the object itself.
 
7264
  value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
 
7265
  CHECK(value->IsTrue());
 
7266
 
 
7267
  value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
 
7268
  CHECK(value->IsTrue());
 
7269
 
 
7270
  context1->Exit();
 
7271
  context0->Exit();
 
7272
  context1.Dispose();
 
7273
  context0.Dispose();
 
7274
}
 
7275
 
 
7276
 
 
7277
static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
 
7278
  v8::Handle<v8::Array> result = v8::Array::New(1);
 
7279
  result->Set(0, v8_str("x"));
 
7280
  return result;
 
7281
}
 
7282
 
 
7283
 
 
7284
THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
 
7285
  v8::HandleScope handle_scope;
 
7286
  v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
 
7287
 
 
7288
  obj_template->Set(v8_str("x"), v8::Integer::New(42));
 
7289
  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
 
7290
                                        NamedPropertyEnumerator);
 
7291
 
 
7292
  LocalContext context;
 
7293
  v8::Handle<v8::Object> global = context->Global();
 
7294
  global->Set(v8_str("object"), obj_template->NewInstance());
 
7295
 
 
7296
  v8::Handle<Value> value =
 
7297
      CompileRun("Object.getOwnPropertyNames(object).join(',')");
 
7298
  CHECK_EQ(v8_str("x"), value);
 
7299
}
 
7300
 
 
7301
 
 
7302
static v8::Handle<Value> ConstTenGetter(Local<String> name,
 
7303
                                        const AccessorInfo& info) {
 
7304
  return v8_num(10);
 
7305
}
 
7306
 
 
7307
 
 
7308
THREADED_TEST(CrossDomainAccessors) {
 
7309
  v8::HandleScope handle_scope;
 
7310
 
 
7311
  v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
 
7312
 
 
7313
  v8::Handle<v8::ObjectTemplate> global_template =
 
7314
      func_template->InstanceTemplate();
 
7315
 
 
7316
  v8::Handle<v8::ObjectTemplate> proto_template =
 
7317
      func_template->PrototypeTemplate();
 
7318
 
 
7319
  // Add an accessor to proto that's accessible by cross-domain JS code.
 
7320
  proto_template->SetAccessor(v8_str("accessible"),
 
7321
                              ConstTenGetter, 0,
 
7322
                              v8::Handle<Value>(),
 
7323
                              v8::ALL_CAN_READ);
 
7324
 
 
7325
  // Add an accessor that is not accessible by cross-domain JS code.
 
7326
  global_template->SetAccessor(v8_str("unreachable"),
 
7327
                               UnreachableGetter, 0,
 
7328
                               v8::Handle<Value>(),
 
7329
                               v8::DEFAULT);
 
7330
 
 
7331
  v8::Persistent<Context> context0 = Context::New(NULL, global_template);
 
7332
  context0->Enter();
 
7333
 
 
7334
  Local<v8::Object> global = context0->Global();
 
7335
  // Add a normal property that shadows 'accessible'
 
7336
  global->Set(v8_str("accessible"), v8_num(11));
 
7337
 
 
7338
  // Enter a new context.
 
7339
  v8::HandleScope scope1;
 
7340
  v8::Persistent<Context> context1 = Context::New();
 
7341
  context1->Enter();
 
7342
 
 
7343
  v8::Handle<v8::Object> global1 = context1->Global();
 
7344
  global1->Set(v8_str("other"), global);
 
7345
 
 
7346
  // Should return 10, instead of 11
 
7347
  v8::Handle<Value> value = v8_compile("other.accessible")->Run();
 
7348
  CHECK(value->IsNumber());
 
7349
  CHECK_EQ(10, value->Int32Value());
 
7350
 
 
7351
  value = v8_compile("other.unreachable")->Run();
 
7352
  CHECK(value->IsUndefined());
 
7353
 
 
7354
  context1->Exit();
 
7355
  context0->Exit();
 
7356
  context1.Dispose();
 
7357
  context0.Dispose();
 
7358
}
 
7359
 
 
7360
 
 
7361
static int named_access_count = 0;
 
7362
static int indexed_access_count = 0;
 
7363
 
 
7364
static bool NamedAccessCounter(Local<v8::Object> global,
 
7365
                               Local<Value> name,
 
7366
                               v8::AccessType type,
 
7367
                               Local<Value> data) {
 
7368
  named_access_count++;
 
7369
  return true;
 
7370
}
 
7371
 
 
7372
 
 
7373
static bool IndexedAccessCounter(Local<v8::Object> global,
 
7374
                                 uint32_t key,
 
7375
                                 v8::AccessType type,
 
7376
                                 Local<Value> data) {
 
7377
  indexed_access_count++;
 
7378
  return true;
 
7379
}
 
7380
 
 
7381
 
 
7382
// This one is too easily disturbed by other tests.
 
7383
TEST(AccessControlIC) {
 
7384
  named_access_count = 0;
 
7385
  indexed_access_count = 0;
 
7386
 
 
7387
  v8::HandleScope handle_scope;
 
7388
 
 
7389
  // Create an environment.
 
7390
  v8::Persistent<Context> context0 = Context::New();
 
7391
  context0->Enter();
 
7392
 
 
7393
  // Create an object that requires access-check functions to be
 
7394
  // called for cross-domain access.
 
7395
  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
 
7396
  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
 
7397
                                           IndexedAccessCounter);
 
7398
  Local<v8::Object> object = object_template->NewInstance();
 
7399
 
 
7400
  v8::HandleScope scope1;
 
7401
 
 
7402
  // Create another environment.
 
7403
  v8::Persistent<Context> context1 = Context::New();
 
7404
  context1->Enter();
 
7405
 
 
7406
  // Make easy access to the object from the other environment.
 
7407
  v8::Handle<v8::Object> global1 = context1->Global();
 
7408
  global1->Set(v8_str("obj"), object);
 
7409
 
 
7410
  v8::Handle<Value> value;
 
7411
 
 
7412
  // Check that the named access-control function is called every time.
 
7413
  CompileRun("function testProp(obj) {"
 
7414
             "  for (var i = 0; i < 10; i++) obj.prop = 1;"
 
7415
             "  for (var j = 0; j < 10; j++) obj.prop;"
 
7416
             "  return obj.prop"
 
7417
             "}");
 
7418
  value = CompileRun("testProp(obj)");
 
7419
  CHECK(value->IsNumber());
 
7420
  CHECK_EQ(1, value->Int32Value());
 
7421
  CHECK_EQ(21, named_access_count);
 
7422
 
 
7423
  // Check that the named access-control function is called every time.
 
7424
  CompileRun("var p = 'prop';"
 
7425
             "function testKeyed(obj) {"
 
7426
             "  for (var i = 0; i < 10; i++) obj[p] = 1;"
 
7427
             "  for (var j = 0; j < 10; j++) obj[p];"
 
7428
             "  return obj[p];"
 
7429
             "}");
 
7430
  // Use obj which requires access checks.  No inline caching is used
 
7431
  // in that case.
 
7432
  value = CompileRun("testKeyed(obj)");
 
7433
  CHECK(value->IsNumber());
 
7434
  CHECK_EQ(1, value->Int32Value());
 
7435
  CHECK_EQ(42, named_access_count);
 
7436
  // Force the inline caches into generic state and try again.
 
7437
  CompileRun("testKeyed({ a: 0 })");
 
7438
  CompileRun("testKeyed({ b: 0 })");
 
7439
  value = CompileRun("testKeyed(obj)");
 
7440
  CHECK(value->IsNumber());
 
7441
  CHECK_EQ(1, value->Int32Value());
 
7442
  CHECK_EQ(63, named_access_count);
 
7443
 
 
7444
  // Check that the indexed access-control function is called every time.
 
7445
  CompileRun("function testIndexed(obj) {"
 
7446
             "  for (var i = 0; i < 10; i++) obj[0] = 1;"
 
7447
             "  for (var j = 0; j < 10; j++) obj[0];"
 
7448
             "  return obj[0]"
 
7449
             "}");
 
7450
  value = CompileRun("testIndexed(obj)");
 
7451
  CHECK(value->IsNumber());
 
7452
  CHECK_EQ(1, value->Int32Value());
 
7453
  CHECK_EQ(21, indexed_access_count);
 
7454
  // Force the inline caches into generic state.
 
7455
  CompileRun("testIndexed(new Array(1))");
 
7456
  // Test that the indexed access check is called.
 
7457
  value = CompileRun("testIndexed(obj)");
 
7458
  CHECK(value->IsNumber());
 
7459
  CHECK_EQ(1, value->Int32Value());
 
7460
  CHECK_EQ(42, indexed_access_count);
 
7461
 
 
7462
  // Check that the named access check is called when invoking
 
7463
  // functions on an object that requires access checks.
 
7464
  CompileRun("obj.f = function() {}");
 
7465
  CompileRun("function testCallNormal(obj) {"
 
7466
             "  for (var i = 0; i < 10; i++) obj.f();"
 
7467
             "}");
 
7468
  CompileRun("testCallNormal(obj)");
 
7469
  CHECK_EQ(74, named_access_count);
 
7470
 
 
7471
  // Force obj into slow case.
 
7472
  value = CompileRun("delete obj.prop");
 
7473
  CHECK(value->BooleanValue());
 
7474
  // Force inline caches into dictionary probing mode.
 
7475
  CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
 
7476
  // Test that the named access check is called.
 
7477
  value = CompileRun("testProp(obj);");
 
7478
  CHECK(value->IsNumber());
 
7479
  CHECK_EQ(1, value->Int32Value());
 
7480
  CHECK_EQ(96, named_access_count);
 
7481
 
 
7482
  // Force the call inline cache into dictionary probing mode.
 
7483
  CompileRun("o.f = function() {}; testCallNormal(o)");
 
7484
  // Test that the named access check is still called for each
 
7485
  // invocation of the function.
 
7486
  value = CompileRun("testCallNormal(obj)");
 
7487
  CHECK_EQ(106, named_access_count);
 
7488
 
 
7489
  context1->Exit();
 
7490
  context0->Exit();
 
7491
  context1.Dispose();
 
7492
  context0.Dispose();
 
7493
}
 
7494
 
 
7495
 
 
7496
static bool NamedAccessFlatten(Local<v8::Object> global,
 
7497
                               Local<Value> name,
 
7498
                               v8::AccessType type,
 
7499
                               Local<Value> data) {
 
7500
  char buf[100];
 
7501
  int len;
 
7502
 
 
7503
  CHECK(name->IsString());
 
7504
 
 
7505
  memset(buf, 0x1, sizeof(buf));
 
7506
  len = name.As<String>()->WriteAscii(buf);
 
7507
  CHECK_EQ(4, len);
 
7508
 
 
7509
  uint16_t buf2[100];
 
7510
 
 
7511
  memset(buf, 0x1, sizeof(buf));
 
7512
  len = name.As<String>()->Write(buf2);
 
7513
  CHECK_EQ(4, len);
 
7514
 
 
7515
  return true;
 
7516
}
 
7517
 
 
7518
 
 
7519
static bool IndexedAccessFlatten(Local<v8::Object> global,
 
7520
                                 uint32_t key,
 
7521
                                 v8::AccessType type,
 
7522
                                 Local<Value> data) {
 
7523
  return true;
 
7524
}
 
7525
 
 
7526
 
 
7527
// Regression test.  In access checks, operations that may cause
 
7528
// garbage collection are not allowed.  It used to be the case that
 
7529
// using the Write operation on a string could cause a garbage
 
7530
// collection due to flattening of the string.  This is no longer the
 
7531
// case.
 
7532
THREADED_TEST(AccessControlFlatten) {
 
7533
  named_access_count = 0;
 
7534
  indexed_access_count = 0;
 
7535
 
 
7536
  v8::HandleScope handle_scope;
 
7537
 
 
7538
  // Create an environment.
 
7539
  v8::Persistent<Context> context0 = Context::New();
 
7540
  context0->Enter();
 
7541
 
 
7542
  // Create an object that requires access-check functions to be
 
7543
  // called for cross-domain access.
 
7544
  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
 
7545
  object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
 
7546
                                           IndexedAccessFlatten);
 
7547
  Local<v8::Object> object = object_template->NewInstance();
 
7548
 
 
7549
  v8::HandleScope scope1;
 
7550
 
 
7551
  // Create another environment.
 
7552
  v8::Persistent<Context> context1 = Context::New();
 
7553
  context1->Enter();
 
7554
 
 
7555
  // Make easy access to the object from the other environment.
 
7556
  v8::Handle<v8::Object> global1 = context1->Global();
 
7557
  global1->Set(v8_str("obj"), object);
 
7558
 
 
7559
  v8::Handle<Value> value;
 
7560
 
 
7561
  value = v8_compile("var p = 'as' + 'df';")->Run();
 
7562
  value = v8_compile("obj[p];")->Run();
 
7563
 
 
7564
  context1->Exit();
 
7565
  context0->Exit();
 
7566
  context1.Dispose();
 
7567
  context0.Dispose();
 
7568
}
 
7569
 
 
7570
 
 
7571
static v8::Handle<Value> AccessControlNamedGetter(
 
7572
    Local<String>, const AccessorInfo&) {
 
7573
  return v8::Integer::New(42);
 
7574
}
 
7575
 
 
7576
 
 
7577
static v8::Handle<Value> AccessControlNamedSetter(
 
7578
    Local<String>, Local<Value> value, const AccessorInfo&) {
 
7579
  return value;
 
7580
}
 
7581
 
 
7582
 
 
7583
static v8::Handle<Value> AccessControlIndexedGetter(
 
7584
      uint32_t index,
 
7585
      const AccessorInfo& info) {
 
7586
  return v8_num(42);
 
7587
}
 
7588
 
 
7589
 
 
7590
static v8::Handle<Value> AccessControlIndexedSetter(
 
7591
    uint32_t, Local<Value> value, const AccessorInfo&) {
 
7592
  return value;
 
7593
}
 
7594
 
 
7595
 
 
7596
THREADED_TEST(AccessControlInterceptorIC) {
 
7597
  named_access_count = 0;
 
7598
  indexed_access_count = 0;
 
7599
 
 
7600
  v8::HandleScope handle_scope;
 
7601
 
 
7602
  // Create an environment.
 
7603
  v8::Persistent<Context> context0 = Context::New();
 
7604
  context0->Enter();
 
7605
 
 
7606
  // Create an object that requires access-check functions to be
 
7607
  // called for cross-domain access.  The object also has interceptors
 
7608
  // interceptor.
 
7609
  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
 
7610
  object_template->SetAccessCheckCallbacks(NamedAccessCounter,
 
7611
                                           IndexedAccessCounter);
 
7612
  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
 
7613
                                           AccessControlNamedSetter);
 
7614
  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
 
7615
                                             AccessControlIndexedSetter);
 
7616
  Local<v8::Object> object = object_template->NewInstance();
 
7617
 
 
7618
  v8::HandleScope scope1;
 
7619
 
 
7620
  // Create another environment.
 
7621
  v8::Persistent<Context> context1 = Context::New();
 
7622
  context1->Enter();
 
7623
 
 
7624
  // Make easy access to the object from the other environment.
 
7625
  v8::Handle<v8::Object> global1 = context1->Global();
 
7626
  global1->Set(v8_str("obj"), object);
 
7627
 
 
7628
  v8::Handle<Value> value;
 
7629
 
 
7630
  // Check that the named access-control function is called every time
 
7631
  // eventhough there is an interceptor on the object.
 
7632
  value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
 
7633
  value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
 
7634
                     "obj.x")->Run();
 
7635
  CHECK(value->IsNumber());
 
7636
  CHECK_EQ(42, value->Int32Value());
 
7637
  CHECK_EQ(21, named_access_count);
 
7638
 
 
7639
  value = v8_compile("var p = 'x';")->Run();
 
7640
  value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
 
7641
  value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
 
7642
                     "obj[p]")->Run();
 
7643
  CHECK(value->IsNumber());
 
7644
  CHECK_EQ(42, value->Int32Value());
 
7645
  CHECK_EQ(42, named_access_count);
 
7646
 
 
7647
  // Check that the indexed access-control function is called every
 
7648
  // time eventhough there is an interceptor on the object.
 
7649
  value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
 
7650
  value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
 
7651
                     "obj[0]")->Run();
 
7652
  CHECK(value->IsNumber());
 
7653
  CHECK_EQ(42, value->Int32Value());
 
7654
  CHECK_EQ(21, indexed_access_count);
 
7655
 
 
7656
  context1->Exit();
 
7657
  context0->Exit();
 
7658
  context1.Dispose();
 
7659
  context0.Dispose();
 
7660
}
 
7661
 
 
7662
 
 
7663
THREADED_TEST(Version) {
 
7664
  v8::V8::GetVersion();
 
7665
}
 
7666
 
 
7667
 
 
7668
static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
 
7669
  ApiTestFuzzer::Fuzz();
 
7670
  return v8_num(12);
 
7671
}
 
7672
 
 
7673
 
 
7674
THREADED_TEST(InstanceProperties) {
 
7675
  v8::HandleScope handle_scope;
 
7676
  LocalContext context;
 
7677
 
 
7678
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
7679
  Local<ObjectTemplate> instance = t->InstanceTemplate();
 
7680
 
 
7681
  instance->Set(v8_str("x"), v8_num(42));
 
7682
  instance->Set(v8_str("f"),
 
7683
                v8::FunctionTemplate::New(InstanceFunctionCallback));
 
7684
 
 
7685
  Local<Value> o = t->GetFunction()->NewInstance();
 
7686
 
 
7687
  context->Global()->Set(v8_str("i"), o);
 
7688
  Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
 
7689
  CHECK_EQ(42, value->Int32Value());
 
7690
 
 
7691
  value = Script::Compile(v8_str("i.f()"))->Run();
 
7692
  CHECK_EQ(12, value->Int32Value());
 
7693
}
 
7694
 
 
7695
 
 
7696
static v8::Handle<Value>
 
7697
GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
 
7698
  ApiTestFuzzer::Fuzz();
 
7699
  return v8::Handle<Value>();
 
7700
}
 
7701
 
 
7702
 
 
7703
THREADED_TEST(GlobalObjectInstanceProperties) {
 
7704
  v8::HandleScope handle_scope;
 
7705
 
 
7706
  Local<Value> global_object;
 
7707
 
 
7708
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
7709
  t->InstanceTemplate()->SetNamedPropertyHandler(
 
7710
      GlobalObjectInstancePropertiesGet);
 
7711
  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
 
7712
  instance_template->Set(v8_str("x"), v8_num(42));
 
7713
  instance_template->Set(v8_str("f"),
 
7714
                         v8::FunctionTemplate::New(InstanceFunctionCallback));
 
7715
 
 
7716
  // The script to check how Crankshaft compiles missing global function
 
7717
  // invocations.  function g is not defined and should throw on call.
 
7718
  const char* script =
 
7719
      "function wrapper(call) {"
 
7720
      "  var x = 0, y = 1;"
 
7721
      "  for (var i = 0; i < 1000; i++) {"
 
7722
      "    x += i * 100;"
 
7723
      "    y += i * 100;"
 
7724
      "  }"
 
7725
      "  if (call) g();"
 
7726
      "}"
 
7727
      "for (var i = 0; i < 17; i++) wrapper(false);"
 
7728
      "var thrown = 0;"
 
7729
      "try { wrapper(true); } catch (e) { thrown = 1; };"
 
7730
      "thrown";
 
7731
 
 
7732
  {
 
7733
    LocalContext env(NULL, instance_template);
 
7734
    // Hold on to the global object so it can be used again in another
 
7735
    // environment initialization.
 
7736
    global_object = env->Global();
 
7737
 
 
7738
    Local<Value> value = Script::Compile(v8_str("x"))->Run();
 
7739
    CHECK_EQ(42, value->Int32Value());
 
7740
    value = Script::Compile(v8_str("f()"))->Run();
 
7741
    CHECK_EQ(12, value->Int32Value());
 
7742
    value = Script::Compile(v8_str(script))->Run();
 
7743
    CHECK_EQ(1, value->Int32Value());
 
7744
  }
 
7745
 
 
7746
  {
 
7747
    // Create new environment reusing the global object.
 
7748
    LocalContext env(NULL, instance_template, global_object);
 
7749
    Local<Value> value = Script::Compile(v8_str("x"))->Run();
 
7750
    CHECK_EQ(42, value->Int32Value());
 
7751
    value = Script::Compile(v8_str("f()"))->Run();
 
7752
    CHECK_EQ(12, value->Int32Value());
 
7753
    value = Script::Compile(v8_str(script))->Run();
 
7754
    CHECK_EQ(1, value->Int32Value());
 
7755
  }
 
7756
}
 
7757
 
 
7758
 
 
7759
THREADED_TEST(CallKnownGlobalReceiver) {
 
7760
  v8::HandleScope handle_scope;
 
7761
 
 
7762
  Local<Value> global_object;
 
7763
 
 
7764
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
7765
  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
 
7766
 
 
7767
  // The script to check that we leave global object not
 
7768
  // global object proxy on stack when we deoptimize from inside
 
7769
  // arguments evaluation.
 
7770
  // To provoke error we need to both force deoptimization
 
7771
  // from arguments evaluation and to force CallIC to take
 
7772
  // CallIC_Miss code path that can't cope with global proxy.
 
7773
  const char* script =
 
7774
      "function bar(x, y) { try { } finally { } }"
 
7775
      "function baz(x) { try { } finally { } }"
 
7776
      "function bom(x) { try { } finally { } }"
 
7777
      "function foo(x) { bar([x], bom(2)); }"
 
7778
      "for (var i = 0; i < 10000; i++) foo(1);"
 
7779
      "foo";
 
7780
 
 
7781
  Local<Value> foo;
 
7782
  {
 
7783
    LocalContext env(NULL, instance_template);
 
7784
    // Hold on to the global object so it can be used again in another
 
7785
    // environment initialization.
 
7786
    global_object = env->Global();
 
7787
    foo = Script::Compile(v8_str(script))->Run();
 
7788
  }
 
7789
 
 
7790
  {
 
7791
    // Create new environment reusing the global object.
 
7792
    LocalContext env(NULL, instance_template, global_object);
 
7793
    env->Global()->Set(v8_str("foo"), foo);
 
7794
    Script::Compile(v8_str("foo()"))->Run();
 
7795
  }
 
7796
}
 
7797
 
 
7798
 
 
7799
static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
 
7800
  ApiTestFuzzer::Fuzz();
 
7801
  return v8_num(42);
 
7802
}
 
7803
 
 
7804
 
 
7805
static int shadow_y;
 
7806
static int shadow_y_setter_call_count;
 
7807
static int shadow_y_getter_call_count;
 
7808
 
 
7809
 
 
7810
static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
 
7811
  shadow_y_setter_call_count++;
 
7812
  shadow_y = 42;
 
7813
}
 
7814
 
 
7815
 
 
7816
static v8::Handle<Value> ShadowYGetter(Local<String> name,
 
7817
                                       const AccessorInfo& info) {
 
7818
  ApiTestFuzzer::Fuzz();
 
7819
  shadow_y_getter_call_count++;
 
7820
  return v8_num(shadow_y);
 
7821
}
 
7822
 
 
7823
 
 
7824
static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
 
7825
                                          const AccessorInfo& info) {
 
7826
  return v8::Handle<Value>();
 
7827
}
 
7828
 
 
7829
 
 
7830
static v8::Handle<Value> ShadowNamedGet(Local<String> key,
 
7831
                                        const AccessorInfo&) {
 
7832
  return v8::Handle<Value>();
 
7833
}
 
7834
 
 
7835
 
 
7836
THREADED_TEST(ShadowObject) {
 
7837
  shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
 
7838
  v8::HandleScope handle_scope;
 
7839
 
 
7840
  Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
7841
  LocalContext context(NULL, global_template);
 
7842
 
 
7843
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
7844
  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
 
7845
  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
 
7846
  Local<ObjectTemplate> proto = t->PrototypeTemplate();
 
7847
  Local<ObjectTemplate> instance = t->InstanceTemplate();
 
7848
 
 
7849
  // Only allow calls of f on instances of t.
 
7850
  Local<v8::Signature> signature = v8::Signature::New(t);
 
7851
  proto->Set(v8_str("f"),
 
7852
             v8::FunctionTemplate::New(ShadowFunctionCallback,
 
7853
                                       Local<Value>(),
 
7854
                                       signature));
 
7855
  proto->Set(v8_str("x"), v8_num(12));
 
7856
 
 
7857
  instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
 
7858
 
 
7859
  Local<Value> o = t->GetFunction()->NewInstance();
 
7860
  context->Global()->Set(v8_str("__proto__"), o);
 
7861
 
 
7862
  Local<Value> value =
 
7863
      Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
 
7864
  CHECK(value->IsBoolean());
 
7865
  CHECK(!value->BooleanValue());
 
7866
 
 
7867
  value = Script::Compile(v8_str("x"))->Run();
 
7868
  CHECK_EQ(12, value->Int32Value());
 
7869
 
 
7870
  value = Script::Compile(v8_str("f()"))->Run();
 
7871
  CHECK_EQ(42, value->Int32Value());
 
7872
 
 
7873
  Script::Compile(v8_str("y = 43"))->Run();
 
7874
  CHECK_EQ(1, shadow_y_setter_call_count);
 
7875
  value = Script::Compile(v8_str("y"))->Run();
 
7876
  CHECK_EQ(1, shadow_y_getter_call_count);
 
7877
  CHECK_EQ(42, value->Int32Value());
 
7878
}
 
7879
 
 
7880
 
 
7881
THREADED_TEST(HiddenPrototype) {
 
7882
  v8::HandleScope handle_scope;
 
7883
  LocalContext context;
 
7884
 
 
7885
  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
 
7886
  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
 
7887
  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
 
7888
  t1->SetHiddenPrototype(true);
 
7889
  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
 
7890
  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
 
7891
  t2->SetHiddenPrototype(true);
 
7892
  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
 
7893
  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
 
7894
  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
 
7895
 
 
7896
  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
 
7897
  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
 
7898
  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
 
7899
  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
 
7900
 
 
7901
  // Setting the prototype on an object skips hidden prototypes.
 
7902
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7903
  o0->Set(v8_str("__proto__"), o1);
 
7904
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7905
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7906
  o0->Set(v8_str("__proto__"), o2);
 
7907
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7908
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7909
  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
 
7910
  o0->Set(v8_str("__proto__"), o3);
 
7911
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7912
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7913
  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
 
7914
  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
 
7915
 
 
7916
  // Getting the prototype of o0 should get the first visible one
 
7917
  // which is o3.  Therefore, z should not be defined on the prototype
 
7918
  // object.
 
7919
  Local<Value> proto = o0->Get(v8_str("__proto__"));
 
7920
  CHECK(proto->IsObject());
 
7921
  CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
 
7922
}
 
7923
 
 
7924
 
 
7925
THREADED_TEST(SetPrototype) {
 
7926
  v8::HandleScope handle_scope;
 
7927
  LocalContext context;
 
7928
 
 
7929
  Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
 
7930
  t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
 
7931
  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
 
7932
  t1->SetHiddenPrototype(true);
 
7933
  t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
 
7934
  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
 
7935
  t2->SetHiddenPrototype(true);
 
7936
  t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
 
7937
  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
 
7938
  t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
 
7939
 
 
7940
  Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
 
7941
  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
 
7942
  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
 
7943
  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
 
7944
 
 
7945
  // Setting the prototype on an object does not skip hidden prototypes.
 
7946
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7947
  CHECK(o0->SetPrototype(o1));
 
7948
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7949
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7950
  CHECK(o1->SetPrototype(o2));
 
7951
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7952
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7953
  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
 
7954
  CHECK(o2->SetPrototype(o3));
 
7955
  CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
 
7956
  CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
 
7957
  CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
 
7958
  CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
 
7959
 
 
7960
  // Getting the prototype of o0 should get the first visible one
 
7961
  // which is o3.  Therefore, z should not be defined on the prototype
 
7962
  // object.
 
7963
  Local<Value> proto = o0->Get(v8_str("__proto__"));
 
7964
  CHECK(proto->IsObject());
 
7965
  CHECK_EQ(proto.As<v8::Object>(), o3);
 
7966
 
 
7967
  // However, Object::GetPrototype ignores hidden prototype.
 
7968
  Local<Value> proto0 = o0->GetPrototype();
 
7969
  CHECK(proto0->IsObject());
 
7970
  CHECK_EQ(proto0.As<v8::Object>(), o1);
 
7971
 
 
7972
  Local<Value> proto1 = o1->GetPrototype();
 
7973
  CHECK(proto1->IsObject());
 
7974
  CHECK_EQ(proto1.As<v8::Object>(), o2);
 
7975
 
 
7976
  Local<Value> proto2 = o2->GetPrototype();
 
7977
  CHECK(proto2->IsObject());
 
7978
  CHECK_EQ(proto2.As<v8::Object>(), o3);
 
7979
}
 
7980
 
 
7981
 
 
7982
// Getting property names of an object with a prototype chain that
 
7983
// triggers dictionary elements in GetLocalPropertyNames() shouldn't
 
7984
// crash the runtime.
 
7985
THREADED_TEST(Regress91517) {
 
7986
  i::FLAG_allow_natives_syntax = true;
 
7987
  v8::HandleScope handle_scope;
 
7988
  LocalContext context;
 
7989
 
 
7990
  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
 
7991
  t1->SetHiddenPrototype(true);
 
7992
  t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
 
7993
  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
 
7994
  t2->SetHiddenPrototype(true);
 
7995
  t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
 
7996
  t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
 
7997
  t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
 
7998
  Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
 
7999
  t3->SetHiddenPrototype(true);
 
8000
  t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
 
8001
  Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
 
8002
  t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
 
8003
 
 
8004
  // Force dictionary-based properties.
 
8005
  i::ScopedVector<char> name_buf(1024);
 
8006
  for (int i = 1; i <= 1000; i++) {
 
8007
    i::OS::SNPrintF(name_buf, "sdf%d", i);
 
8008
    t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
 
8009
  }
 
8010
 
 
8011
  Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
 
8012
  Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
 
8013
  Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
 
8014
  Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
 
8015
 
 
8016
  // Create prototype chain of hidden prototypes.
 
8017
  CHECK(o4->SetPrototype(o3));
 
8018
  CHECK(o3->SetPrototype(o2));
 
8019
  CHECK(o2->SetPrototype(o1));
 
8020
 
 
8021
  // Call the runtime version of GetLocalPropertyNames() on the natively
 
8022
  // created object through JavaScript.
 
8023
  context->Global()->Set(v8_str("obj"), o4);
 
8024
  CompileRun("var names = %GetLocalPropertyNames(obj);");
 
8025
 
 
8026
  ExpectInt32("names.length", 1006);
 
8027
  ExpectTrue("names.indexOf(\"baz\") >= 0");
 
8028
  ExpectTrue("names.indexOf(\"boo\") >= 0");
 
8029
  ExpectTrue("names.indexOf(\"foo\") >= 0");
 
8030
  ExpectTrue("names.indexOf(\"fuz1\") >= 0");
 
8031
  ExpectTrue("names.indexOf(\"fuz2\") >= 0");
 
8032
  ExpectFalse("names[1005] == undefined");
 
8033
}
 
8034
 
 
8035
 
 
8036
THREADED_TEST(FunctionReadOnlyPrototype) {
 
8037
  v8::HandleScope handle_scope;
 
8038
  LocalContext context;
 
8039
 
 
8040
  Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
 
8041
  t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
 
8042
  t1->ReadOnlyPrototype();
 
8043
  context->Global()->Set(v8_str("func1"), t1->GetFunction());
 
8044
  // Configured value of ReadOnly flag.
 
8045
  CHECK(CompileRun(
 
8046
      "(function() {"
 
8047
      "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
 
8048
      "  return (descriptor['writable'] == false);"
 
8049
      "})()")->BooleanValue());
 
8050
  CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
 
8051
  CHECK_EQ(42,
 
8052
           CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
 
8053
 
 
8054
  Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
 
8055
  t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
 
8056
  context->Global()->Set(v8_str("func2"), t2->GetFunction());
 
8057
  // Default value of ReadOnly flag.
 
8058
  CHECK(CompileRun(
 
8059
      "(function() {"
 
8060
      "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
 
8061
      "  return (descriptor['writable'] == true);"
 
8062
      "})()")->BooleanValue());
 
8063
  CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
 
8064
}
 
8065
 
 
8066
 
 
8067
THREADED_TEST(SetPrototypeThrows) {
 
8068
  v8::HandleScope handle_scope;
 
8069
  LocalContext context;
 
8070
 
 
8071
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
8072
 
 
8073
  Local<v8::Object> o0 = t->GetFunction()->NewInstance();
 
8074
  Local<v8::Object> o1 = t->GetFunction()->NewInstance();
 
8075
 
 
8076
  CHECK(o0->SetPrototype(o1));
 
8077
  // If setting the prototype leads to the cycle, SetPrototype should
 
8078
  // return false and keep VM in sane state.
 
8079
  v8::TryCatch try_catch;
 
8080
  CHECK(!o1->SetPrototype(o0));
 
8081
  CHECK(!try_catch.HasCaught());
 
8082
  ASSERT(!i::Isolate::Current()->has_pending_exception());
 
8083
 
 
8084
  CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
 
8085
}
 
8086
 
 
8087
 
 
8088
THREADED_TEST(GetterSetterExceptions) {
 
8089
  v8::HandleScope handle_scope;
 
8090
  LocalContext context;
 
8091
  CompileRun(
 
8092
    "function Foo() { };"
 
8093
    "function Throw() { throw 5; };"
 
8094
    "var x = { };"
 
8095
    "x.__defineSetter__('set', Throw);"
 
8096
    "x.__defineGetter__('get', Throw);");
 
8097
  Local<v8::Object> x =
 
8098
      Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
 
8099
  v8::TryCatch try_catch;
 
8100
  x->Set(v8_str("set"), v8::Integer::New(8));
 
8101
  x->Get(v8_str("get"));
 
8102
  x->Set(v8_str("set"), v8::Integer::New(8));
 
8103
  x->Get(v8_str("get"));
 
8104
  x->Set(v8_str("set"), v8::Integer::New(8));
 
8105
  x->Get(v8_str("get"));
 
8106
  x->Set(v8_str("set"), v8::Integer::New(8));
 
8107
  x->Get(v8_str("get"));
 
8108
}
 
8109
 
 
8110
 
 
8111
THREADED_TEST(Constructor) {
 
8112
  v8::HandleScope handle_scope;
 
8113
  LocalContext context;
 
8114
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
8115
  templ->SetClassName(v8_str("Fun"));
 
8116
  Local<Function> cons = templ->GetFunction();
 
8117
  context->Global()->Set(v8_str("Fun"), cons);
 
8118
  Local<v8::Object> inst = cons->NewInstance();
 
8119
  i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
 
8120
  CHECK(obj->IsJSObject());
 
8121
  Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
 
8122
  CHECK(value->BooleanValue());
 
8123
}
 
8124
 
 
8125
 
 
8126
static Handle<Value> ConstructorCallback(const Arguments& args) {
 
8127
  ApiTestFuzzer::Fuzz();
 
8128
  Local<Object> This;
 
8129
 
 
8130
  if (args.IsConstructCall()) {
 
8131
    Local<Object> Holder = args.Holder();
 
8132
    This = Object::New();
 
8133
    Local<Value> proto = Holder->GetPrototype();
 
8134
    if (proto->IsObject()) {
 
8135
      This->SetPrototype(proto);
 
8136
    }
 
8137
  } else {
 
8138
    This = args.This();
 
8139
  }
 
8140
 
 
8141
  This->Set(v8_str("a"), args[0]);
 
8142
  return This;
 
8143
}
 
8144
 
 
8145
 
 
8146
static Handle<Value> FakeConstructorCallback(const Arguments& args) {
 
8147
  ApiTestFuzzer::Fuzz();
 
8148
  return args[0];
 
8149
}
 
8150
 
 
8151
 
 
8152
THREADED_TEST(ConstructorForObject) {
 
8153
  v8::HandleScope handle_scope;
 
8154
  LocalContext context;
 
8155
 
 
8156
  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8157
    instance_template->SetCallAsFunctionHandler(ConstructorCallback);
 
8158
    Local<Object> instance = instance_template->NewInstance();
 
8159
    context->Global()->Set(v8_str("obj"), instance);
 
8160
    v8::TryCatch try_catch;
 
8161
    Local<Value> value;
 
8162
    CHECK(!try_catch.HasCaught());
 
8163
 
 
8164
    // Call the Object's constructor with a 32-bit signed integer.
 
8165
    value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
 
8166
    CHECK(!try_catch.HasCaught());
 
8167
    CHECK(value->IsInt32());
 
8168
    CHECK_EQ(28, value->Int32Value());
 
8169
 
 
8170
    Local<Value> args1[] = { v8_num(28) };
 
8171
    Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
 
8172
    CHECK(value_obj1->IsObject());
 
8173
    Local<Object> object1 = Local<Object>::Cast(value_obj1);
 
8174
    value = object1->Get(v8_str("a"));
 
8175
    CHECK(value->IsInt32());
 
8176
    CHECK(!try_catch.HasCaught());
 
8177
    CHECK_EQ(28, value->Int32Value());
 
8178
 
 
8179
    // Call the Object's constructor with a String.
 
8180
    value = CompileRun(
 
8181
        "(function() { var o = new obj('tipli'); return o.a; })()");
 
8182
    CHECK(!try_catch.HasCaught());
 
8183
    CHECK(value->IsString());
 
8184
    String::AsciiValue string_value1(value->ToString());
 
8185
    CHECK_EQ("tipli", *string_value1);
 
8186
 
 
8187
    Local<Value> args2[] = { v8_str("tipli") };
 
8188
    Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
 
8189
    CHECK(value_obj2->IsObject());
 
8190
    Local<Object> object2 = Local<Object>::Cast(value_obj2);
 
8191
    value = object2->Get(v8_str("a"));
 
8192
    CHECK(!try_catch.HasCaught());
 
8193
    CHECK(value->IsString());
 
8194
    String::AsciiValue string_value2(value->ToString());
 
8195
    CHECK_EQ("tipli", *string_value2);
 
8196
 
 
8197
    // Call the Object's constructor with a Boolean.
 
8198
    value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
 
8199
    CHECK(!try_catch.HasCaught());
 
8200
    CHECK(value->IsBoolean());
 
8201
    CHECK_EQ(true, value->BooleanValue());
 
8202
 
 
8203
    Handle<Value> args3[] = { v8::True() };
 
8204
    Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
 
8205
    CHECK(value_obj3->IsObject());
 
8206
    Local<Object> object3 = Local<Object>::Cast(value_obj3);
 
8207
    value = object3->Get(v8_str("a"));
 
8208
    CHECK(!try_catch.HasCaught());
 
8209
    CHECK(value->IsBoolean());
 
8210
    CHECK_EQ(true, value->BooleanValue());
 
8211
 
 
8212
    // Call the Object's constructor with undefined.
 
8213
    Handle<Value> args4[] = { v8::Undefined() };
 
8214
    Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
 
8215
    CHECK(value_obj4->IsObject());
 
8216
    Local<Object> object4 = Local<Object>::Cast(value_obj4);
 
8217
    value = object4->Get(v8_str("a"));
 
8218
    CHECK(!try_catch.HasCaught());
 
8219
    CHECK(value->IsUndefined());
 
8220
 
 
8221
    // Call the Object's constructor with null.
 
8222
    Handle<Value> args5[] = { v8::Null() };
 
8223
    Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
 
8224
    CHECK(value_obj5->IsObject());
 
8225
    Local<Object> object5 = Local<Object>::Cast(value_obj5);
 
8226
    value = object5->Get(v8_str("a"));
 
8227
    CHECK(!try_catch.HasCaught());
 
8228
    CHECK(value->IsNull());
 
8229
  }
 
8230
 
 
8231
  // Check exception handling when there is no constructor set for the Object.
 
8232
  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8233
    Local<Object> instance = instance_template->NewInstance();
 
8234
    context->Global()->Set(v8_str("obj2"), instance);
 
8235
    v8::TryCatch try_catch;
 
8236
    Local<Value> value;
 
8237
    CHECK(!try_catch.HasCaught());
 
8238
 
 
8239
    value = CompileRun("new obj2(28)");
 
8240
    CHECK(try_catch.HasCaught());
 
8241
    String::AsciiValue exception_value1(try_catch.Exception());
 
8242
    CHECK_EQ("TypeError: object is not a function", *exception_value1);
 
8243
    try_catch.Reset();
 
8244
 
 
8245
    Local<Value> args[] = { v8_num(29) };
 
8246
    value = instance->CallAsConstructor(1, args);
 
8247
    CHECK(try_catch.HasCaught());
 
8248
    String::AsciiValue exception_value2(try_catch.Exception());
 
8249
    CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
 
8250
    try_catch.Reset();
 
8251
  }
 
8252
 
 
8253
  // Check the case when constructor throws exception.
 
8254
  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8255
    instance_template->SetCallAsFunctionHandler(ThrowValue);
 
8256
    Local<Object> instance = instance_template->NewInstance();
 
8257
    context->Global()->Set(v8_str("obj3"), instance);
 
8258
    v8::TryCatch try_catch;
 
8259
    Local<Value> value;
 
8260
    CHECK(!try_catch.HasCaught());
 
8261
 
 
8262
    value = CompileRun("new obj3(22)");
 
8263
    CHECK(try_catch.HasCaught());
 
8264
    String::AsciiValue exception_value1(try_catch.Exception());
 
8265
    CHECK_EQ("22", *exception_value1);
 
8266
    try_catch.Reset();
 
8267
 
 
8268
    Local<Value> args[] = { v8_num(23) };
 
8269
    value = instance->CallAsConstructor(1, args);
 
8270
    CHECK(try_catch.HasCaught());
 
8271
    String::AsciiValue exception_value2(try_catch.Exception());
 
8272
    CHECK_EQ("23", *exception_value2);
 
8273
    try_catch.Reset();
 
8274
  }
 
8275
 
 
8276
  // Check whether constructor returns with an object or non-object.
 
8277
  { Local<FunctionTemplate> function_template =
 
8278
        FunctionTemplate::New(FakeConstructorCallback);
 
8279
    Local<Function> function = function_template->GetFunction();
 
8280
    Local<Object> instance1 = function;
 
8281
    context->Global()->Set(v8_str("obj4"), instance1);
 
8282
    v8::TryCatch try_catch;
 
8283
    Local<Value> value;
 
8284
    CHECK(!try_catch.HasCaught());
 
8285
 
 
8286
    CHECK(instance1->IsObject());
 
8287
    CHECK(instance1->IsFunction());
 
8288
 
 
8289
    value = CompileRun("new obj4(28)");
 
8290
    CHECK(!try_catch.HasCaught());
 
8291
    CHECK(value->IsObject());
 
8292
 
 
8293
    Local<Value> args1[] = { v8_num(28) };
 
8294
    value = instance1->CallAsConstructor(1, args1);
 
8295
    CHECK(!try_catch.HasCaught());
 
8296
    CHECK(value->IsObject());
 
8297
 
 
8298
    Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8299
    instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
 
8300
    Local<Object> instance2 = instance_template->NewInstance();
 
8301
    context->Global()->Set(v8_str("obj5"), instance2);
 
8302
    CHECK(!try_catch.HasCaught());
 
8303
 
 
8304
    CHECK(instance2->IsObject());
 
8305
    CHECK(!instance2->IsFunction());
 
8306
 
 
8307
    value = CompileRun("new obj5(28)");
 
8308
    CHECK(!try_catch.HasCaught());
 
8309
    CHECK(!value->IsObject());
 
8310
 
 
8311
    Local<Value> args2[] = { v8_num(28) };
 
8312
    value = instance2->CallAsConstructor(1, args2);
 
8313
    CHECK(!try_catch.HasCaught());
 
8314
    CHECK(!value->IsObject());
 
8315
  }
 
8316
}
 
8317
 
 
8318
 
 
8319
THREADED_TEST(FunctionDescriptorException) {
 
8320
  v8::HandleScope handle_scope;
 
8321
  LocalContext context;
 
8322
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
8323
  templ->SetClassName(v8_str("Fun"));
 
8324
  Local<Function> cons = templ->GetFunction();
 
8325
  context->Global()->Set(v8_str("Fun"), cons);
 
8326
  Local<Value> value = CompileRun(
 
8327
    "function test() {"
 
8328
    "  try {"
 
8329
    "    (new Fun()).blah()"
 
8330
    "  } catch (e) {"
 
8331
    "    var str = String(e);"
 
8332
    "    if (str.indexOf('TypeError') == -1) return 1;"
 
8333
    "    if (str.indexOf('[object Fun]') != -1) return 2;"
 
8334
    "    if (str.indexOf('#<Fun>') == -1) return 3;"
 
8335
    "    return 0;"
 
8336
    "  }"
 
8337
    "  return 4;"
 
8338
    "}"
 
8339
    "test();");
 
8340
  CHECK_EQ(0, value->Int32Value());
 
8341
}
 
8342
 
 
8343
 
 
8344
THREADED_TEST(EvalAliasedDynamic) {
 
8345
  v8::HandleScope scope;
 
8346
  LocalContext current;
 
8347
 
 
8348
  // Tests where aliased eval can only be resolved dynamically.
 
8349
  Local<Script> script =
 
8350
      Script::Compile(v8_str("function f(x) { "
 
8351
                             "  var foo = 2;"
 
8352
                             "  with (x) { return eval('foo'); }"
 
8353
                             "}"
 
8354
                             "foo = 0;"
 
8355
                             "result1 = f(new Object());"
 
8356
                             "result2 = f(this);"
 
8357
                             "var x = new Object();"
 
8358
                             "x.eval = function(x) { return 1; };"
 
8359
                             "result3 = f(x);"));
 
8360
  script->Run();
 
8361
  CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
 
8362
  CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
 
8363
  CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
 
8364
 
 
8365
  v8::TryCatch try_catch;
 
8366
  script =
 
8367
    Script::Compile(v8_str("function f(x) { "
 
8368
                           "  var bar = 2;"
 
8369
                           "  with (x) { return eval('bar'); }"
 
8370
                           "}"
 
8371
                           "result4 = f(this)"));
 
8372
  script->Run();
 
8373
  CHECK(!try_catch.HasCaught());
 
8374
  CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
 
8375
 
 
8376
  try_catch.Reset();
 
8377
}
 
8378
 
 
8379
 
 
8380
THREADED_TEST(CrossEval) {
 
8381
  v8::HandleScope scope;
 
8382
  LocalContext other;
 
8383
  LocalContext current;
 
8384
 
 
8385
  Local<String> token = v8_str("<security token>");
 
8386
  other->SetSecurityToken(token);
 
8387
  current->SetSecurityToken(token);
 
8388
 
 
8389
  // Set up reference from current to other.
 
8390
  current->Global()->Set(v8_str("other"), other->Global());
 
8391
 
 
8392
  // Check that new variables are introduced in other context.
 
8393
  Local<Script> script =
 
8394
      Script::Compile(v8_str("other.eval('var foo = 1234')"));
 
8395
  script->Run();
 
8396
  Local<Value> foo = other->Global()->Get(v8_str("foo"));
 
8397
  CHECK_EQ(1234, foo->Int32Value());
 
8398
  CHECK(!current->Global()->Has(v8_str("foo")));
 
8399
 
 
8400
  // Check that writing to non-existing properties introduces them in
 
8401
  // the other context.
 
8402
  script =
 
8403
      Script::Compile(v8_str("other.eval('na = 1234')"));
 
8404
  script->Run();
 
8405
  CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
 
8406
  CHECK(!current->Global()->Has(v8_str("na")));
 
8407
 
 
8408
  // Check that global variables in current context are not visible in other
 
8409
  // context.
 
8410
  v8::TryCatch try_catch;
 
8411
  script =
 
8412
      Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
 
8413
  Local<Value> result = script->Run();
 
8414
  CHECK(try_catch.HasCaught());
 
8415
  try_catch.Reset();
 
8416
 
 
8417
  // Check that local variables in current context are not visible in other
 
8418
  // context.
 
8419
  script =
 
8420
      Script::Compile(v8_str("(function() { "
 
8421
                             "  var baz = 87;"
 
8422
                             "  return other.eval('baz');"
 
8423
                             "})();"));
 
8424
  result = script->Run();
 
8425
  CHECK(try_catch.HasCaught());
 
8426
  try_catch.Reset();
 
8427
 
 
8428
  // Check that global variables in the other environment are visible
 
8429
  // when evaluting code.
 
8430
  other->Global()->Set(v8_str("bis"), v8_num(1234));
 
8431
  script = Script::Compile(v8_str("other.eval('bis')"));
 
8432
  CHECK_EQ(1234, script->Run()->Int32Value());
 
8433
  CHECK(!try_catch.HasCaught());
 
8434
 
 
8435
  // Check that the 'this' pointer points to the global object evaluating
 
8436
  // code.
 
8437
  other->Global()->Set(v8_str("t"), other->Global());
 
8438
  script = Script::Compile(v8_str("other.eval('this == t')"));
 
8439
  result = script->Run();
 
8440
  CHECK(result->IsTrue());
 
8441
  CHECK(!try_catch.HasCaught());
 
8442
 
 
8443
  // Check that variables introduced in with-statement are not visible in
 
8444
  // other context.
 
8445
  script =
 
8446
      Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
 
8447
  result = script->Run();
 
8448
  CHECK(try_catch.HasCaught());
 
8449
  try_catch.Reset();
 
8450
 
 
8451
  // Check that you cannot use 'eval.call' with another object than the
 
8452
  // current global object.
 
8453
  script =
 
8454
      Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
 
8455
  result = script->Run();
 
8456
  CHECK(try_catch.HasCaught());
 
8457
}
 
8458
 
 
8459
 
 
8460
// Test that calling eval in a context which has been detached from
 
8461
// its global throws an exception.  This behavior is consistent with
 
8462
// other JavaScript implementations.
 
8463
THREADED_TEST(EvalInDetachedGlobal) {
 
8464
  v8::HandleScope scope;
 
8465
 
 
8466
  v8::Persistent<Context> context0 = Context::New();
 
8467
  v8::Persistent<Context> context1 = Context::New();
 
8468
 
 
8469
  // Set up function in context0 that uses eval from context0.
 
8470
  context0->Enter();
 
8471
  v8::Handle<v8::Value> fun =
 
8472
      CompileRun("var x = 42;"
 
8473
                 "(function() {"
 
8474
                 "  var e = eval;"
 
8475
                 "  return function(s) { return e(s); }"
 
8476
                 "})()");
 
8477
  context0->Exit();
 
8478
 
 
8479
  // Put the function into context1 and call it before and after
 
8480
  // detaching the global.  Before detaching, the call succeeds and
 
8481
  // after detaching and exception is thrown.
 
8482
  context1->Enter();
 
8483
  context1->Global()->Set(v8_str("fun"), fun);
 
8484
  v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
 
8485
  CHECK_EQ(42, x_value->Int32Value());
 
8486
  context0->DetachGlobal();
 
8487
  v8::TryCatch catcher;
 
8488
  x_value = CompileRun("fun('x')");
 
8489
  CHECK(x_value.IsEmpty());
 
8490
  CHECK(catcher.HasCaught());
 
8491
  context1->Exit();
 
8492
 
 
8493
  context1.Dispose();
 
8494
  context0.Dispose();
 
8495
}
 
8496
 
 
8497
 
 
8498
THREADED_TEST(CrossLazyLoad) {
 
8499
  v8::HandleScope scope;
 
8500
  LocalContext other;
 
8501
  LocalContext current;
 
8502
 
 
8503
  Local<String> token = v8_str("<security token>");
 
8504
  other->SetSecurityToken(token);
 
8505
  current->SetSecurityToken(token);
 
8506
 
 
8507
  // Set up reference from current to other.
 
8508
  current->Global()->Set(v8_str("other"), other->Global());
 
8509
 
 
8510
  // Trigger lazy loading in other context.
 
8511
  Local<Script> script =
 
8512
      Script::Compile(v8_str("other.eval('new Date(42)')"));
 
8513
  Local<Value> value = script->Run();
 
8514
  CHECK_EQ(42.0, value->NumberValue());
 
8515
}
 
8516
 
 
8517
 
 
8518
static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
 
8519
  ApiTestFuzzer::Fuzz();
 
8520
  if (args.IsConstructCall()) {
 
8521
    if (args[0]->IsInt32()) {
 
8522
       return v8_num(-args[0]->Int32Value());
 
8523
    }
 
8524
  }
 
8525
 
 
8526
  return args[0];
 
8527
}
 
8528
 
 
8529
 
 
8530
// Test that a call handler can be set for objects which will allow
 
8531
// non-function objects created through the API to be called as
 
8532
// functions.
 
8533
THREADED_TEST(CallAsFunction) {
 
8534
  v8::HandleScope scope;
 
8535
  LocalContext context;
 
8536
 
 
8537
  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
8538
    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
 
8539
    instance_template->SetCallAsFunctionHandler(call_as_function);
 
8540
    Local<v8::Object> instance = t->GetFunction()->NewInstance();
 
8541
    context->Global()->Set(v8_str("obj"), instance);
 
8542
    v8::TryCatch try_catch;
 
8543
    Local<Value> value;
 
8544
    CHECK(!try_catch.HasCaught());
 
8545
 
 
8546
    value = CompileRun("obj(42)");
 
8547
    CHECK(!try_catch.HasCaught());
 
8548
    CHECK_EQ(42, value->Int32Value());
 
8549
 
 
8550
    value = CompileRun("(function(o){return o(49)})(obj)");
 
8551
    CHECK(!try_catch.HasCaught());
 
8552
    CHECK_EQ(49, value->Int32Value());
 
8553
 
 
8554
    // test special case of call as function
 
8555
    value = CompileRun("[obj]['0'](45)");
 
8556
    CHECK(!try_catch.HasCaught());
 
8557
    CHECK_EQ(45, value->Int32Value());
 
8558
 
 
8559
    value = CompileRun("obj.call = Function.prototype.call;"
 
8560
                       "obj.call(null, 87)");
 
8561
    CHECK(!try_catch.HasCaught());
 
8562
    CHECK_EQ(87, value->Int32Value());
 
8563
 
 
8564
    // Regression tests for bug #1116356: Calling call through call/apply
 
8565
    // must work for non-function receivers.
 
8566
    const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
 
8567
    value = CompileRun(apply_99);
 
8568
    CHECK(!try_catch.HasCaught());
 
8569
    CHECK_EQ(99, value->Int32Value());
 
8570
 
 
8571
    const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
 
8572
    value = CompileRun(call_17);
 
8573
    CHECK(!try_catch.HasCaught());
 
8574
    CHECK_EQ(17, value->Int32Value());
 
8575
 
 
8576
    // Check that the call-as-function handler can be called through
 
8577
    // new.
 
8578
    value = CompileRun("new obj(43)");
 
8579
    CHECK(!try_catch.HasCaught());
 
8580
    CHECK_EQ(-43, value->Int32Value());
 
8581
 
 
8582
    // Check that the call-as-function handler can be called through
 
8583
    // the API.
 
8584
    v8::Handle<Value> args[] = { v8_num(28) };
 
8585
    value = instance->CallAsFunction(instance, 1, args);
 
8586
    CHECK(!try_catch.HasCaught());
 
8587
    CHECK_EQ(28, value->Int32Value());
 
8588
  }
 
8589
 
 
8590
  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
8591
    Local<ObjectTemplate> instance_template(t->InstanceTemplate());
 
8592
    USE(instance_template);
 
8593
    Local<v8::Object> instance = t->GetFunction()->NewInstance();
 
8594
    context->Global()->Set(v8_str("obj2"), instance);
 
8595
    v8::TryCatch try_catch;
 
8596
    Local<Value> value;
 
8597
    CHECK(!try_catch.HasCaught());
 
8598
 
 
8599
    // Call an object without call-as-function handler through the JS
 
8600
    value = CompileRun("obj2(28)");
 
8601
    CHECK(value.IsEmpty());
 
8602
    CHECK(try_catch.HasCaught());
 
8603
    String::AsciiValue exception_value1(try_catch.Exception());
 
8604
    CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
 
8605
             *exception_value1);
 
8606
    try_catch.Reset();
 
8607
 
 
8608
    // Call an object without call-as-function handler through the API
 
8609
    value = CompileRun("obj2(28)");
 
8610
    v8::Handle<Value> args[] = { v8_num(28) };
 
8611
    value = instance->CallAsFunction(instance, 1, args);
 
8612
    CHECK(value.IsEmpty());
 
8613
    CHECK(try_catch.HasCaught());
 
8614
    String::AsciiValue exception_value2(try_catch.Exception());
 
8615
    CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
 
8616
    try_catch.Reset();
 
8617
  }
 
8618
 
 
8619
  { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
 
8620
    Local<ObjectTemplate> instance_template = t->InstanceTemplate();
 
8621
    instance_template->SetCallAsFunctionHandler(ThrowValue);
 
8622
    Local<v8::Object> instance = t->GetFunction()->NewInstance();
 
8623
    context->Global()->Set(v8_str("obj3"), instance);
 
8624
    v8::TryCatch try_catch;
 
8625
    Local<Value> value;
 
8626
    CHECK(!try_catch.HasCaught());
 
8627
 
 
8628
    // Catch the exception which is thrown by call-as-function handler
 
8629
    value = CompileRun("obj3(22)");
 
8630
    CHECK(try_catch.HasCaught());
 
8631
    String::AsciiValue exception_value1(try_catch.Exception());
 
8632
    CHECK_EQ("22", *exception_value1);
 
8633
    try_catch.Reset();
 
8634
 
 
8635
    v8::Handle<Value> args[] = { v8_num(23) };
 
8636
    value = instance->CallAsFunction(instance, 1, args);
 
8637
    CHECK(try_catch.HasCaught());
 
8638
    String::AsciiValue exception_value2(try_catch.Exception());
 
8639
    CHECK_EQ("23", *exception_value2);
 
8640
    try_catch.Reset();
 
8641
  }
 
8642
}
 
8643
 
 
8644
 
 
8645
// Check whether a non-function object is callable.
 
8646
THREADED_TEST(CallableObject) {
 
8647
  v8::HandleScope scope;
 
8648
  LocalContext context;
 
8649
 
 
8650
  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8651
    instance_template->SetCallAsFunctionHandler(call_as_function);
 
8652
    Local<Object> instance = instance_template->NewInstance();
 
8653
    v8::TryCatch try_catch;
 
8654
 
 
8655
    CHECK(instance->IsCallable());
 
8656
    CHECK(!try_catch.HasCaught());
 
8657
  }
 
8658
 
 
8659
  { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
 
8660
    Local<Object> instance = instance_template->NewInstance();
 
8661
    v8::TryCatch try_catch;
 
8662
 
 
8663
    CHECK(!instance->IsCallable());
 
8664
    CHECK(!try_catch.HasCaught());
 
8665
  }
 
8666
 
 
8667
  { Local<FunctionTemplate> function_template =
 
8668
        FunctionTemplate::New(call_as_function);
 
8669
    Local<Function> function = function_template->GetFunction();
 
8670
    Local<Object> instance = function;
 
8671
    v8::TryCatch try_catch;
 
8672
 
 
8673
    CHECK(instance->IsCallable());
 
8674
    CHECK(!try_catch.HasCaught());
 
8675
  }
 
8676
 
 
8677
  { Local<FunctionTemplate> function_template = FunctionTemplate::New();
 
8678
    Local<Function> function = function_template->GetFunction();
 
8679
    Local<Object> instance = function;
 
8680
    v8::TryCatch try_catch;
 
8681
 
 
8682
    CHECK(instance->IsCallable());
 
8683
    CHECK(!try_catch.HasCaught());
 
8684
  }
 
8685
}
 
8686
 
 
8687
 
 
8688
static int CountHandles() {
 
8689
  return v8::HandleScope::NumberOfHandles();
 
8690
}
 
8691
 
 
8692
 
 
8693
static int Recurse(int depth, int iterations) {
 
8694
  v8::HandleScope scope;
 
8695
  if (depth == 0) return CountHandles();
 
8696
  for (int i = 0; i < iterations; i++) {
 
8697
    Local<v8::Number> n(v8::Integer::New(42));
 
8698
  }
 
8699
  return Recurse(depth - 1, iterations);
 
8700
}
 
8701
 
 
8702
 
 
8703
THREADED_TEST(HandleIteration) {
 
8704
  static const int kIterations = 500;
 
8705
  static const int kNesting = 200;
 
8706
  CHECK_EQ(0, CountHandles());
 
8707
  {
 
8708
    v8::HandleScope scope1;
 
8709
    CHECK_EQ(0, CountHandles());
 
8710
    for (int i = 0; i < kIterations; i++) {
 
8711
      Local<v8::Number> n(v8::Integer::New(42));
 
8712
      CHECK_EQ(i + 1, CountHandles());
 
8713
    }
 
8714
 
 
8715
    CHECK_EQ(kIterations, CountHandles());
 
8716
    {
 
8717
      v8::HandleScope scope2;
 
8718
      for (int j = 0; j < kIterations; j++) {
 
8719
        Local<v8::Number> n(v8::Integer::New(42));
 
8720
        CHECK_EQ(j + 1 + kIterations, CountHandles());
 
8721
      }
 
8722
    }
 
8723
    CHECK_EQ(kIterations, CountHandles());
 
8724
  }
 
8725
  CHECK_EQ(0, CountHandles());
 
8726
  CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
 
8727
}
 
8728
 
 
8729
 
 
8730
static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
 
8731
    Local<String> name,
 
8732
    const AccessorInfo& info) {
 
8733
  ApiTestFuzzer::Fuzz();
 
8734
  return v8::Handle<Value>();
 
8735
}
 
8736
 
 
8737
 
 
8738
THREADED_TEST(InterceptorHasOwnProperty) {
 
8739
  v8::HandleScope scope;
 
8740
  LocalContext context;
 
8741
  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
8742
  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
 
8743
  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
 
8744
  Local<Function> function = fun_templ->GetFunction();
 
8745
  context->Global()->Set(v8_str("constructor"), function);
 
8746
  v8::Handle<Value> value = CompileRun(
 
8747
      "var o = new constructor();"
 
8748
      "o.hasOwnProperty('ostehaps');");
 
8749
  CHECK_EQ(false, value->BooleanValue());
 
8750
  value = CompileRun(
 
8751
      "o.ostehaps = 42;"
 
8752
      "o.hasOwnProperty('ostehaps');");
 
8753
  CHECK_EQ(true, value->BooleanValue());
 
8754
  value = CompileRun(
 
8755
      "var p = new constructor();"
 
8756
      "p.hasOwnProperty('ostehaps');");
 
8757
  CHECK_EQ(false, value->BooleanValue());
 
8758
}
 
8759
 
 
8760
 
 
8761
static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
 
8762
    Local<String> name,
 
8763
    const AccessorInfo& info) {
 
8764
  ApiTestFuzzer::Fuzz();
 
8765
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
8766
  return v8::Handle<Value>();
 
8767
}
 
8768
 
 
8769
 
 
8770
THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
 
8771
  v8::HandleScope scope;
 
8772
  LocalContext context;
 
8773
  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
8774
  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
 
8775
  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
 
8776
  Local<Function> function = fun_templ->GetFunction();
 
8777
  context->Global()->Set(v8_str("constructor"), function);
 
8778
  // Let's first make some stuff so we can be sure to get a good GC.
 
8779
  CompileRun(
 
8780
      "function makestr(size) {"
 
8781
      "  switch (size) {"
 
8782
      "    case 1: return 'f';"
 
8783
      "    case 2: return 'fo';"
 
8784
      "    case 3: return 'foo';"
 
8785
      "  }"
 
8786
      "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
 
8787
      "}"
 
8788
      "var x = makestr(12345);"
 
8789
      "x = makestr(31415);"
 
8790
      "x = makestr(23456);");
 
8791
  v8::Handle<Value> value = CompileRun(
 
8792
      "var o = new constructor();"
 
8793
      "o.__proto__ = new String(x);"
 
8794
      "o.hasOwnProperty('ostehaps');");
 
8795
  CHECK_EQ(false, value->BooleanValue());
 
8796
}
 
8797
 
 
8798
 
 
8799
typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
 
8800
                                                 const AccessorInfo& info);
 
8801
 
 
8802
 
 
8803
static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
 
8804
                                   const char* source,
 
8805
                                   int expected) {
 
8806
  v8::HandleScope scope;
 
8807
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
8808
  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
 
8809
  LocalContext context;
 
8810
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
8811
  v8::Handle<Value> value = CompileRun(source);
 
8812
  CHECK_EQ(expected, value->Int32Value());
 
8813
}
 
8814
 
 
8815
 
 
8816
static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
 
8817
                                                 const AccessorInfo& info) {
 
8818
  ApiTestFuzzer::Fuzz();
 
8819
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
8820
  CHECK_EQ(isolate, info.GetIsolate());
 
8821
  CHECK_EQ(v8_str("data"), info.Data());
 
8822
  CHECK_EQ(v8_str("x"), name);
 
8823
  return v8::Integer::New(42);
 
8824
}
 
8825
 
 
8826
 
 
8827
// This test should hit the load IC for the interceptor case.
 
8828
THREADED_TEST(InterceptorLoadIC) {
 
8829
  CheckInterceptorLoadIC(InterceptorLoadICGetter,
 
8830
    "var result = 0;"
 
8831
    "for (var i = 0; i < 1000; i++) {"
 
8832
    "  result = o.x;"
 
8833
    "}",
 
8834
    42);
 
8835
}
 
8836
 
 
8837
 
 
8838
// Below go several tests which verify that JITing for various
 
8839
// configurations of interceptor and explicit fields works fine
 
8840
// (those cases are special cased to get better performance).
 
8841
 
 
8842
static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
 
8843
                                                 const AccessorInfo& info) {
 
8844
  ApiTestFuzzer::Fuzz();
 
8845
  return v8_str("x")->Equals(name)
 
8846
      ? v8::Integer::New(42) : v8::Handle<v8::Value>();
 
8847
}
 
8848
 
 
8849
 
 
8850
THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
 
8851
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8852
    "var result = 0;"
 
8853
    "o.y = 239;"
 
8854
    "for (var i = 0; i < 1000; i++) {"
 
8855
    "  result = o.y;"
 
8856
    "}",
 
8857
    239);
 
8858
}
 
8859
 
 
8860
 
 
8861
THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
 
8862
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8863
    "var result = 0;"
 
8864
    "o.__proto__ = { 'y': 239 };"
 
8865
    "for (var i = 0; i < 1000; i++) {"
 
8866
    "  result = o.y + o.x;"
 
8867
    "}",
 
8868
    239 + 42);
 
8869
}
 
8870
 
 
8871
 
 
8872
THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
 
8873
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8874
    "var result = 0;"
 
8875
    "o.__proto__.y = 239;"
 
8876
    "for (var i = 0; i < 1000; i++) {"
 
8877
    "  result = o.y + o.x;"
 
8878
    "}",
 
8879
    239 + 42);
 
8880
}
 
8881
 
 
8882
 
 
8883
THREADED_TEST(InterceptorLoadICUndefined) {
 
8884
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8885
    "var result = 0;"
 
8886
    "for (var i = 0; i < 1000; i++) {"
 
8887
    "  result = (o.y == undefined) ? 239 : 42;"
 
8888
    "}",
 
8889
    239);
 
8890
}
 
8891
 
 
8892
 
 
8893
THREADED_TEST(InterceptorLoadICWithOverride) {
 
8894
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8895
    "fst = new Object();  fst.__proto__ = o;"
 
8896
    "snd = new Object();  snd.__proto__ = fst;"
 
8897
    "var result1 = 0;"
 
8898
    "for (var i = 0; i < 1000;  i++) {"
 
8899
    "  result1 = snd.x;"
 
8900
    "}"
 
8901
    "fst.x = 239;"
 
8902
    "var result = 0;"
 
8903
    "for (var i = 0; i < 1000; i++) {"
 
8904
    "  result = snd.x;"
 
8905
    "}"
 
8906
    "result + result1",
 
8907
    239 + 42);
 
8908
}
 
8909
 
 
8910
 
 
8911
// Test the case when we stored field into
 
8912
// a stub, but interceptor produced value on its own.
 
8913
THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
 
8914
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8915
    "proto = new Object();"
 
8916
    "o.__proto__ = proto;"
 
8917
    "proto.x = 239;"
 
8918
    "for (var i = 0; i < 1000; i++) {"
 
8919
    "  o.x;"
 
8920
    // Now it should be ICed and keep a reference to x defined on proto
 
8921
    "}"
 
8922
    "var result = 0;"
 
8923
    "for (var i = 0; i < 1000; i++) {"
 
8924
    "  result += o.x;"
 
8925
    "}"
 
8926
    "result;",
 
8927
    42 * 1000);
 
8928
}
 
8929
 
 
8930
 
 
8931
// Test the case when we stored field into
 
8932
// a stub, but it got invalidated later on.
 
8933
THREADED_TEST(InterceptorLoadICInvalidatedField) {
 
8934
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8935
    "proto1 = new Object();"
 
8936
    "proto2 = new Object();"
 
8937
    "o.__proto__ = proto1;"
 
8938
    "proto1.__proto__ = proto2;"
 
8939
    "proto2.y = 239;"
 
8940
    "for (var i = 0; i < 1000; i++) {"
 
8941
    "  o.y;"
 
8942
    // Now it should be ICed and keep a reference to y defined on proto2
 
8943
    "}"
 
8944
    "proto1.y = 42;"
 
8945
    "var result = 0;"
 
8946
    "for (var i = 0; i < 1000; i++) {"
 
8947
    "  result += o.y;"
 
8948
    "}"
 
8949
    "result;",
 
8950
    42 * 1000);
 
8951
}
 
8952
 
 
8953
 
 
8954
static int interceptor_load_not_handled_calls = 0;
 
8955
static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
 
8956
                                                   const AccessorInfo& info) {
 
8957
  ++interceptor_load_not_handled_calls;
 
8958
  return v8::Handle<v8::Value>();
 
8959
}
 
8960
 
 
8961
 
 
8962
// Test how post-interceptor lookups are done in the non-cacheable
 
8963
// case: the interceptor should not be invoked during this lookup.
 
8964
THREADED_TEST(InterceptorLoadICPostInterceptor) {
 
8965
  interceptor_load_not_handled_calls = 0;
 
8966
  CheckInterceptorLoadIC(InterceptorLoadNotHandled,
 
8967
    "receiver = new Object();"
 
8968
    "receiver.__proto__ = o;"
 
8969
    "proto = new Object();"
 
8970
    "/* Make proto a slow-case object. */"
 
8971
    "for (var i = 0; i < 1000; i++) {"
 
8972
    "  proto[\"xxxxxxxx\" + i] = [];"
 
8973
    "}"
 
8974
    "proto.x = 17;"
 
8975
    "o.__proto__ = proto;"
 
8976
    "var result = 0;"
 
8977
    "for (var i = 0; i < 1000; i++) {"
 
8978
    "  result += receiver.x;"
 
8979
    "}"
 
8980
    "result;",
 
8981
    17 * 1000);
 
8982
  CHECK_EQ(1000, interceptor_load_not_handled_calls);
 
8983
}
 
8984
 
 
8985
 
 
8986
// Test the case when we stored field into
 
8987
// a stub, but it got invalidated later on due to override on
 
8988
// global object which is between interceptor and fields' holders.
 
8989
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
 
8990
  CheckInterceptorLoadIC(InterceptorLoadXICGetter,
 
8991
    "o.__proto__ = this;"  // set a global to be a proto of o.
 
8992
    "this.__proto__.y = 239;"
 
8993
    "for (var i = 0; i < 10; i++) {"
 
8994
    "  if (o.y != 239) throw 'oops: ' + o.y;"
 
8995
    // Now it should be ICed and keep a reference to y defined on field_holder.
 
8996
    "}"
 
8997
    "this.y = 42;"  // Assign on a global.
 
8998
    "var result = 0;"
 
8999
    "for (var i = 0; i < 10; i++) {"
 
9000
    "  result += o.y;"
 
9001
    "}"
 
9002
    "result;",
 
9003
    42 * 10);
 
9004
}
 
9005
 
 
9006
 
 
9007
static void SetOnThis(Local<String> name,
 
9008
                      Local<Value> value,
 
9009
                      const AccessorInfo& info) {
 
9010
  info.This()->ForceSet(name, value);
 
9011
}
 
9012
 
 
9013
 
 
9014
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
 
9015
  v8::HandleScope scope;
 
9016
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9017
  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9018
  templ->SetAccessor(v8_str("y"), Return239);
 
9019
  LocalContext context;
 
9020
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9021
 
 
9022
  // Check the case when receiver and interceptor's holder
 
9023
  // are the same objects.
 
9024
  v8::Handle<Value> value = CompileRun(
 
9025
      "var result = 0;"
 
9026
      "for (var i = 0; i < 7; i++) {"
 
9027
      "  result = o.y;"
 
9028
      "}");
 
9029
  CHECK_EQ(239, value->Int32Value());
 
9030
 
 
9031
  // Check the case when interceptor's holder is in proto chain
 
9032
  // of receiver.
 
9033
  value = CompileRun(
 
9034
      "r = { __proto__: o };"
 
9035
      "var result = 0;"
 
9036
      "for (var i = 0; i < 7; i++) {"
 
9037
      "  result = r.y;"
 
9038
      "}");
 
9039
  CHECK_EQ(239, value->Int32Value());
 
9040
}
 
9041
 
 
9042
 
 
9043
THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
 
9044
  v8::HandleScope scope;
 
9045
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
9046
  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9047
  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
 
9048
  templ_p->SetAccessor(v8_str("y"), Return239);
 
9049
 
 
9050
  LocalContext context;
 
9051
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
9052
  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
 
9053
 
 
9054
  // Check the case when receiver and interceptor's holder
 
9055
  // are the same objects.
 
9056
  v8::Handle<Value> value = CompileRun(
 
9057
      "o.__proto__ = p;"
 
9058
      "var result = 0;"
 
9059
      "for (var i = 0; i < 7; i++) {"
 
9060
      "  result = o.x + o.y;"
 
9061
      "}");
 
9062
  CHECK_EQ(239 + 42, value->Int32Value());
 
9063
 
 
9064
  // Check the case when interceptor's holder is in proto chain
 
9065
  // of receiver.
 
9066
  value = CompileRun(
 
9067
      "r = { __proto__: o };"
 
9068
      "var result = 0;"
 
9069
      "for (var i = 0; i < 7; i++) {"
 
9070
      "  result = r.x + r.y;"
 
9071
      "}");
 
9072
  CHECK_EQ(239 + 42, value->Int32Value());
 
9073
}
 
9074
 
 
9075
 
 
9076
THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
 
9077
  v8::HandleScope scope;
 
9078
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9079
  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9080
  templ->SetAccessor(v8_str("y"), Return239);
 
9081
 
 
9082
  LocalContext context;
 
9083
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9084
 
 
9085
  v8::Handle<Value> value = CompileRun(
 
9086
    "fst = new Object();  fst.__proto__ = o;"
 
9087
    "snd = new Object();  snd.__proto__ = fst;"
 
9088
    "var result1 = 0;"
 
9089
    "for (var i = 0; i < 7;  i++) {"
 
9090
    "  result1 = snd.x;"
 
9091
    "}"
 
9092
    "fst.x = 239;"
 
9093
    "var result = 0;"
 
9094
    "for (var i = 0; i < 7; i++) {"
 
9095
    "  result = snd.x;"
 
9096
    "}"
 
9097
    "result + result1");
 
9098
  CHECK_EQ(239 + 42, value->Int32Value());
 
9099
}
 
9100
 
 
9101
 
 
9102
// Test the case when we stored callback into
 
9103
// a stub, but interceptor produced value on its own.
 
9104
THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
 
9105
  v8::HandleScope scope;
 
9106
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
9107
  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9108
  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
 
9109
  templ_p->SetAccessor(v8_str("y"), Return239);
 
9110
 
 
9111
  LocalContext context;
 
9112
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
9113
  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
 
9114
 
 
9115
  v8::Handle<Value> value = CompileRun(
 
9116
    "o.__proto__ = p;"
 
9117
    "for (var i = 0; i < 7; i++) {"
 
9118
    "  o.x;"
 
9119
    // Now it should be ICed and keep a reference to x defined on p
 
9120
    "}"
 
9121
    "var result = 0;"
 
9122
    "for (var i = 0; i < 7; i++) {"
 
9123
    "  result += o.x;"
 
9124
    "}"
 
9125
    "result");
 
9126
  CHECK_EQ(42 * 7, value->Int32Value());
 
9127
}
 
9128
 
 
9129
 
 
9130
// Test the case when we stored callback into
 
9131
// a stub, but it got invalidated later on.
 
9132
THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
 
9133
  v8::HandleScope scope;
 
9134
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
9135
  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9136
  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
 
9137
  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
 
9138
 
 
9139
  LocalContext context;
 
9140
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
9141
  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
 
9142
 
 
9143
  v8::Handle<Value> value = CompileRun(
 
9144
    "inbetween = new Object();"
 
9145
    "o.__proto__ = inbetween;"
 
9146
    "inbetween.__proto__ = p;"
 
9147
    "for (var i = 0; i < 10; i++) {"
 
9148
    "  o.y;"
 
9149
    // Now it should be ICed and keep a reference to y defined on p
 
9150
    "}"
 
9151
    "inbetween.y = 42;"
 
9152
    "var result = 0;"
 
9153
    "for (var i = 0; i < 10; i++) {"
 
9154
    "  result += o.y;"
 
9155
    "}"
 
9156
    "result");
 
9157
  CHECK_EQ(42 * 10, value->Int32Value());
 
9158
}
 
9159
 
 
9160
 
 
9161
// Test the case when we stored callback into
 
9162
// a stub, but it got invalidated later on due to override on
 
9163
// global object which is between interceptor and callbacks' holders.
 
9164
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
 
9165
  v8::HandleScope scope;
 
9166
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
9167
  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9168
  v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
 
9169
  templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
 
9170
 
 
9171
  LocalContext context;
 
9172
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
9173
  context->Global()->Set(v8_str("p"), templ_p->NewInstance());
 
9174
 
 
9175
  v8::Handle<Value> value = CompileRun(
 
9176
    "o.__proto__ = this;"
 
9177
    "this.__proto__ = p;"
 
9178
    "for (var i = 0; i < 10; i++) {"
 
9179
    "  if (o.y != 239) throw 'oops: ' + o.y;"
 
9180
    // Now it should be ICed and keep a reference to y defined on p
 
9181
    "}"
 
9182
    "this.y = 42;"
 
9183
    "var result = 0;"
 
9184
    "for (var i = 0; i < 10; i++) {"
 
9185
    "  result += o.y;"
 
9186
    "}"
 
9187
    "result");
 
9188
  CHECK_EQ(42 * 10, value->Int32Value());
 
9189
}
 
9190
 
 
9191
 
 
9192
static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
 
9193
                                                  const AccessorInfo& info) {
 
9194
  ApiTestFuzzer::Fuzz();
 
9195
  CHECK(v8_str("x")->Equals(name));
 
9196
  return v8::Integer::New(0);
 
9197
}
 
9198
 
 
9199
 
 
9200
THREADED_TEST(InterceptorReturningZero) {
 
9201
  CheckInterceptorLoadIC(InterceptorLoadICGetter0,
 
9202
     "o.x == undefined ? 1 : 0",
 
9203
     0);
 
9204
}
 
9205
 
 
9206
 
 
9207
static v8::Handle<Value> InterceptorStoreICSetter(
 
9208
    Local<String> key, Local<Value> value, const AccessorInfo&) {
 
9209
  CHECK(v8_str("x")->Equals(key));
 
9210
  CHECK_EQ(42, value->Int32Value());
 
9211
  return value;
 
9212
}
 
9213
 
 
9214
 
 
9215
// This test should hit the store IC for the interceptor case.
 
9216
THREADED_TEST(InterceptorStoreIC) {
 
9217
  v8::HandleScope scope;
 
9218
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9219
  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
 
9220
                                 InterceptorStoreICSetter,
 
9221
                                 0, 0, 0, v8_str("data"));
 
9222
  LocalContext context;
 
9223
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9224
  CompileRun(
 
9225
      "for (var i = 0; i < 1000; i++) {"
 
9226
      "  o.x = 42;"
 
9227
      "}");
 
9228
}
 
9229
 
 
9230
 
 
9231
THREADED_TEST(InterceptorStoreICWithNoSetter) {
 
9232
  v8::HandleScope scope;
 
9233
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9234
  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
9235
  LocalContext context;
 
9236
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9237
  v8::Handle<Value> value = CompileRun(
 
9238
    "for (var i = 0; i < 1000; i++) {"
 
9239
    "  o.y = 239;"
 
9240
    "}"
 
9241
    "42 + o.y");
 
9242
  CHECK_EQ(239 + 42, value->Int32Value());
 
9243
}
 
9244
 
 
9245
 
 
9246
 
 
9247
 
 
9248
v8::Handle<Value> call_ic_function;
 
9249
v8::Handle<Value> call_ic_function2;
 
9250
v8::Handle<Value> call_ic_function3;
 
9251
 
 
9252
static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
 
9253
                                                 const AccessorInfo& info) {
 
9254
  ApiTestFuzzer::Fuzz();
 
9255
  CHECK(v8_str("x")->Equals(name));
 
9256
  return call_ic_function;
 
9257
}
 
9258
 
 
9259
 
 
9260
// This test should hit the call IC for the interceptor case.
 
9261
THREADED_TEST(InterceptorCallIC) {
 
9262
  v8::HandleScope scope;
 
9263
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9264
  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
 
9265
  LocalContext context;
 
9266
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9267
  call_ic_function =
 
9268
      v8_compile("function f(x) { return x + 1; }; f")->Run();
 
9269
  v8::Handle<Value> value = CompileRun(
 
9270
    "var result = 0;"
 
9271
    "for (var i = 0; i < 1000; i++) {"
 
9272
    "  result = o.x(41);"
 
9273
    "}");
 
9274
  CHECK_EQ(42, value->Int32Value());
 
9275
}
 
9276
 
 
9277
 
 
9278
// This test checks that if interceptor doesn't provide
 
9279
// a value, we can fetch regular value.
 
9280
THREADED_TEST(InterceptorCallICSeesOthers) {
 
9281
  v8::HandleScope scope;
 
9282
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9283
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
9284
  LocalContext context;
 
9285
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9286
  v8::Handle<Value> value = CompileRun(
 
9287
    "o.x = function f(x) { return x + 1; };"
 
9288
    "var result = 0;"
 
9289
    "for (var i = 0; i < 7; i++) {"
 
9290
    "  result = o.x(41);"
 
9291
    "}");
 
9292
  CHECK_EQ(42, value->Int32Value());
 
9293
}
 
9294
 
 
9295
 
 
9296
static v8::Handle<Value> call_ic_function4;
 
9297
static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
 
9298
                                                  const AccessorInfo& info) {
 
9299
  ApiTestFuzzer::Fuzz();
 
9300
  CHECK(v8_str("x")->Equals(name));
 
9301
  return call_ic_function4;
 
9302
}
 
9303
 
 
9304
 
 
9305
// This test checks that if interceptor provides a function,
 
9306
// even if we cached shadowed variant, interceptor's function
 
9307
// is invoked
 
9308
THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
 
9309
  v8::HandleScope scope;
 
9310
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9311
  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
 
9312
  LocalContext context;
 
9313
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9314
  call_ic_function4 =
 
9315
      v8_compile("function f(x) { return x - 1; }; f")->Run();
 
9316
  v8::Handle<Value> value = CompileRun(
 
9317
    "o.__proto__.x = function(x) { return x + 1; };"
 
9318
    "var result = 0;"
 
9319
    "for (var i = 0; i < 1000; i++) {"
 
9320
    "  result = o.x(42);"
 
9321
    "}");
 
9322
  CHECK_EQ(41, value->Int32Value());
 
9323
}
 
9324
 
 
9325
 
 
9326
// Test the case when we stored cacheable lookup into
 
9327
// a stub, but it got invalidated later on
 
9328
THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
 
9329
  v8::HandleScope scope;
 
9330
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9331
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
9332
  LocalContext context;
 
9333
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9334
  v8::Handle<Value> value = CompileRun(
 
9335
    "proto1 = new Object();"
 
9336
    "proto2 = new Object();"
 
9337
    "o.__proto__ = proto1;"
 
9338
    "proto1.__proto__ = proto2;"
 
9339
    "proto2.y = function(x) { return x + 1; };"
 
9340
    // Invoke it many times to compile a stub
 
9341
    "for (var i = 0; i < 7; i++) {"
 
9342
    "  o.y(42);"
 
9343
    "}"
 
9344
    "proto1.y = function(x) { return x - 1; };"
 
9345
    "var result = 0;"
 
9346
    "for (var i = 0; i < 7; i++) {"
 
9347
    "  result += o.y(42);"
 
9348
    "}");
 
9349
  CHECK_EQ(41 * 7, value->Int32Value());
 
9350
}
 
9351
 
 
9352
 
 
9353
// This test checks that if interceptor doesn't provide a function,
 
9354
// cached constant function is used
 
9355
THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
 
9356
  v8::HandleScope scope;
 
9357
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9358
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
9359
  LocalContext context;
 
9360
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9361
  v8::Handle<Value> value = CompileRun(
 
9362
    "function inc(x) { return x + 1; };"
 
9363
    "inc(1);"
 
9364
    "o.x = inc;"
 
9365
    "var result = 0;"
 
9366
    "for (var i = 0; i < 1000; i++) {"
 
9367
    "  result = o.x(42);"
 
9368
    "}");
 
9369
  CHECK_EQ(43, value->Int32Value());
 
9370
}
 
9371
 
 
9372
 
 
9373
static v8::Handle<Value> call_ic_function5;
 
9374
static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
 
9375
                                                  const AccessorInfo& info) {
 
9376
  ApiTestFuzzer::Fuzz();
 
9377
  if (v8_str("x")->Equals(name))
 
9378
    return call_ic_function5;
 
9379
  else
 
9380
    return Local<Value>();
 
9381
}
 
9382
 
 
9383
 
 
9384
// This test checks that if interceptor provides a function,
 
9385
// even if we cached constant function, interceptor's function
 
9386
// is invoked
 
9387
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
 
9388
  v8::HandleScope scope;
 
9389
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9390
  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
 
9391
  LocalContext context;
 
9392
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9393
  call_ic_function5 =
 
9394
      v8_compile("function f(x) { return x - 1; }; f")->Run();
 
9395
  v8::Handle<Value> value = CompileRun(
 
9396
    "function inc(x) { return x + 1; };"
 
9397
    "inc(1);"
 
9398
    "o.x = inc;"
 
9399
    "var result = 0;"
 
9400
    "for (var i = 0; i < 1000; i++) {"
 
9401
    "  result = o.x(42);"
 
9402
    "}");
 
9403
  CHECK_EQ(41, value->Int32Value());
 
9404
}
 
9405
 
 
9406
 
 
9407
static v8::Handle<Value> call_ic_function6;
 
9408
static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
 
9409
                                                  const AccessorInfo& info) {
 
9410
  ApiTestFuzzer::Fuzz();
 
9411
  if (v8_str("x")->Equals(name))
 
9412
    return call_ic_function6;
 
9413
  else
 
9414
    return Local<Value>();
 
9415
}
 
9416
 
 
9417
 
 
9418
// Same test as above, except the code is wrapped in a function
 
9419
// to test the optimized compiler.
 
9420
THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
 
9421
  i::FLAG_allow_natives_syntax = true;
 
9422
  v8::HandleScope scope;
 
9423
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9424
  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
 
9425
  LocalContext context;
 
9426
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9427
  call_ic_function6 =
 
9428
      v8_compile("function f(x) { return x - 1; }; f")->Run();
 
9429
  v8::Handle<Value> value = CompileRun(
 
9430
    "function inc(x) { return x + 1; };"
 
9431
    "inc(1);"
 
9432
    "o.x = inc;"
 
9433
    "function test() {"
 
9434
    "  var result = 0;"
 
9435
    "  for (var i = 0; i < 1000; i++) {"
 
9436
    "    result = o.x(42);"
 
9437
    "  }"
 
9438
    "  return result;"
 
9439
    "};"
 
9440
    "test();"
 
9441
    "test();"
 
9442
    "test();"
 
9443
    "%OptimizeFunctionOnNextCall(test);"
 
9444
    "test()");
 
9445
  CHECK_EQ(41, value->Int32Value());
 
9446
}
 
9447
 
 
9448
 
 
9449
// Test the case when we stored constant function into
 
9450
// a stub, but it got invalidated later on
 
9451
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
 
9452
  v8::HandleScope scope;
 
9453
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9454
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
9455
  LocalContext context;
 
9456
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9457
  v8::Handle<Value> value = CompileRun(
 
9458
    "function inc(x) { return x + 1; };"
 
9459
    "inc(1);"
 
9460
    "proto1 = new Object();"
 
9461
    "proto2 = new Object();"
 
9462
    "o.__proto__ = proto1;"
 
9463
    "proto1.__proto__ = proto2;"
 
9464
    "proto2.y = inc;"
 
9465
    // Invoke it many times to compile a stub
 
9466
    "for (var i = 0; i < 7; i++) {"
 
9467
    "  o.y(42);"
 
9468
    "}"
 
9469
    "proto1.y = function(x) { return x - 1; };"
 
9470
    "var result = 0;"
 
9471
    "for (var i = 0; i < 7; i++) {"
 
9472
    "  result += o.y(42);"
 
9473
    "}");
 
9474
  CHECK_EQ(41 * 7, value->Int32Value());
 
9475
}
 
9476
 
 
9477
 
 
9478
// Test the case when we stored constant function into
 
9479
// a stub, but it got invalidated later on due to override on
 
9480
// global object which is between interceptor and constant function' holders.
 
9481
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
 
9482
  v8::HandleScope scope;
 
9483
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
9484
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
9485
  LocalContext context;
 
9486
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
9487
  v8::Handle<Value> value = CompileRun(
 
9488
    "function inc(x) { return x + 1; };"
 
9489
    "inc(1);"
 
9490
    "o.__proto__ = this;"
 
9491
    "this.__proto__.y = inc;"
 
9492
    // Invoke it many times to compile a stub
 
9493
    "for (var i = 0; i < 7; i++) {"
 
9494
    "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
 
9495
    "}"
 
9496
    "this.y = function(x) { return x - 1; };"
 
9497
    "var result = 0;"
 
9498
    "for (var i = 0; i < 7; i++) {"
 
9499
    "  result += o.y(42);"
 
9500
    "}");
 
9501
  CHECK_EQ(41 * 7, value->Int32Value());
 
9502
}
 
9503
 
 
9504
 
 
9505
// Test the case when actual function to call sits on global object.
 
9506
THREADED_TEST(InterceptorCallICCachedFromGlobal) {
 
9507
  v8::HandleScope scope;
 
9508
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
9509
  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 
9510
 
 
9511
  LocalContext context;
 
9512
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
9513
 
 
9514
  v8::Handle<Value> value = CompileRun(
 
9515
    "try {"
 
9516
    "  o.__proto__ = this;"
 
9517
    "  for (var i = 0; i < 10; i++) {"
 
9518
    "    var v = o.parseFloat('239');"
 
9519
    "    if (v != 239) throw v;"
 
9520
      // Now it should be ICed and keep a reference to parseFloat.
 
9521
    "  }"
 
9522
    "  var result = 0;"
 
9523
    "  for (var i = 0; i < 10; i++) {"
 
9524
    "    result += o.parseFloat('239');"
 
9525
    "  }"
 
9526
    "  result"
 
9527
    "} catch(e) {"
 
9528
    "  e"
 
9529
    "};");
 
9530
  CHECK_EQ(239 * 10, value->Int32Value());
 
9531
}
 
9532
 
 
9533
static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
 
9534
                                                  const AccessorInfo& info) {
 
9535
  ApiTestFuzzer::Fuzz();
 
9536
  int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
 
9537
  ++(*call_count);
 
9538
  if ((*call_count) % 20 == 0) {
 
9539
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
9540
  }
 
9541
  return v8::Handle<Value>();
 
9542
}
 
9543
 
 
9544
static v8::Handle<Value> FastApiCallback_TrivialSignature(
 
9545
    const v8::Arguments& args) {
 
9546
  ApiTestFuzzer::Fuzz();
 
9547
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
9548
  CHECK_EQ(isolate, args.GetIsolate());
 
9549
  CHECK_EQ(args.This(), args.Holder());
 
9550
  CHECK(args.Data()->Equals(v8_str("method_data")));
 
9551
  return v8::Integer::New(args[0]->Int32Value() + 1);
 
9552
}
 
9553
 
 
9554
static v8::Handle<Value> FastApiCallback_SimpleSignature(
 
9555
    const v8::Arguments& args) {
 
9556
  ApiTestFuzzer::Fuzz();
 
9557
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
9558
  CHECK_EQ(isolate, args.GetIsolate());
 
9559
  CHECK_EQ(args.This()->GetPrototype(), args.Holder());
 
9560
  CHECK(args.Data()->Equals(v8_str("method_data")));
 
9561
  // Note, we're using HasRealNamedProperty instead of Has to avoid
 
9562
  // invoking the interceptor again.
 
9563
  CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
 
9564
  return v8::Integer::New(args[0]->Int32Value() + 1);
 
9565
}
 
9566
 
 
9567
// Helper to maximize the odds of object moving.
 
9568
static void GenerateSomeGarbage() {
 
9569
  CompileRun(
 
9570
      "var garbage;"
 
9571
      "for (var i = 0; i < 1000; i++) {"
 
9572
      "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
 
9573
      "}"
 
9574
      "garbage = undefined;");
 
9575
}
 
9576
 
 
9577
 
 
9578
v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
 
9579
  static int count = 0;
 
9580
  if (count++ % 3 == 0) {
 
9581
    HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
9582
        // This should move the stub
 
9583
    GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
 
9584
  }
 
9585
  return v8::Handle<v8::Value>();
 
9586
}
 
9587
 
 
9588
 
 
9589
THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
 
9590
  v8::HandleScope scope;
 
9591
  LocalContext context;
 
9592
  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
 
9593
  nativeobject_templ->Set("callback",
 
9594
                          v8::FunctionTemplate::New(DirectApiCallback));
 
9595
  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
 
9596
  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
 
9597
  // call the api function multiple times to ensure direct call stub creation.
 
9598
  CompileRun(
 
9599
        "function f() {"
 
9600
        "  for (var i = 1; i <= 30; i++) {"
 
9601
        "    nativeobject.callback();"
 
9602
        "  }"
 
9603
        "}"
 
9604
        "f();");
 
9605
}
 
9606
 
 
9607
 
 
9608
v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
 
9609
  return v8::ThrowException(v8_str("g"));
 
9610
}
 
9611
 
 
9612
 
 
9613
THREADED_TEST(CallICFastApi_DirectCall_Throw) {
 
9614
  v8::HandleScope scope;
 
9615
  LocalContext context;
 
9616
  v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
 
9617
  nativeobject_templ->Set("callback",
 
9618
                          v8::FunctionTemplate::New(ThrowingDirectApiCallback));
 
9619
  v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
 
9620
  context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
 
9621
  // call the api function multiple times to ensure direct call stub creation.
 
9622
  v8::Handle<Value> result = CompileRun(
 
9623
      "var result = '';"
 
9624
      "function f() {"
 
9625
      "  for (var i = 1; i <= 5; i++) {"
 
9626
      "    try { nativeobject.callback(); } catch (e) { result += e; }"
 
9627
      "  }"
 
9628
      "}"
 
9629
      "f(); result;");
 
9630
  CHECK_EQ(v8_str("ggggg"), result);
 
9631
}
 
9632
 
 
9633
 
 
9634
v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
 
9635
                                           const v8::AccessorInfo& info) {
 
9636
  if (++p_getter_count % 3 == 0) {
 
9637
    HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
 
9638
    GenerateSomeGarbage();
 
9639
  }
 
9640
  return v8::Handle<v8::Value>();
 
9641
}
 
9642
 
 
9643
 
 
9644
THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
 
9645
  v8::HandleScope scope;
 
9646
  LocalContext context;
 
9647
  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
 
9648
  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
 
9649
  context->Global()->Set(v8_str("o1"), obj->NewInstance());
 
9650
  p_getter_count = 0;
 
9651
  CompileRun(
 
9652
      "function f() {"
 
9653
      "  for (var i = 0; i < 30; i++) o1.p1;"
 
9654
      "}"
 
9655
      "f();");
 
9656
  CHECK_EQ(30, p_getter_count);
 
9657
}
 
9658
 
 
9659
 
 
9660
v8::Handle<v8::Value> ThrowingDirectGetterCallback(
 
9661
    Local<String> name, const v8::AccessorInfo& info) {
 
9662
  return v8::ThrowException(v8_str("g"));
 
9663
}
 
9664
 
 
9665
 
 
9666
THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
 
9667
  v8::HandleScope scope;
 
9668
  LocalContext context;
 
9669
  v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
 
9670
  obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
 
9671
  context->Global()->Set(v8_str("o1"), obj->NewInstance());
 
9672
  v8::Handle<Value> result = CompileRun(
 
9673
      "var result = '';"
 
9674
      "for (var i = 0; i < 5; i++) {"
 
9675
      "    try { o1.p1; } catch (e) { result += e; }"
 
9676
      "}"
 
9677
      "result;");
 
9678
  CHECK_EQ(v8_str("ggggg"), result);
 
9679
}
 
9680
 
 
9681
 
 
9682
THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
 
9683
  int interceptor_call_count = 0;
 
9684
  v8::HandleScope scope;
 
9685
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9686
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9687
      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
 
9688
                                v8_str("method_data"),
 
9689
                                v8::Handle<v8::Signature>());
 
9690
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9691
  proto_templ->Set(v8_str("method"), method_templ);
 
9692
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9693
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9694
                                 NULL, NULL, NULL, NULL,
 
9695
                                 v8::External::Wrap(&interceptor_call_count));
 
9696
  LocalContext context;
 
9697
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9698
  GenerateSomeGarbage();
 
9699
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9700
  CompileRun(
 
9701
      "var result = 0;"
 
9702
      "for (var i = 0; i < 100; i++) {"
 
9703
      "  result = o.method(41);"
 
9704
      "}");
 
9705
  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
 
9706
  CHECK_EQ(100, interceptor_call_count);
 
9707
}
 
9708
 
 
9709
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
 
9710
  int interceptor_call_count = 0;
 
9711
  v8::HandleScope scope;
 
9712
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9713
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9714
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9715
                                v8_str("method_data"),
 
9716
                                v8::Signature::New(fun_templ));
 
9717
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9718
  proto_templ->Set(v8_str("method"), method_templ);
 
9719
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9720
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9721
                                 NULL, NULL, NULL, NULL,
 
9722
                                 v8::External::Wrap(&interceptor_call_count));
 
9723
  LocalContext context;
 
9724
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9725
  GenerateSomeGarbage();
 
9726
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9727
  CompileRun(
 
9728
      "o.foo = 17;"
 
9729
      "var receiver = {};"
 
9730
      "receiver.__proto__ = o;"
 
9731
      "var result = 0;"
 
9732
      "for (var i = 0; i < 100; i++) {"
 
9733
      "  result = receiver.method(41);"
 
9734
      "}");
 
9735
  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
 
9736
  CHECK_EQ(100, interceptor_call_count);
 
9737
}
 
9738
 
 
9739
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
 
9740
  int interceptor_call_count = 0;
 
9741
  v8::HandleScope scope;
 
9742
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9743
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9744
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9745
                                v8_str("method_data"),
 
9746
                                v8::Signature::New(fun_templ));
 
9747
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9748
  proto_templ->Set(v8_str("method"), method_templ);
 
9749
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9750
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9751
                                 NULL, NULL, NULL, NULL,
 
9752
                                 v8::External::Wrap(&interceptor_call_count));
 
9753
  LocalContext context;
 
9754
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9755
  GenerateSomeGarbage();
 
9756
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9757
  CompileRun(
 
9758
      "o.foo = 17;"
 
9759
      "var receiver = {};"
 
9760
      "receiver.__proto__ = o;"
 
9761
      "var result = 0;"
 
9762
      "var saved_result = 0;"
 
9763
      "for (var i = 0; i < 100; i++) {"
 
9764
      "  result = receiver.method(41);"
 
9765
      "  if (i == 50) {"
 
9766
      "    saved_result = result;"
 
9767
      "    receiver = {method: function(x) { return x - 1 }};"
 
9768
      "  }"
 
9769
      "}");
 
9770
  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
 
9771
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
9772
  CHECK_GE(interceptor_call_count, 50);
 
9773
}
 
9774
 
 
9775
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
 
9776
  int interceptor_call_count = 0;
 
9777
  v8::HandleScope scope;
 
9778
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9779
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9780
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9781
                                v8_str("method_data"),
 
9782
                                v8::Signature::New(fun_templ));
 
9783
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9784
  proto_templ->Set(v8_str("method"), method_templ);
 
9785
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9786
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9787
                                 NULL, NULL, NULL, NULL,
 
9788
                                 v8::External::Wrap(&interceptor_call_count));
 
9789
  LocalContext context;
 
9790
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9791
  GenerateSomeGarbage();
 
9792
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9793
  CompileRun(
 
9794
      "o.foo = 17;"
 
9795
      "var receiver = {};"
 
9796
      "receiver.__proto__ = o;"
 
9797
      "var result = 0;"
 
9798
      "var saved_result = 0;"
 
9799
      "for (var i = 0; i < 100; i++) {"
 
9800
      "  result = receiver.method(41);"
 
9801
      "  if (i == 50) {"
 
9802
      "    saved_result = result;"
 
9803
      "    o.method = function(x) { return x - 1 };"
 
9804
      "  }"
 
9805
      "}");
 
9806
  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
 
9807
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
9808
  CHECK_GE(interceptor_call_count, 50);
 
9809
}
 
9810
 
 
9811
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
 
9812
  int interceptor_call_count = 0;
 
9813
  v8::HandleScope scope;
 
9814
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9815
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9816
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9817
                                v8_str("method_data"),
 
9818
                                v8::Signature::New(fun_templ));
 
9819
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9820
  proto_templ->Set(v8_str("method"), method_templ);
 
9821
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9822
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9823
                                 NULL, NULL, NULL, NULL,
 
9824
                                 v8::External::Wrap(&interceptor_call_count));
 
9825
  LocalContext context;
 
9826
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9827
  GenerateSomeGarbage();
 
9828
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9829
  v8::TryCatch try_catch;
 
9830
  CompileRun(
 
9831
      "o.foo = 17;"
 
9832
      "var receiver = {};"
 
9833
      "receiver.__proto__ = o;"
 
9834
      "var result = 0;"
 
9835
      "var saved_result = 0;"
 
9836
      "for (var i = 0; i < 100; i++) {"
 
9837
      "  result = receiver.method(41);"
 
9838
      "  if (i == 50) {"
 
9839
      "    saved_result = result;"
 
9840
      "    receiver = 333;"
 
9841
      "  }"
 
9842
      "}");
 
9843
  CHECK(try_catch.HasCaught());
 
9844
  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
 
9845
           try_catch.Exception()->ToString());
 
9846
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
9847
  CHECK_GE(interceptor_call_count, 50);
 
9848
}
 
9849
 
 
9850
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
 
9851
  int interceptor_call_count = 0;
 
9852
  v8::HandleScope scope;
 
9853
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9854
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9855
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9856
                                v8_str("method_data"),
 
9857
                                v8::Signature::New(fun_templ));
 
9858
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9859
  proto_templ->Set(v8_str("method"), method_templ);
 
9860
  v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
 
9861
  templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
 
9862
                                 NULL, NULL, NULL, NULL,
 
9863
                                 v8::External::Wrap(&interceptor_call_count));
 
9864
  LocalContext context;
 
9865
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9866
  GenerateSomeGarbage();
 
9867
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9868
  v8::TryCatch try_catch;
 
9869
  CompileRun(
 
9870
      "o.foo = 17;"
 
9871
      "var receiver = {};"
 
9872
      "receiver.__proto__ = o;"
 
9873
      "var result = 0;"
 
9874
      "var saved_result = 0;"
 
9875
      "for (var i = 0; i < 100; i++) {"
 
9876
      "  result = receiver.method(41);"
 
9877
      "  if (i == 50) {"
 
9878
      "    saved_result = result;"
 
9879
      "    receiver = {method: receiver.method};"
 
9880
      "  }"
 
9881
      "}");
 
9882
  CHECK(try_catch.HasCaught());
 
9883
  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
 
9884
           try_catch.Exception()->ToString());
 
9885
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
9886
  CHECK_GE(interceptor_call_count, 50);
 
9887
}
 
9888
 
 
9889
THREADED_TEST(CallICFastApi_TrivialSignature) {
 
9890
  v8::HandleScope scope;
 
9891
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9892
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9893
      v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
 
9894
                                v8_str("method_data"),
 
9895
                                v8::Handle<v8::Signature>());
 
9896
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9897
  proto_templ->Set(v8_str("method"), method_templ);
 
9898
  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
 
9899
  USE(templ);
 
9900
  LocalContext context;
 
9901
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9902
  GenerateSomeGarbage();
 
9903
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9904
  CompileRun(
 
9905
      "var result = 0;"
 
9906
      "for (var i = 0; i < 100; i++) {"
 
9907
      "  result = o.method(41);"
 
9908
      "}");
 
9909
 
 
9910
  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
 
9911
}
 
9912
 
 
9913
THREADED_TEST(CallICFastApi_SimpleSignature) {
 
9914
  v8::HandleScope scope;
 
9915
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9916
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9917
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9918
                                v8_str("method_data"),
 
9919
                                v8::Signature::New(fun_templ));
 
9920
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9921
  proto_templ->Set(v8_str("method"), method_templ);
 
9922
  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
 
9923
  CHECK(!templ.IsEmpty());
 
9924
  LocalContext context;
 
9925
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9926
  GenerateSomeGarbage();
 
9927
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9928
  CompileRun(
 
9929
      "o.foo = 17;"
 
9930
      "var receiver = {};"
 
9931
      "receiver.__proto__ = o;"
 
9932
      "var result = 0;"
 
9933
      "for (var i = 0; i < 100; i++) {"
 
9934
      "  result = receiver.method(41);"
 
9935
      "}");
 
9936
 
 
9937
  CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
 
9938
}
 
9939
 
 
9940
THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
 
9941
  v8::HandleScope scope;
 
9942
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9943
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9944
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9945
                                v8_str("method_data"),
 
9946
                                v8::Signature::New(fun_templ));
 
9947
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9948
  proto_templ->Set(v8_str("method"), method_templ);
 
9949
  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
 
9950
  CHECK(!templ.IsEmpty());
 
9951
  LocalContext context;
 
9952
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9953
  GenerateSomeGarbage();
 
9954
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9955
  CompileRun(
 
9956
      "o.foo = 17;"
 
9957
      "var receiver = {};"
 
9958
      "receiver.__proto__ = o;"
 
9959
      "var result = 0;"
 
9960
      "var saved_result = 0;"
 
9961
      "for (var i = 0; i < 100; i++) {"
 
9962
      "  result = receiver.method(41);"
 
9963
      "  if (i == 50) {"
 
9964
      "    saved_result = result;"
 
9965
      "    receiver = {method: function(x) { return x - 1 }};"
 
9966
      "  }"
 
9967
      "}");
 
9968
  CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
 
9969
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
9970
}
 
9971
 
 
9972
THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
 
9973
  v8::HandleScope scope;
 
9974
  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
 
9975
  v8::Handle<v8::FunctionTemplate> method_templ =
 
9976
      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
 
9977
                                v8_str("method_data"),
 
9978
                                v8::Signature::New(fun_templ));
 
9979
  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
 
9980
  proto_templ->Set(v8_str("method"), method_templ);
 
9981
  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
 
9982
  CHECK(!templ.IsEmpty());
 
9983
  LocalContext context;
 
9984
  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
 
9985
  GenerateSomeGarbage();
 
9986
  context->Global()->Set(v8_str("o"), fun->NewInstance());
 
9987
  v8::TryCatch try_catch;
 
9988
  CompileRun(
 
9989
      "o.foo = 17;"
 
9990
      "var receiver = {};"
 
9991
      "receiver.__proto__ = o;"
 
9992
      "var result = 0;"
 
9993
      "var saved_result = 0;"
 
9994
      "for (var i = 0; i < 100; i++) {"
 
9995
      "  result = receiver.method(41);"
 
9996
      "  if (i == 50) {"
 
9997
      "    saved_result = result;"
 
9998
      "    receiver = 333;"
 
9999
      "  }"
 
10000
      "}");
 
10001
  CHECK(try_catch.HasCaught());
 
10002
  CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
 
10003
           try_catch.Exception()->ToString());
 
10004
  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
10005
}
 
10006
 
 
10007
 
 
10008
v8::Handle<Value> keyed_call_ic_function;
 
10009
 
 
10010
static v8::Handle<Value> InterceptorKeyedCallICGetter(
 
10011
    Local<String> name, const AccessorInfo& info) {
 
10012
  ApiTestFuzzer::Fuzz();
 
10013
  if (v8_str("x")->Equals(name)) {
 
10014
    return keyed_call_ic_function;
 
10015
  }
 
10016
  return v8::Handle<Value>();
 
10017
}
 
10018
 
 
10019
 
 
10020
// Test the case when we stored cacheable lookup into
 
10021
// a stub, but the function name changed (to another cacheable function).
 
10022
THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
 
10023
  v8::HandleScope scope;
 
10024
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10025
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
10026
  LocalContext context;
 
10027
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
10028
  CompileRun(
 
10029
    "proto = new Object();"
 
10030
    "proto.y = function(x) { return x + 1; };"
 
10031
    "proto.z = function(x) { return x - 1; };"
 
10032
    "o.__proto__ = proto;"
 
10033
    "var result = 0;"
 
10034
    "var method = 'y';"
 
10035
    "for (var i = 0; i < 10; i++) {"
 
10036
    "  if (i == 5) { method = 'z'; };"
 
10037
    "  result += o[method](41);"
 
10038
    "}");
 
10039
  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 
10040
}
 
10041
 
 
10042
 
 
10043
// Test the case when we stored cacheable lookup into
 
10044
// a stub, but the function name changed (and the new function is present
 
10045
// both before and after the interceptor in the prototype chain).
 
10046
THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
 
10047
  v8::HandleScope scope;
 
10048
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10049
  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
 
10050
  LocalContext context;
 
10051
  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
 
10052
  keyed_call_ic_function =
 
10053
      v8_compile("function f(x) { return x - 1; }; f")->Run();
 
10054
  CompileRun(
 
10055
    "o = new Object();"
 
10056
    "proto2 = new Object();"
 
10057
    "o.y = function(x) { return x + 1; };"
 
10058
    "proto2.y = function(x) { return x + 2; };"
 
10059
    "o.__proto__ = proto1;"
 
10060
    "proto1.__proto__ = proto2;"
 
10061
    "var result = 0;"
 
10062
    "var method = 'x';"
 
10063
    "for (var i = 0; i < 10; i++) {"
 
10064
    "  if (i == 5) { method = 'y'; };"
 
10065
    "  result += o[method](41);"
 
10066
    "}");
 
10067
  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 
10068
}
 
10069
 
 
10070
 
 
10071
// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
 
10072
// on the global object.
 
10073
THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
 
10074
  v8::HandleScope scope;
 
10075
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10076
  templ->SetNamedPropertyHandler(NoBlockGetterX);
 
10077
  LocalContext context;
 
10078
  context->Global()->Set(v8_str("o"), templ->NewInstance());
 
10079
  CompileRun(
 
10080
    "function inc(x) { return x + 1; };"
 
10081
    "inc(1);"
 
10082
    "function dec(x) { return x - 1; };"
 
10083
    "dec(1);"
 
10084
    "o.__proto__ = this;"
 
10085
    "this.__proto__.x = inc;"
 
10086
    "this.__proto__.y = dec;"
 
10087
    "var result = 0;"
 
10088
    "var method = 'x';"
 
10089
    "for (var i = 0; i < 10; i++) {"
 
10090
    "  if (i == 5) { method = 'y'; };"
 
10091
    "  result += o[method](41);"
 
10092
    "}");
 
10093
  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 
10094
}
 
10095
 
 
10096
 
 
10097
// Test the case when actual function to call sits on global object.
 
10098
THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
 
10099
  v8::HandleScope scope;
 
10100
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
10101
  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 
10102
  LocalContext context;
 
10103
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
10104
 
 
10105
  CompileRun(
 
10106
    "function len(x) { return x.length; };"
 
10107
    "o.__proto__ = this;"
 
10108
    "var m = 'parseFloat';"
 
10109
    "var result = 0;"
 
10110
    "for (var i = 0; i < 10; i++) {"
 
10111
    "  if (i == 5) {"
 
10112
    "    m = 'len';"
 
10113
    "    saved_result = result;"
 
10114
    "  };"
 
10115
    "  result = o[m]('239');"
 
10116
    "}");
 
10117
  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
 
10118
  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 
10119
}
 
10120
 
 
10121
// Test the map transition before the interceptor.
 
10122
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
 
10123
  v8::HandleScope scope;
 
10124
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
10125
  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 
10126
  LocalContext context;
 
10127
  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
 
10128
 
 
10129
  CompileRun(
 
10130
    "var o = new Object();"
 
10131
    "o.__proto__ = proto;"
 
10132
    "o.method = function(x) { return x + 1; };"
 
10133
    "var m = 'method';"
 
10134
    "var result = 0;"
 
10135
    "for (var i = 0; i < 10; i++) {"
 
10136
    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
 
10137
    "  result += o[m](41);"
 
10138
    "}");
 
10139
  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 
10140
}
 
10141
 
 
10142
 
 
10143
// Test the map transition after the interceptor.
 
10144
THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
 
10145
  v8::HandleScope scope;
 
10146
  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 
10147
  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 
10148
  LocalContext context;
 
10149
  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
10150
 
 
10151
  CompileRun(
 
10152
    "var proto = new Object();"
 
10153
    "o.__proto__ = proto;"
 
10154
    "proto.method = function(x) { return x + 1; };"
 
10155
    "var m = 'method';"
 
10156
    "var result = 0;"
 
10157
    "for (var i = 0; i < 10; i++) {"
 
10158
    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
 
10159
    "  result += o[m](41);"
 
10160
    "}");
 
10161
  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 
10162
}
 
10163
 
 
10164
 
 
10165
static int interceptor_call_count = 0;
 
10166
 
 
10167
static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
 
10168
                                                     const AccessorInfo& info) {
 
10169
  ApiTestFuzzer::Fuzz();
 
10170
  if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
 
10171
    return call_ic_function2;
 
10172
  }
 
10173
  return v8::Handle<Value>();
 
10174
}
 
10175
 
 
10176
 
 
10177
// This test should hit load and call ICs for the interceptor case.
 
10178
// Once in a while, the interceptor will reply that a property was not
 
10179
// found in which case we should get a reference error.
 
10180
THREADED_TEST(InterceptorICReferenceErrors) {
 
10181
  v8::HandleScope scope;
 
10182
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10183
  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
 
10184
  LocalContext context(0, templ, v8::Handle<Value>());
 
10185
  call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
 
10186
  v8::Handle<Value> value = CompileRun(
 
10187
    "function f() {"
 
10188
    "  for (var i = 0; i < 1000; i++) {"
 
10189
    "    try { x; } catch(e) { return true; }"
 
10190
    "  }"
 
10191
    "  return false;"
 
10192
    "};"
 
10193
    "f();");
 
10194
  CHECK_EQ(true, value->BooleanValue());
 
10195
  interceptor_call_count = 0;
 
10196
  value = CompileRun(
 
10197
    "function g() {"
 
10198
    "  for (var i = 0; i < 1000; i++) {"
 
10199
    "    try { x(42); } catch(e) { return true; }"
 
10200
    "  }"
 
10201
    "  return false;"
 
10202
    "};"
 
10203
    "g();");
 
10204
  CHECK_EQ(true, value->BooleanValue());
 
10205
}
 
10206
 
 
10207
 
 
10208
static int interceptor_ic_exception_get_count = 0;
 
10209
 
 
10210
static v8::Handle<Value> InterceptorICExceptionGetter(
 
10211
    Local<String> name,
 
10212
    const AccessorInfo& info) {
 
10213
  ApiTestFuzzer::Fuzz();
 
10214
  if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
 
10215
    return call_ic_function3;
 
10216
  }
 
10217
  if (interceptor_ic_exception_get_count == 20) {
 
10218
    return v8::ThrowException(v8_num(42));
 
10219
  }
 
10220
  // Do not handle get for properties other than x.
 
10221
  return v8::Handle<Value>();
 
10222
}
 
10223
 
 
10224
// Test interceptor load/call IC where the interceptor throws an
 
10225
// exception once in a while.
 
10226
THREADED_TEST(InterceptorICGetterExceptions) {
 
10227
  interceptor_ic_exception_get_count = 0;
 
10228
  v8::HandleScope scope;
 
10229
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10230
  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
 
10231
  LocalContext context(0, templ, v8::Handle<Value>());
 
10232
  call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
 
10233
  v8::Handle<Value> value = CompileRun(
 
10234
    "function f() {"
 
10235
    "  for (var i = 0; i < 100; i++) {"
 
10236
    "    try { x; } catch(e) { return true; }"
 
10237
    "  }"
 
10238
    "  return false;"
 
10239
    "};"
 
10240
    "f();");
 
10241
  CHECK_EQ(true, value->BooleanValue());
 
10242
  interceptor_ic_exception_get_count = 0;
 
10243
  value = CompileRun(
 
10244
    "function f() {"
 
10245
    "  for (var i = 0; i < 100; i++) {"
 
10246
    "    try { x(42); } catch(e) { return true; }"
 
10247
    "  }"
 
10248
    "  return false;"
 
10249
    "};"
 
10250
    "f();");
 
10251
  CHECK_EQ(true, value->BooleanValue());
 
10252
}
 
10253
 
 
10254
 
 
10255
static int interceptor_ic_exception_set_count = 0;
 
10256
 
 
10257
static v8::Handle<Value> InterceptorICExceptionSetter(
 
10258
      Local<String> key, Local<Value> value, const AccessorInfo&) {
 
10259
  ApiTestFuzzer::Fuzz();
 
10260
  if (++interceptor_ic_exception_set_count > 20) {
 
10261
    return v8::ThrowException(v8_num(42));
 
10262
  }
 
10263
  // Do not actually handle setting.
 
10264
  return v8::Handle<Value>();
 
10265
}
 
10266
 
 
10267
// Test interceptor store IC where the interceptor throws an exception
 
10268
// once in a while.
 
10269
THREADED_TEST(InterceptorICSetterExceptions) {
 
10270
  interceptor_ic_exception_set_count = 0;
 
10271
  v8::HandleScope scope;
 
10272
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10273
  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
 
10274
  LocalContext context(0, templ, v8::Handle<Value>());
 
10275
  v8::Handle<Value> value = CompileRun(
 
10276
    "function f() {"
 
10277
    "  for (var i = 0; i < 100; i++) {"
 
10278
    "    try { x = 42; } catch(e) { return true; }"
 
10279
    "  }"
 
10280
    "  return false;"
 
10281
    "};"
 
10282
    "f();");
 
10283
  CHECK_EQ(true, value->BooleanValue());
 
10284
}
 
10285
 
 
10286
 
 
10287
// Test that we ignore null interceptors.
 
10288
THREADED_TEST(NullNamedInterceptor) {
 
10289
  v8::HandleScope scope;
 
10290
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10291
  templ->SetNamedPropertyHandler(0);
 
10292
  LocalContext context;
 
10293
  templ->Set("x", v8_num(42));
 
10294
  v8::Handle<v8::Object> obj = templ->NewInstance();
 
10295
  context->Global()->Set(v8_str("obj"), obj);
 
10296
  v8::Handle<Value> value = CompileRun("obj.x");
 
10297
  CHECK(value->IsInt32());
 
10298
  CHECK_EQ(42, value->Int32Value());
 
10299
}
 
10300
 
 
10301
 
 
10302
// Test that we ignore null interceptors.
 
10303
THREADED_TEST(NullIndexedInterceptor) {
 
10304
  v8::HandleScope scope;
 
10305
  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 
10306
  templ->SetIndexedPropertyHandler(0);
 
10307
  LocalContext context;
 
10308
  templ->Set("42", v8_num(42));
 
10309
  v8::Handle<v8::Object> obj = templ->NewInstance();
 
10310
  context->Global()->Set(v8_str("obj"), obj);
 
10311
  v8::Handle<Value> value = CompileRun("obj[42]");
 
10312
  CHECK(value->IsInt32());
 
10313
  CHECK_EQ(42, value->Int32Value());
 
10314
}
 
10315
 
 
10316
 
 
10317
THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
 
10318
  v8::HandleScope scope;
 
10319
  v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
10320
  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
 
10321
  LocalContext env;
 
10322
  env->Global()->Set(v8_str("obj"),
 
10323
                     templ->GetFunction()->NewInstance());
 
10324
  ExpectTrue("obj.x === 42");
 
10325
  ExpectTrue("!obj.propertyIsEnumerable('x')");
 
10326
}
 
10327
 
 
10328
 
 
10329
static Handle<Value> ThrowingGetter(Local<String> name,
 
10330
                                    const AccessorInfo& info) {
 
10331
  ApiTestFuzzer::Fuzz();
 
10332
  ThrowException(Handle<Value>());
 
10333
  return Undefined();
 
10334
}
 
10335
 
 
10336
 
 
10337
THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
 
10338
  HandleScope scope;
 
10339
  LocalContext context;
 
10340
 
 
10341
  Local<FunctionTemplate> templ = FunctionTemplate::New();
 
10342
  Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
 
10343
  instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
 
10344
 
 
10345
  Local<Object> instance = templ->GetFunction()->NewInstance();
 
10346
 
 
10347
  Local<Object> another = Object::New();
 
10348
  another->SetPrototype(instance);
 
10349
 
 
10350
  Local<Object> with_js_getter = CompileRun(
 
10351
      "o = {};\n"
 
10352
      "o.__defineGetter__('f', function() { throw undefined; });\n"
 
10353
      "o\n").As<Object>();
 
10354
  CHECK(!with_js_getter.IsEmpty());
 
10355
 
 
10356
  TryCatch try_catch;
 
10357
 
 
10358
  Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
 
10359
  CHECK(try_catch.HasCaught());
 
10360
  try_catch.Reset();
 
10361
  CHECK(result.IsEmpty());
 
10362
 
 
10363
  result = another->GetRealNamedProperty(v8_str("f"));
 
10364
  CHECK(try_catch.HasCaught());
 
10365
  try_catch.Reset();
 
10366
  CHECK(result.IsEmpty());
 
10367
 
 
10368
  result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
 
10369
  CHECK(try_catch.HasCaught());
 
10370
  try_catch.Reset();
 
10371
  CHECK(result.IsEmpty());
 
10372
 
 
10373
  result = another->Get(v8_str("f"));
 
10374
  CHECK(try_catch.HasCaught());
 
10375
  try_catch.Reset();
 
10376
  CHECK(result.IsEmpty());
 
10377
 
 
10378
  result = with_js_getter->GetRealNamedProperty(v8_str("f"));
 
10379
  CHECK(try_catch.HasCaught());
 
10380
  try_catch.Reset();
 
10381
  CHECK(result.IsEmpty());
 
10382
 
 
10383
  result = with_js_getter->Get(v8_str("f"));
 
10384
  CHECK(try_catch.HasCaught());
 
10385
  try_catch.Reset();
 
10386
  CHECK(result.IsEmpty());
 
10387
}
 
10388
 
 
10389
 
 
10390
static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
 
10391
  TryCatch try_catch;
 
10392
  // Verboseness is important: it triggers message delivery which can call into
 
10393
  // external code.
 
10394
  try_catch.SetVerbose(true);
 
10395
  CompileRun("throw 'from JS';");
 
10396
  CHECK(try_catch.HasCaught());
 
10397
  CHECK(!i::Isolate::Current()->has_pending_exception());
 
10398
  CHECK(!i::Isolate::Current()->has_scheduled_exception());
 
10399
  return Undefined();
 
10400
}
 
10401
 
 
10402
 
 
10403
static int call_depth;
 
10404
 
 
10405
 
 
10406
static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
 
10407
  TryCatch try_catch;
 
10408
}
 
10409
 
 
10410
 
 
10411
static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
 
10412
  if (--call_depth) CompileRun("throw 'ThrowInJS';");
 
10413
}
 
10414
 
 
10415
 
 
10416
static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
 
10417
  if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
 
10418
}
 
10419
 
 
10420
 
 
10421
static void WebKitLike(Handle<Message> message, Handle<Value> data) {
 
10422
  Handle<String> errorMessageString = message->Get();
 
10423
  CHECK(!errorMessageString.IsEmpty());
 
10424
  message->GetStackTrace();
 
10425
  message->GetScriptResourceName();
 
10426
}
 
10427
 
 
10428
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
 
10429
  HandleScope scope;
 
10430
  LocalContext context;
 
10431
 
 
10432
  Local<Function> func =
 
10433
      FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
 
10434
  context->Global()->Set(v8_str("func"), func);
 
10435
 
 
10436
  MessageCallback callbacks[] =
 
10437
      { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
 
10438
  for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
 
10439
    MessageCallback callback = callbacks[i];
 
10440
    if (callback != NULL) {
 
10441
      V8::AddMessageListener(callback);
 
10442
    }
 
10443
    // Some small number to control number of times message handler should
 
10444
    // throw an exception.
 
10445
    call_depth = 5;
 
10446
    ExpectFalse(
 
10447
        "var thrown = false;\n"
 
10448
        "try { func(); } catch(e) { thrown = true; }\n"
 
10449
        "thrown\n");
 
10450
    if (callback != NULL) {
 
10451
      V8::RemoveMessageListeners(callback);
 
10452
    }
 
10453
  }
 
10454
}
 
10455
 
 
10456
 
 
10457
static v8::Handle<Value> ParentGetter(Local<String> name,
 
10458
                                      const AccessorInfo& info) {
 
10459
  ApiTestFuzzer::Fuzz();
 
10460
  return v8_num(1);
 
10461
}
 
10462
 
 
10463
 
 
10464
static v8::Handle<Value> ChildGetter(Local<String> name,
 
10465
                                     const AccessorInfo& info) {
 
10466
  ApiTestFuzzer::Fuzz();
 
10467
  return v8_num(42);
 
10468
}
 
10469
 
 
10470
 
 
10471
THREADED_TEST(Overriding) {
 
10472
  i::FLAG_es5_readonly = true;
 
10473
  v8::HandleScope scope;
 
10474
  LocalContext context;
 
10475
 
 
10476
  // Parent template.
 
10477
  Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
 
10478
  Local<ObjectTemplate> parent_instance_templ =
 
10479
      parent_templ->InstanceTemplate();
 
10480
  parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
 
10481
 
 
10482
  // Template that inherits from the parent template.
 
10483
  Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
 
10484
  Local<ObjectTemplate> child_instance_templ =
 
10485
      child_templ->InstanceTemplate();
 
10486
  child_templ->Inherit(parent_templ);
 
10487
  // Override 'f'.  The child version of 'f' should get called for child
 
10488
  // instances.
 
10489
  child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
 
10490
  // Add 'g' twice.  The 'g' added last should get called for instances.
 
10491
  child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
 
10492
  child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
 
10493
 
 
10494
  // Add 'h' as an accessor to the proto template with ReadOnly attributes
 
10495
  // so 'h' can be shadowed on the instance object.
 
10496
  Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
 
10497
  child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
 
10498
      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
 
10499
 
 
10500
  // Add 'i' as an accessor to the instance template with ReadOnly attributes
 
10501
  // but the attribute does not have effect because it is duplicated with
 
10502
  // NULL setter.
 
10503
  child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
 
10504
      v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
 
10505
 
 
10506
 
 
10507
 
 
10508
  // Instantiate the child template.
 
10509
  Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
 
10510
 
 
10511
  // Check that the child function overrides the parent one.
 
10512
  context->Global()->Set(v8_str("o"), instance);
 
10513
  Local<Value> value = v8_compile("o.f")->Run();
 
10514
  // Check that the 'g' that was added last is hit.
 
10515
  CHECK_EQ(42, value->Int32Value());
 
10516
  value = v8_compile("o.g")->Run();
 
10517
  CHECK_EQ(42, value->Int32Value());
 
10518
 
 
10519
  // Check that 'h' cannot be shadowed.
 
10520
  value = v8_compile("o.h = 3; o.h")->Run();
 
10521
  CHECK_EQ(1, value->Int32Value());
 
10522
 
 
10523
  // Check that 'i' cannot be shadowed or changed.
 
10524
  value = v8_compile("o.i = 3; o.i")->Run();
 
10525
  CHECK_EQ(42, value->Int32Value());
 
10526
}
 
10527
 
 
10528
 
 
10529
static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
 
10530
  ApiTestFuzzer::Fuzz();
 
10531
  return v8::Boolean::New(args.IsConstructCall());
 
10532
}
 
10533
 
 
10534
 
 
10535
THREADED_TEST(IsConstructCall) {
 
10536
  v8::HandleScope scope;
 
10537
 
 
10538
  // Function template with call handler.
 
10539
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
10540
  templ->SetCallHandler(IsConstructHandler);
 
10541
 
 
10542
  LocalContext context;
 
10543
 
 
10544
  context->Global()->Set(v8_str("f"), templ->GetFunction());
 
10545
  Local<Value> value = v8_compile("f()")->Run();
 
10546
  CHECK(!value->BooleanValue());
 
10547
  value = v8_compile("new f()")->Run();
 
10548
  CHECK(value->BooleanValue());
 
10549
}
 
10550
 
 
10551
 
 
10552
THREADED_TEST(ObjectProtoToString) {
 
10553
  v8::HandleScope scope;
 
10554
  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
 
10555
  templ->SetClassName(v8_str("MyClass"));
 
10556
 
 
10557
  LocalContext context;
 
10558
 
 
10559
  Local<String> customized_tostring = v8_str("customized toString");
 
10560
 
 
10561
  // Replace Object.prototype.toString
 
10562
  v8_compile("Object.prototype.toString = function() {"
 
10563
                  "  return 'customized toString';"
 
10564
                  "}")->Run();
 
10565
 
 
10566
  // Normal ToString call should call replaced Object.prototype.toString
 
10567
  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
 
10568
  Local<String> value = instance->ToString();
 
10569
  CHECK(value->IsString() && value->Equals(customized_tostring));
 
10570
 
 
10571
  // ObjectProtoToString should not call replace toString function.
 
10572
  value = instance->ObjectProtoToString();
 
10573
  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
 
10574
 
 
10575
  // Check global
 
10576
  value = context->Global()->ObjectProtoToString();
 
10577
  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
 
10578
 
 
10579
  // Check ordinary object
 
10580
  Local<Value> object = v8_compile("new Object()")->Run();
 
10581
  value = object.As<v8::Object>()->ObjectProtoToString();
 
10582
  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
 
10583
}
 
10584
 
 
10585
 
 
10586
THREADED_TEST(ObjectGetConstructorName) {
 
10587
  v8::HandleScope scope;
 
10588
  LocalContext context;
 
10589
  v8_compile("function Parent() {};"
 
10590
             "function Child() {};"
 
10591
             "Child.prototype = new Parent();"
 
10592
             "var outer = { inner: function() { } };"
 
10593
             "var p = new Parent();"
 
10594
             "var c = new Child();"
 
10595
             "var x = new outer.inner();")->Run();
 
10596
 
 
10597
  Local<v8::Value> p = context->Global()->Get(v8_str("p"));
 
10598
  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
 
10599
      v8_str("Parent")));
 
10600
 
 
10601
  Local<v8::Value> c = context->Global()->Get(v8_str("c"));
 
10602
  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
 
10603
      v8_str("Child")));
 
10604
 
 
10605
  Local<v8::Value> x = context->Global()->Get(v8_str("x"));
 
10606
  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
 
10607
      v8_str("outer.inner")));
 
10608
}
 
10609
 
 
10610
 
 
10611
bool ApiTestFuzzer::fuzzing_ = false;
 
10612
i::Semaphore* ApiTestFuzzer::all_tests_done_=
 
10613
  i::OS::CreateSemaphore(0);
 
10614
int ApiTestFuzzer::active_tests_;
 
10615
int ApiTestFuzzer::tests_being_run_;
 
10616
int ApiTestFuzzer::current_;
 
10617
 
 
10618
 
 
10619
// We are in a callback and want to switch to another thread (if we
 
10620
// are currently running the thread fuzzing test).
 
10621
void ApiTestFuzzer::Fuzz() {
 
10622
  if (!fuzzing_) return;
 
10623
  ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
 
10624
  test->ContextSwitch();
 
10625
}
 
10626
 
 
10627
 
 
10628
// Let the next thread go.  Since it is also waiting on the V8 lock it may
 
10629
// not start immediately.
 
10630
bool ApiTestFuzzer::NextThread() {
 
10631
  int test_position = GetNextTestNumber();
 
10632
  const char* test_name = RegisterThreadedTest::nth(current_)->name();
 
10633
  if (test_position == current_) {
 
10634
    if (kLogThreading)
 
10635
      printf("Stay with %s\n", test_name);
 
10636
    return false;
 
10637
  }
 
10638
  if (kLogThreading) {
 
10639
    printf("Switch from %s to %s\n",
 
10640
           test_name,
 
10641
           RegisterThreadedTest::nth(test_position)->name());
 
10642
  }
 
10643
  current_ = test_position;
 
10644
  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
 
10645
  return true;
 
10646
}
 
10647
 
 
10648
 
 
10649
void ApiTestFuzzer::Run() {
 
10650
  // When it is our turn...
 
10651
  gate_->Wait();
 
10652
  {
 
10653
    // ... get the V8 lock and start running the test.
 
10654
    v8::Locker locker;
 
10655
    CallTest();
 
10656
  }
 
10657
  // This test finished.
 
10658
  active_ = false;
 
10659
  active_tests_--;
 
10660
  // If it was the last then signal that fact.
 
10661
  if (active_tests_ == 0) {
 
10662
    all_tests_done_->Signal();
 
10663
  } else {
 
10664
    // Otherwise select a new test and start that.
 
10665
    NextThread();
 
10666
  }
 
10667
}
 
10668
 
 
10669
 
 
10670
static unsigned linear_congruential_generator;
 
10671
 
 
10672
 
 
10673
void ApiTestFuzzer::SetUp(PartOfTest part) {
 
10674
  linear_congruential_generator = i::FLAG_testing_prng_seed;
 
10675
  fuzzing_ = true;
 
10676
  int count = RegisterThreadedTest::count();
 
10677
  int start =  count * part / (LAST_PART + 1);
 
10678
  int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
 
10679
  active_tests_ = tests_being_run_ = end - start + 1;
 
10680
  for (int i = 0; i < tests_being_run_; i++) {
 
10681
    RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
 
10682
  }
 
10683
  for (int i = 0; i < active_tests_; i++) {
 
10684
    RegisterThreadedTest::nth(i)->fuzzer_->Start();
 
10685
  }
 
10686
}
 
10687
 
 
10688
 
 
10689
static void CallTestNumber(int test_number) {
 
10690
  (RegisterThreadedTest::nth(test_number)->callback())();
 
10691
}
 
10692
 
 
10693
 
 
10694
void ApiTestFuzzer::RunAllTests() {
 
10695
  // Set off the first test.
 
10696
  current_ = -1;
 
10697
  NextThread();
 
10698
  // Wait till they are all done.
 
10699
  all_tests_done_->Wait();
 
10700
}
 
10701
 
 
10702
 
 
10703
int ApiTestFuzzer::GetNextTestNumber() {
 
10704
  int next_test;
 
10705
  do {
 
10706
    next_test = (linear_congruential_generator >> 16) % tests_being_run_;
 
10707
    linear_congruential_generator *= 1664525u;
 
10708
    linear_congruential_generator += 1013904223u;
 
10709
  } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
 
10710
  return next_test;
 
10711
}
 
10712
 
 
10713
 
 
10714
void ApiTestFuzzer::ContextSwitch() {
 
10715
  // If the new thread is the same as the current thread there is nothing to do.
 
10716
  if (NextThread()) {
 
10717
    // Now it can start.
 
10718
    v8::Unlocker unlocker;
 
10719
    // Wait till someone starts us again.
 
10720
    gate_->Wait();
 
10721
    // And we're off.
 
10722
  }
 
10723
}
 
10724
 
 
10725
 
 
10726
void ApiTestFuzzer::TearDown() {
 
10727
  fuzzing_ = false;
 
10728
  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
 
10729
    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
 
10730
    if (fuzzer != NULL) fuzzer->Join();
 
10731
  }
 
10732
}
 
10733
 
 
10734
 
 
10735
// Lets not be needlessly self-referential.
 
10736
TEST(Threading) {
 
10737
  ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
 
10738
  ApiTestFuzzer::RunAllTests();
 
10739
  ApiTestFuzzer::TearDown();
 
10740
}
 
10741
 
 
10742
TEST(Threading2) {
 
10743
  ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
 
10744
  ApiTestFuzzer::RunAllTests();
 
10745
  ApiTestFuzzer::TearDown();
 
10746
}
 
10747
 
 
10748
TEST(Threading3) {
 
10749
  ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
 
10750
  ApiTestFuzzer::RunAllTests();
 
10751
  ApiTestFuzzer::TearDown();
 
10752
}
 
10753
 
 
10754
TEST(Threading4) {
 
10755
  ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
 
10756
  ApiTestFuzzer::RunAllTests();
 
10757
  ApiTestFuzzer::TearDown();
 
10758
}
 
10759
 
 
10760
void ApiTestFuzzer::CallTest() {
 
10761
  if (kLogThreading)
 
10762
    printf("Start test %d\n", test_number_);
 
10763
  CallTestNumber(test_number_);
 
10764
  if (kLogThreading)
 
10765
    printf("End test %d\n", test_number_);
 
10766
}
 
10767
 
 
10768
 
 
10769
static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
 
10770
  CHECK(v8::Locker::IsLocked());
 
10771
  ApiTestFuzzer::Fuzz();
 
10772
  v8::Unlocker unlocker;
 
10773
  const char* code = "throw 7;";
 
10774
  {
 
10775
    v8::Locker nested_locker;
 
10776
    v8::HandleScope scope;
 
10777
    v8::Handle<Value> exception;
 
10778
    { v8::TryCatch try_catch;
 
10779
      v8::Handle<Value> value = CompileRun(code);
 
10780
      CHECK(value.IsEmpty());
 
10781
      CHECK(try_catch.HasCaught());
 
10782
      // Make sure to wrap the exception in a new handle because
 
10783
      // the handle returned from the TryCatch is destroyed
 
10784
      // when the TryCatch is destroyed.
 
10785
      exception = Local<Value>::New(try_catch.Exception());
 
10786
    }
 
10787
    return v8::ThrowException(exception);
 
10788
  }
 
10789
}
 
10790
 
 
10791
 
 
10792
static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
 
10793
  CHECK(v8::Locker::IsLocked());
 
10794
  ApiTestFuzzer::Fuzz();
 
10795
  v8::Unlocker unlocker;
 
10796
  const char* code = "throw 7;";
 
10797
  {
 
10798
    v8::Locker nested_locker;
 
10799
    v8::HandleScope scope;
 
10800
    v8::Handle<Value> value = CompileRun(code);
 
10801
    CHECK(value.IsEmpty());
 
10802
    return v8_str("foo");
 
10803
  }
 
10804
}
 
10805
 
 
10806
 
 
10807
// These are locking tests that don't need to be run again
 
10808
// as part of the locking aggregation tests.
 
10809
TEST(NestedLockers) {
 
10810
  v8::Locker locker;
 
10811
  CHECK(v8::Locker::IsLocked());
 
10812
  v8::HandleScope scope;
 
10813
  LocalContext env;
 
10814
  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
 
10815
  Local<Function> fun = fun_templ->GetFunction();
 
10816
  env->Global()->Set(v8_str("throw_in_js"), fun);
 
10817
  Local<Script> script = v8_compile("(function () {"
 
10818
                                    "  try {"
 
10819
                                    "    throw_in_js();"
 
10820
                                    "    return 42;"
 
10821
                                    "  } catch (e) {"
 
10822
                                    "    return e * 13;"
 
10823
                                    "  }"
 
10824
                                    "})();");
 
10825
  CHECK_EQ(91, script->Run()->Int32Value());
 
10826
}
 
10827
 
 
10828
 
 
10829
// These are locking tests that don't need to be run again
 
10830
// as part of the locking aggregation tests.
 
10831
TEST(NestedLockersNoTryCatch) {
 
10832
  v8::Locker locker;
 
10833
  v8::HandleScope scope;
 
10834
  LocalContext env;
 
10835
  Local<v8::FunctionTemplate> fun_templ =
 
10836
      v8::FunctionTemplate::New(ThrowInJSNoCatch);
 
10837
  Local<Function> fun = fun_templ->GetFunction();
 
10838
  env->Global()->Set(v8_str("throw_in_js"), fun);
 
10839
  Local<Script> script = v8_compile("(function () {"
 
10840
                                    "  try {"
 
10841
                                    "    throw_in_js();"
 
10842
                                    "    return 42;"
 
10843
                                    "  } catch (e) {"
 
10844
                                    "    return e * 13;"
 
10845
                                    "  }"
 
10846
                                    "})();");
 
10847
  CHECK_EQ(91, script->Run()->Int32Value());
 
10848
}
 
10849
 
 
10850
 
 
10851
THREADED_TEST(RecursiveLocking) {
 
10852
  v8::Locker locker;
 
10853
  {
 
10854
    v8::Locker locker2;
 
10855
    CHECK(v8::Locker::IsLocked());
 
10856
  }
 
10857
}
 
10858
 
 
10859
 
 
10860
static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
 
10861
  ApiTestFuzzer::Fuzz();
 
10862
  v8::Unlocker unlocker;
 
10863
  return v8::Undefined();
 
10864
}
 
10865
 
 
10866
 
 
10867
THREADED_TEST(LockUnlockLock) {
 
10868
  {
 
10869
    v8::Locker locker;
 
10870
    v8::HandleScope scope;
 
10871
    LocalContext env;
 
10872
    Local<v8::FunctionTemplate> fun_templ =
 
10873
        v8::FunctionTemplate::New(UnlockForAMoment);
 
10874
    Local<Function> fun = fun_templ->GetFunction();
 
10875
    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
 
10876
    Local<Script> script = v8_compile("(function () {"
 
10877
                                      "  unlock_for_a_moment();"
 
10878
                                      "  return 42;"
 
10879
                                      "})();");
 
10880
    CHECK_EQ(42, script->Run()->Int32Value());
 
10881
  }
 
10882
  {
 
10883
    v8::Locker locker;
 
10884
    v8::HandleScope scope;
 
10885
    LocalContext env;
 
10886
    Local<v8::FunctionTemplate> fun_templ =
 
10887
        v8::FunctionTemplate::New(UnlockForAMoment);
 
10888
    Local<Function> fun = fun_templ->GetFunction();
 
10889
    env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
 
10890
    Local<Script> script = v8_compile("(function () {"
 
10891
                                      "  unlock_for_a_moment();"
 
10892
                                      "  return 42;"
 
10893
                                      "})();");
 
10894
    CHECK_EQ(42, script->Run()->Int32Value());
 
10895
  }
 
10896
}
 
10897
 
 
10898
 
 
10899
static int GetGlobalObjectsCount() {
 
10900
  i::Isolate::Current()->heap()->EnsureHeapIsIterable();
 
10901
  int count = 0;
 
10902
  i::HeapIterator it;
 
10903
  for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
 
10904
    if (object->IsJSGlobalObject()) count++;
 
10905
  return count;
 
10906
}
 
10907
 
 
10908
 
 
10909
static void CheckSurvivingGlobalObjectsCount(int expected) {
 
10910
  // We need to collect all garbage twice to be sure that everything
 
10911
  // has been collected.  This is because inline caches are cleared in
 
10912
  // the first garbage collection but some of the maps have already
 
10913
  // been marked at that point.  Therefore some of the maps are not
 
10914
  // collected until the second garbage collection.
 
10915
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
10916
  HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
 
10917
  int count = GetGlobalObjectsCount();
 
10918
#ifdef DEBUG
 
10919
  if (count != expected) HEAP->TracePathToGlobal();
 
10920
#endif
 
10921
  CHECK_EQ(expected, count);
 
10922
}
 
10923
 
 
10924
 
 
10925
TEST(DontLeakGlobalObjects) {
 
10926
  // Regression test for issues 1139850 and 1174891.
 
10927
 
 
10928
  v8::V8::Initialize();
 
10929
 
 
10930
  for (int i = 0; i < 5; i++) {
 
10931
    { v8::HandleScope scope;
 
10932
      LocalContext context;
 
10933
    }
 
10934
    v8::V8::ContextDisposedNotification();
 
10935
    CheckSurvivingGlobalObjectsCount(0);
 
10936
 
 
10937
    { v8::HandleScope scope;
 
10938
      LocalContext context;
 
10939
      v8_compile("Date")->Run();
 
10940
    }
 
10941
    v8::V8::ContextDisposedNotification();
 
10942
    CheckSurvivingGlobalObjectsCount(0);
 
10943
 
 
10944
    { v8::HandleScope scope;
 
10945
      LocalContext context;
 
10946
      v8_compile("/aaa/")->Run();
 
10947
    }
 
10948
    v8::V8::ContextDisposedNotification();
 
10949
    CheckSurvivingGlobalObjectsCount(0);
 
10950
 
 
10951
    { v8::HandleScope scope;
 
10952
      const char* extension_list[] = { "v8/gc" };
 
10953
      v8::ExtensionConfiguration extensions(1, extension_list);
 
10954
      LocalContext context(&extensions);
 
10955
      v8_compile("gc();")->Run();
 
10956
    }
 
10957
    v8::V8::ContextDisposedNotification();
 
10958
    CheckSurvivingGlobalObjectsCount(0);
 
10959
  }
 
10960
}
 
10961
 
 
10962
 
 
10963
v8::Persistent<v8::Object> some_object;
 
10964
v8::Persistent<v8::Object> bad_handle;
 
10965
 
 
10966
void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
 
10967
  v8::HandleScope scope;
 
10968
  bad_handle = v8::Persistent<v8::Object>::New(some_object);
 
10969
  handle.Dispose();
 
10970
}
 
10971
 
 
10972
 
 
10973
THREADED_TEST(NewPersistentHandleFromWeakCallback) {
 
10974
  LocalContext context;
 
10975
 
 
10976
  v8::Persistent<v8::Object> handle1, handle2;
 
10977
  {
 
10978
    v8::HandleScope scope;
 
10979
    some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
 
10980
    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
10981
    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
10982
  }
 
10983
  // Note: order is implementation dependent alas: currently
 
10984
  // global handle nodes are processed by PostGarbageCollectionProcessing
 
10985
  // in reverse allocation order, so if second allocated handle is deleted,
 
10986
  // weak callback of the first handle would be able to 'reallocate' it.
 
10987
  handle1.MakeWeak(NULL, NewPersistentHandleCallback);
 
10988
  handle2.Dispose();
 
10989
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
10990
}
 
10991
 
 
10992
 
 
10993
v8::Persistent<v8::Object> to_be_disposed;
 
10994
 
 
10995
void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
 
10996
  to_be_disposed.Dispose();
 
10997
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
10998
  handle.Dispose();
 
10999
}
 
11000
 
 
11001
 
 
11002
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
 
11003
  LocalContext context;
 
11004
 
 
11005
  v8::Persistent<v8::Object> handle1, handle2;
 
11006
  {
 
11007
    v8::HandleScope scope;
 
11008
    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
11009
    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
11010
  }
 
11011
  handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
 
11012
  to_be_disposed = handle2;
 
11013
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
11014
}
 
11015
 
 
11016
void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
 
11017
  handle.Dispose();
 
11018
}
 
11019
 
 
11020
void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
 
11021
  v8::HandleScope scope;
 
11022
  v8::Persistent<v8::Object>::New(v8::Object::New());
 
11023
  handle.Dispose();
 
11024
}
 
11025
 
 
11026
 
 
11027
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
 
11028
  LocalContext context;
 
11029
 
 
11030
  v8::Persistent<v8::Object> handle1, handle2, handle3;
 
11031
  {
 
11032
    v8::HandleScope scope;
 
11033
    handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
11034
    handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
11035
    handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
 
11036
  }
 
11037
  handle2.MakeWeak(NULL, DisposingCallback);
 
11038
  handle3.MakeWeak(NULL, HandleCreatingCallback);
 
11039
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
11040
}
 
11041
 
 
11042
 
 
11043
THREADED_TEST(CheckForCrossContextObjectLiterals) {
 
11044
  v8::V8::Initialize();
 
11045
 
 
11046
  const int nof = 2;
 
11047
  const char* sources[nof] = {
 
11048
    "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
 
11049
    "Object()"
 
11050
  };
 
11051
 
 
11052
  for (int i = 0; i < nof; i++) {
 
11053
    const char* source = sources[i];
 
11054
    { v8::HandleScope scope;
 
11055
      LocalContext context;
 
11056
      CompileRun(source);
 
11057
    }
 
11058
    { v8::HandleScope scope;
 
11059
      LocalContext context;
 
11060
      CompileRun(source);
 
11061
    }
 
11062
  }
 
11063
}
 
11064
 
 
11065
 
 
11066
static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
 
11067
  v8::HandleScope inner;
 
11068
  env->Enter();
 
11069
  v8::Handle<Value> three = v8_num(3);
 
11070
  v8::Handle<Value> value = inner.Close(three);
 
11071
  env->Exit();
 
11072
  return value;
 
11073
}
 
11074
 
 
11075
 
 
11076
THREADED_TEST(NestedHandleScopeAndContexts) {
 
11077
  v8::HandleScope outer;
 
11078
  v8::Persistent<Context> env = Context::New();
 
11079
  env->Enter();
 
11080
  v8::Handle<Value> value = NestedScope(env);
 
11081
  v8::Handle<String> str(value->ToString());
 
11082
  CHECK(!str.IsEmpty());
 
11083
  env->Exit();
 
11084
  env.Dispose();
 
11085
}
 
11086
 
 
11087
 
 
11088
static i::Handle<i::JSFunction>* foo_ptr = NULL;
 
11089
static int foo_count = 0;
 
11090
static i::Handle<i::JSFunction>* bar_ptr = NULL;
 
11091
static int bar_count = 0;
 
11092
 
 
11093
 
 
11094
static void entry_hook(uintptr_t function,
 
11095
                       uintptr_t return_addr_location) {
 
11096
  i::Code* code = i::Code::GetCodeFromTargetAddress(
 
11097
      reinterpret_cast<i::Address>(function));
 
11098
  CHECK(code != NULL);
 
11099
 
 
11100
  if (bar_ptr != NULL && code == (*bar_ptr)->code())
 
11101
    ++bar_count;
 
11102
 
 
11103
  if (foo_ptr != NULL && code == (*foo_ptr)->code())
 
11104
    ++foo_count;
 
11105
 
 
11106
  // TODO(siggi): Verify return_addr_location.
 
11107
  //     This can be done by capturing JitCodeEvents, but requires an ordered
 
11108
  //     collection.
 
11109
}
 
11110
 
 
11111
 
 
11112
static void RunLoopInNewEnv() {
 
11113
  bar_ptr = NULL;
 
11114
  foo_ptr = NULL;
 
11115
 
 
11116
  v8::HandleScope outer;
 
11117
  v8::Persistent<Context> env = Context::New();
 
11118
  env->Enter();
 
11119
 
 
11120
  const char* script =
 
11121
      "function bar() {"
 
11122
      "  var sum = 0;"
 
11123
      "  for (i = 0; i < 100; ++i)"
 
11124
      "    sum = foo(i);"
 
11125
      "  return sum;"
 
11126
      "}"
 
11127
      "function foo(i) { return i * i; }";
 
11128
  CompileRun(script);
 
11129
  i::Handle<i::JSFunction> bar =
 
11130
      i::Handle<i::JSFunction>::cast(
 
11131
          v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
 
11132
  ASSERT(*bar);
 
11133
 
 
11134
  i::Handle<i::JSFunction> foo =
 
11135
      i::Handle<i::JSFunction>::cast(
 
11136
           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
 
11137
  ASSERT(*foo);
 
11138
 
 
11139
  bar_ptr = &bar;
 
11140
  foo_ptr = &foo;
 
11141
 
 
11142
  v8::Handle<v8::Value> value = CompileRun("bar();");
 
11143
  CHECK(value->IsNumber());
 
11144
  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
 
11145
 
 
11146
  // Test the optimized codegen path.
 
11147
  value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
 
11148
                     "bar();");
 
11149
  CHECK(value->IsNumber());
 
11150
  CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
 
11151
 
 
11152
  env->Exit();
 
11153
}
 
11154
 
 
11155
 
 
11156
TEST(SetFunctionEntryHook) {
 
11157
  i::FLAG_allow_natives_syntax = true;
 
11158
 
 
11159
  // Test setting and resetting the entry hook.
 
11160
  // Nulling it should always succeed.
 
11161
  CHECK(v8::V8::SetFunctionEntryHook(NULL));
 
11162
 
 
11163
  CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
 
11164
  // Setting a hook while one's active should fail.
 
11165
  CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
 
11166
 
 
11167
  CHECK(v8::V8::SetFunctionEntryHook(NULL));
 
11168
 
 
11169
  // Reset the entry count to zero and set the entry hook.
 
11170
  bar_count = 0;
 
11171
  foo_count = 0;
 
11172
  CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
 
11173
  RunLoopInNewEnv();
 
11174
 
 
11175
  CHECK_EQ(2, bar_count);
 
11176
  CHECK_EQ(200, foo_count);
 
11177
 
 
11178
  // Clear the entry hook and count.
 
11179
  bar_count = 0;
 
11180
  foo_count = 0;
 
11181
  v8::V8::SetFunctionEntryHook(NULL);
 
11182
 
 
11183
  // Clear the compilation cache to make sure we don't reuse the
 
11184
  // functions from the previous invocation.
 
11185
  v8::internal::Isolate::Current()->compilation_cache()->Clear();
 
11186
 
 
11187
  // Verify that entry hooking is now disabled.
 
11188
  RunLoopInNewEnv();
 
11189
  CHECK_EQ(0u, bar_count);
 
11190
  CHECK_EQ(0u, foo_count);
 
11191
}
 
11192
 
 
11193
 
 
11194
static i::HashMap* code_map = NULL;
 
11195
static int saw_bar = 0;
 
11196
static int move_events = 0;
 
11197
 
 
11198
 
 
11199
static bool FunctionNameIs(const char* expected,
 
11200
                           const v8::JitCodeEvent* event) {
 
11201
  // Log lines for functions are of the general form:
 
11202
  // "LazyCompile:<type><function_name>", where the type is one of
 
11203
  // "*", "~" or "".
 
11204
  static const char kPreamble[] = "LazyCompile:";
 
11205
  static size_t kPreambleLen = sizeof(kPreamble) - 1;
 
11206
 
 
11207
  if (event->name.len < sizeof(kPreamble) - 1 ||
 
11208
      strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
 
11209
    return false;
 
11210
  }
 
11211
 
 
11212
  const char* tail = event->name.str + kPreambleLen;
 
11213
  size_t tail_len = event->name.len - kPreambleLen;
 
11214
  size_t expected_len = strlen(expected);
 
11215
  if (tail_len == expected_len + 1) {
 
11216
    if (*tail == '*' || *tail == '~') {
 
11217
      --tail_len;
 
11218
      ++tail;
 
11219
    } else {
 
11220
      return false;
 
11221
    }
 
11222
  }
 
11223
 
 
11224
  if (tail_len != expected_len)
 
11225
    return false;
 
11226
 
 
11227
  return strncmp(tail, expected, expected_len) == 0;
 
11228
}
 
11229
 
 
11230
 
 
11231
static void event_handler(const v8::JitCodeEvent* event) {
 
11232
  CHECK(event != NULL);
 
11233
  CHECK(code_map != NULL);
 
11234
 
 
11235
  switch (event->type) {
 
11236
    case v8::JitCodeEvent::CODE_ADDED: {
 
11237
        CHECK(event->code_start != NULL);
 
11238
        CHECK_NE(0, static_cast<int>(event->code_len));
 
11239
        CHECK(event->name.str != NULL);
 
11240
        i::HashMap::Entry* entry =
 
11241
            code_map->Lookup(event->code_start,
 
11242
                             i::ComputePointerHash(event->code_start),
 
11243
                             true);
 
11244
        entry->value = reinterpret_cast<void*>(event->code_len);
 
11245
 
 
11246
        if (FunctionNameIs("bar", event)) {
 
11247
          ++saw_bar;
 
11248
        }
 
11249
      }
 
11250
      break;
 
11251
 
 
11252
    case v8::JitCodeEvent::CODE_MOVED: {
 
11253
        uint32_t hash = i::ComputePointerHash(event->code_start);
 
11254
        // We would like to never see code move that we haven't seen before,
 
11255
        // but the code creation event does not happen until the line endings
 
11256
        // have been calculated (this is so that we can report the line in the
 
11257
        // script at which the function source is found, see
 
11258
        // Compiler::RecordFunctionCompilation) and the line endings
 
11259
        // calculations can cause a GC, which can move the newly created code
 
11260
        // before its existence can be logged.
 
11261
        i::HashMap::Entry* entry =
 
11262
            code_map->Lookup(event->code_start, hash, false);
 
11263
        if (entry != NULL) {
 
11264
          ++move_events;
 
11265
 
 
11266
          CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
 
11267
          code_map->Remove(event->code_start, hash);
 
11268
 
 
11269
          entry = code_map->Lookup(event->new_code_start,
 
11270
                                   i::ComputePointerHash(event->new_code_start),
 
11271
                                   true);
 
11272
          CHECK(entry != NULL);
 
11273
          entry->value = reinterpret_cast<void*>(event->code_len);
 
11274
        }
 
11275
      }
 
11276
      break;
 
11277
 
 
11278
    case v8::JitCodeEvent::CODE_REMOVED:
 
11279
      // Object/code removal events are currently not dispatched from the GC.
 
11280
      CHECK(false);
 
11281
      break;
 
11282
    default:
 
11283
      // Impossible event.
 
11284
      CHECK(false);
 
11285
      break;
 
11286
  }
 
11287
}
 
11288
 
 
11289
 
 
11290
// Implemented in the test-alloc.cc test suite.
 
11291
void SimulateFullSpace(i::PagedSpace* space);
 
11292
 
 
11293
 
 
11294
static bool MatchPointers(void* key1, void* key2) {
 
11295
  return key1 == key2;
 
11296
}
 
11297
 
 
11298
 
 
11299
TEST(SetJitCodeEventHandler) {
 
11300
  const char* script =
 
11301
    "function bar() {"
 
11302
    "  var sum = 0;"
 
11303
    "  for (i = 0; i < 100; ++i)"
 
11304
    "    sum = foo(i);"
 
11305
    "  return sum;"
 
11306
    "}"
 
11307
    "function foo(i) { return i * i; };"
 
11308
    "bar();";
 
11309
 
 
11310
  // Run this test in a new isolate to make sure we don't
 
11311
  // have remnants of state from other code.
 
11312
  v8::Isolate* isolate = v8::Isolate::New();
 
11313
  isolate->Enter();
 
11314
 
 
11315
  {
 
11316
    i::HashMap code(MatchPointers);
 
11317
    code_map = &code;
 
11318
 
 
11319
    saw_bar = 0;
 
11320
    move_events = 0;
 
11321
 
 
11322
    i::FLAG_stress_compaction = true;
 
11323
    V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
 
11324
 
 
11325
    v8::HandleScope scope;
 
11326
    // Generate new code objects sparsely distributed across several
 
11327
    // different fragmented code-space pages.
 
11328
    const int kIterations = 10;
 
11329
    for (int i = 0; i < kIterations; ++i) {
 
11330
      LocalContext env;
 
11331
 
 
11332
      v8::Handle<v8::Script> compiled_script;
 
11333
      {
 
11334
        i::AlwaysAllocateScope always_allocate;
 
11335
        SimulateFullSpace(HEAP->code_space());
 
11336
        compiled_script = v8_compile(script);
 
11337
      }
 
11338
      compiled_script->Run();
 
11339
 
 
11340
      // Clear the compilation cache to get more wastage.
 
11341
      ISOLATE->compilation_cache()->Clear();
 
11342
    }
 
11343
 
 
11344
    // Force code movement.
 
11345
    HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
 
11346
 
 
11347
    CHECK_LE(kIterations, saw_bar);
 
11348
    CHECK_NE(0, move_events);
 
11349
 
 
11350
    code_map = NULL;
 
11351
    V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
 
11352
  }
 
11353
 
 
11354
  isolate->Exit();
 
11355
  isolate->Dispose();
 
11356
 
 
11357
  // Do this in a new isolate.
 
11358
  isolate = v8::Isolate::New();
 
11359
  isolate->Enter();
 
11360
 
 
11361
  // Verify that we get callbacks for existing code objects when we
 
11362
  // request enumeration of existing code.
 
11363
  {
 
11364
    v8::HandleScope scope;
 
11365
    LocalContext env;
 
11366
    CompileRun(script);
 
11367
 
 
11368
    // Now get code through initial iteration.
 
11369
    i::HashMap code(MatchPointers);
 
11370
    code_map = &code;
 
11371
 
 
11372
    V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
 
11373
    V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
 
11374
 
 
11375
    code_map = NULL;
 
11376
 
 
11377
    // We expect that we got some events. Note that if we could get code removal
 
11378
    // notifications, we could compare two collections, one created by listening
 
11379
    // from the time of creation of an isolate, and the other by subscribing
 
11380
    // with EnumExisting.
 
11381
    CHECK_NE(0, code.occupancy());
 
11382
  }
 
11383
 
 
11384
  isolate->Exit();
 
11385
  isolate->Dispose();
 
11386
}
 
11387
 
 
11388
 
 
11389
static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
 
11390
 
 
11391
 
 
11392
THREADED_TEST(ExternalAllocatedMemory) {
 
11393
  v8::HandleScope outer;
 
11394
  v8::Persistent<Context> env(Context::New());
 
11395
  CHECK(!env.IsEmpty());
 
11396
  const intptr_t kSize = 1024*1024;
 
11397
  CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
 
11398
           cast(kSize));
 
11399
  CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
 
11400
           cast(0));
 
11401
}
 
11402
 
 
11403
 
 
11404
THREADED_TEST(DisposeEnteredContext) {
 
11405
  v8::HandleScope scope;
 
11406
  LocalContext outer;
 
11407
  { v8::Persistent<v8::Context> inner = v8::Context::New();
 
11408
    inner->Enter();
 
11409
    inner.Dispose();
 
11410
    inner.Clear();
 
11411
    inner->Exit();
 
11412
  }
 
11413
}
 
11414
 
 
11415
 
 
11416
// Regression test for issue 54, object templates with internal fields
 
11417
// but no accessors or interceptors did not get their internal field
 
11418
// count set on instances.
 
11419
THREADED_TEST(Regress54) {
 
11420
  v8::HandleScope outer;
 
11421
  LocalContext context;
 
11422
  static v8::Persistent<v8::ObjectTemplate> templ;
 
11423
  if (templ.IsEmpty()) {
 
11424
    v8::HandleScope inner;
 
11425
    v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
 
11426
    local->SetInternalFieldCount(1);
 
11427
    templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
 
11428
  }
 
11429
  v8::Handle<v8::Object> result = templ->NewInstance();
 
11430
  CHECK_EQ(1, result->InternalFieldCount());
 
11431
}
 
11432
 
 
11433
 
 
11434
// If part of the threaded tests, this test makes ThreadingTest fail
 
11435
// on mac.
 
11436
TEST(CatchStackOverflow) {
 
11437
  v8::HandleScope scope;
 
11438
  LocalContext context;
 
11439
  v8::TryCatch try_catch;
 
11440
  v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
 
11441
    "function f() {"
 
11442
    "  return f();"
 
11443
    "}"
 
11444
    ""
 
11445
    "f();"));
 
11446
  v8::Handle<v8::Value> result = script->Run();
 
11447
  CHECK(result.IsEmpty());
 
11448
}
 
11449
 
 
11450
 
 
11451
static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
 
11452
                                    const char* resource_name,
 
11453
                                    int line_offset) {
 
11454
  v8::HandleScope scope;
 
11455
  v8::TryCatch try_catch;
 
11456
  v8::Handle<v8::Value> result = script->Run();
 
11457
  CHECK(result.IsEmpty());
 
11458
  CHECK(try_catch.HasCaught());
 
11459
  v8::Handle<v8::Message> message = try_catch.Message();
 
11460
  CHECK(!message.IsEmpty());
 
11461
  CHECK_EQ(10 + line_offset, message->GetLineNumber());
 
11462
  CHECK_EQ(91, message->GetStartPosition());
 
11463
  CHECK_EQ(92, message->GetEndPosition());
 
11464
  CHECK_EQ(2, message->GetStartColumn());
 
11465
  CHECK_EQ(3, message->GetEndColumn());
 
11466
  v8::String::AsciiValue line(message->GetSourceLine());
 
11467
  CHECK_EQ("  throw 'nirk';", *line);
 
11468
  v8::String::AsciiValue name(message->GetScriptResourceName());
 
11469
  CHECK_EQ(resource_name, *name);
 
11470
}
 
11471
 
 
11472
 
 
11473
THREADED_TEST(TryCatchSourceInfo) {
 
11474
  v8::HandleScope scope;
 
11475
  LocalContext context;
 
11476
  v8::Handle<v8::String> source = v8::String::New(
 
11477
      "function Foo() {\n"
 
11478
      "  return Bar();\n"
 
11479
      "}\n"
 
11480
      "\n"
 
11481
      "function Bar() {\n"
 
11482
      "  return Baz();\n"
 
11483
      "}\n"
 
11484
      "\n"
 
11485
      "function Baz() {\n"
 
11486
      "  throw 'nirk';\n"
 
11487
      "}\n"
 
11488
      "\n"
 
11489
      "Foo();\n");
 
11490
 
 
11491
  const char* resource_name;
 
11492
  v8::Handle<v8::Script> script;
 
11493
  resource_name = "test.js";
 
11494
  script = v8::Script::Compile(source, v8::String::New(resource_name));
 
11495
  CheckTryCatchSourceInfo(script, resource_name, 0);
 
11496
 
 
11497
  resource_name = "test1.js";
 
11498
  v8::ScriptOrigin origin1(v8::String::New(resource_name));
 
11499
  script = v8::Script::Compile(source, &origin1);
 
11500
  CheckTryCatchSourceInfo(script, resource_name, 0);
 
11501
 
 
11502
  resource_name = "test2.js";
 
11503
  v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
 
11504
  script = v8::Script::Compile(source, &origin2);
 
11505
  CheckTryCatchSourceInfo(script, resource_name, 7);
 
11506
}
 
11507
 
 
11508
 
 
11509
THREADED_TEST(CompilationCache) {
 
11510
  v8::HandleScope scope;
 
11511
  LocalContext context;
 
11512
  v8::Handle<v8::String> source0 = v8::String::New("1234");
 
11513
  v8::Handle<v8::String> source1 = v8::String::New("1234");
 
11514
  v8::Handle<v8::Script> script0 =
 
11515
      v8::Script::Compile(source0, v8::String::New("test.js"));
 
11516
  v8::Handle<v8::Script> script1 =
 
11517
      v8::Script::Compile(source1, v8::String::New("test.js"));
 
11518
  v8::Handle<v8::Script> script2 =
 
11519
      v8::Script::Compile(source0);  // different origin
 
11520
  CHECK_EQ(1234, script0->Run()->Int32Value());
 
11521
  CHECK_EQ(1234, script1->Run()->Int32Value());
 
11522
  CHECK_EQ(1234, script2->Run()->Int32Value());
 
11523
}
 
11524
 
 
11525
 
 
11526
static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
 
11527
  ApiTestFuzzer::Fuzz();
 
11528
  return v8_num(42);
 
11529
}
 
11530
 
 
11531
 
 
11532
THREADED_TEST(CallbackFunctionName) {
 
11533
  v8::HandleScope scope;
 
11534
  LocalContext context;
 
11535
  Local<ObjectTemplate> t = ObjectTemplate::New();
 
11536
  t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
 
11537
  context->Global()->Set(v8_str("obj"), t->NewInstance());
 
11538
  v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
 
11539
  CHECK(value->IsString());
 
11540
  v8::String::AsciiValue name(value);
 
11541
  CHECK_EQ("asdf", *name);
 
11542
}
 
11543
 
 
11544
 
 
11545
THREADED_TEST(DateAccess) {
 
11546
  v8::HandleScope scope;
 
11547
  LocalContext context;
 
11548
  v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
 
11549
  CHECK(date->IsDate());
 
11550
  CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
 
11551
}
 
11552
 
 
11553
 
 
11554
void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
 
11555
  v8::Handle<v8::Object> obj = val.As<v8::Object>();
 
11556
  v8::Handle<v8::Array> props = obj->GetPropertyNames();
 
11557
  CHECK_EQ(elmc, props->Length());
 
11558
  for (int i = 0; i < elmc; i++) {
 
11559
    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
 
11560
    CHECK_EQ(elmv[i], *elm);
 
11561
  }
 
11562
}
 
11563
 
 
11564
 
 
11565
void CheckOwnProperties(v8::Handle<v8::Value> val,
 
11566
                        int elmc,
 
11567
                        const char* elmv[]) {
 
11568
  v8::Handle<v8::Object> obj = val.As<v8::Object>();
 
11569
  v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
 
11570
  CHECK_EQ(elmc, props->Length());
 
11571
  for (int i = 0; i < elmc; i++) {
 
11572
    v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
 
11573
    CHECK_EQ(elmv[i], *elm);
 
11574
  }
 
11575
}
 
11576
 
 
11577
 
 
11578
THREADED_TEST(PropertyEnumeration) {
 
11579
  v8::HandleScope scope;
 
11580
  LocalContext context;
 
11581
  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
 
11582
      "var result = [];"
 
11583
      "result[0] = {};"
 
11584
      "result[1] = {a: 1, b: 2};"
 
11585
      "result[2] = [1, 2, 3];"
 
11586
      "var proto = {x: 1, y: 2, z: 3};"
 
11587
      "var x = { __proto__: proto, w: 0, z: 1 };"
 
11588
      "result[3] = x;"
 
11589
      "result;"))->Run();
 
11590
  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
 
11591
  CHECK_EQ(4, elms->Length());
 
11592
  int elmc0 = 0;
 
11593
  const char** elmv0 = NULL;
 
11594
  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
 
11595
  CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
 
11596
  int elmc1 = 2;
 
11597
  const char* elmv1[] = {"a", "b"};
 
11598
  CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
 
11599
  CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
 
11600
  int elmc2 = 3;
 
11601
  const char* elmv2[] = {"0", "1", "2"};
 
11602
  CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
 
11603
  CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
 
11604
  int elmc3 = 4;
 
11605
  const char* elmv3[] = {"w", "z", "x", "y"};
 
11606
  CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
 
11607
  int elmc4 = 2;
 
11608
  const char* elmv4[] = {"w", "z"};
 
11609
  CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
 
11610
}
 
11611
 
 
11612
THREADED_TEST(PropertyEnumeration2) {
 
11613
  v8::HandleScope scope;
 
11614
  LocalContext context;
 
11615
  v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
 
11616
      "var result = [];"
 
11617
      "result[0] = {};"
 
11618
      "result[1] = {a: 1, b: 2};"
 
11619
      "result[2] = [1, 2, 3];"
 
11620
      "var proto = {x: 1, y: 2, z: 3};"
 
11621
      "var x = { __proto__: proto, w: 0, z: 1 };"
 
11622
      "result[3] = x;"
 
11623
      "result;"))->Run();
 
11624
  v8::Handle<v8::Array> elms = obj.As<v8::Array>();
 
11625
  CHECK_EQ(4, elms->Length());
 
11626
  int elmc0 = 0;
 
11627
  const char** elmv0 = NULL;
 
11628
  CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
 
11629
 
 
11630
  v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
 
11631
  v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
 
11632
  CHECK_EQ(0, props->Length());
 
11633
  for (uint32_t i = 0; i < props->Length(); i++) {
 
11634
    printf("p[%d]\n", i);
 
11635
  }
 
11636
}
 
11637
 
 
11638
static bool NamedSetAccessBlocker(Local<v8::Object> obj,
 
11639
                                  Local<Value> name,
 
11640
                                  v8::AccessType type,
 
11641
                                  Local<Value> data) {
 
11642
  return type != v8::ACCESS_SET;
 
11643
}
 
11644
 
 
11645
 
 
11646
static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
 
11647
                                    uint32_t key,
 
11648
                                    v8::AccessType type,
 
11649
                                    Local<Value> data) {
 
11650
  return type != v8::ACCESS_SET;
 
11651
}
 
11652
 
 
11653
 
 
11654
THREADED_TEST(DisableAccessChecksWhileConfiguring) {
 
11655
  v8::HandleScope scope;
 
11656
  LocalContext context;
 
11657
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
11658
  templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
 
11659
                                 IndexedSetAccessBlocker);
 
11660
  templ->Set(v8_str("x"), v8::True());
 
11661
  Local<v8::Object> instance = templ->NewInstance();
 
11662
  context->Global()->Set(v8_str("obj"), instance);
 
11663
  Local<Value> value = CompileRun("obj.x");
 
11664
  CHECK(value->BooleanValue());
 
11665
}
 
11666
 
 
11667
 
 
11668
static bool NamedGetAccessBlocker(Local<v8::Object> obj,
 
11669
                                  Local<Value> name,
 
11670
                                  v8::AccessType type,
 
11671
                                  Local<Value> data) {
 
11672
  return false;
 
11673
}
 
11674
 
 
11675
 
 
11676
static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
 
11677
                                    uint32_t key,
 
11678
                                    v8::AccessType type,
 
11679
                                    Local<Value> data) {
 
11680
  return false;
 
11681
}
 
11682
 
 
11683
 
 
11684
 
 
11685
THREADED_TEST(AccessChecksReenabledCorrectly) {
 
11686
  v8::HandleScope scope;
 
11687
  LocalContext context;
 
11688
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
11689
  templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
 
11690
                                 IndexedGetAccessBlocker);
 
11691
  templ->Set(v8_str("a"), v8_str("a"));
 
11692
  // Add more than 8 (see kMaxFastProperties) properties
 
11693
  // so that the constructor will force copying map.
 
11694
  // Cannot sprintf, gcc complains unsafety.
 
11695
  char buf[4];
 
11696
  for (char i = '0'; i <= '9' ; i++) {
 
11697
    buf[0] = i;
 
11698
    for (char j = '0'; j <= '9'; j++) {
 
11699
      buf[1] = j;
 
11700
      for (char k = '0'; k <= '9'; k++) {
 
11701
        buf[2] = k;
 
11702
        buf[3] = 0;
 
11703
        templ->Set(v8_str(buf), v8::Number::New(k));
 
11704
      }
 
11705
    }
 
11706
  }
 
11707
 
 
11708
  Local<v8::Object> instance_1 = templ->NewInstance();
 
11709
  context->Global()->Set(v8_str("obj_1"), instance_1);
 
11710
 
 
11711
  Local<Value> value_1 = CompileRun("obj_1.a");
 
11712
  CHECK(value_1->IsUndefined());
 
11713
 
 
11714
  Local<v8::Object> instance_2 = templ->NewInstance();
 
11715
  context->Global()->Set(v8_str("obj_2"), instance_2);
 
11716
 
 
11717
  Local<Value> value_2 = CompileRun("obj_2.a");
 
11718
  CHECK(value_2->IsUndefined());
 
11719
}
 
11720
 
 
11721
 
 
11722
// This tests that access check information remains on the global
 
11723
// object template when creating contexts.
 
11724
THREADED_TEST(AccessControlRepeatedContextCreation) {
 
11725
  v8::HandleScope handle_scope;
 
11726
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
11727
  global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
 
11728
                                           IndexedSetAccessBlocker);
 
11729
  i::Handle<i::ObjectTemplateInfo> internal_template =
 
11730
      v8::Utils::OpenHandle(*global_template);
 
11731
  CHECK(!internal_template->constructor()->IsUndefined());
 
11732
  i::Handle<i::FunctionTemplateInfo> constructor(
 
11733
      i::FunctionTemplateInfo::cast(internal_template->constructor()));
 
11734
  CHECK(!constructor->access_check_info()->IsUndefined());
 
11735
  v8::Persistent<Context> context0(Context::New(NULL, global_template));
 
11736
  CHECK(!context0.IsEmpty());
 
11737
  CHECK(!constructor->access_check_info()->IsUndefined());
 
11738
}
 
11739
 
 
11740
 
 
11741
THREADED_TEST(TurnOnAccessCheck) {
 
11742
  v8::HandleScope handle_scope;
 
11743
 
 
11744
  // Create an environment with access check to the global object disabled by
 
11745
  // default.
 
11746
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
11747
  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
 
11748
                                           IndexedGetAccessBlocker,
 
11749
                                           v8::Handle<v8::Value>(),
 
11750
                                           false);
 
11751
  v8::Persistent<Context> context = Context::New(NULL, global_template);
 
11752
  Context::Scope context_scope(context);
 
11753
 
 
11754
  // Set up a property and a number of functions.
 
11755
  context->Global()->Set(v8_str("a"), v8_num(1));
 
11756
  CompileRun("function f1() {return a;}"
 
11757
             "function f2() {return a;}"
 
11758
             "function g1() {return h();}"
 
11759
             "function g2() {return h();}"
 
11760
             "function h() {return 1;}");
 
11761
  Local<Function> f1 =
 
11762
      Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
 
11763
  Local<Function> f2 =
 
11764
      Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
 
11765
  Local<Function> g1 =
 
11766
      Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
 
11767
  Local<Function> g2 =
 
11768
      Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
 
11769
  Local<Function> h =
 
11770
      Local<Function>::Cast(context->Global()->Get(v8_str("h")));
 
11771
 
 
11772
  // Get the global object.
 
11773
  v8::Handle<v8::Object> global = context->Global();
 
11774
 
 
11775
  // Call f1 one time and f2 a number of times. This will ensure that f1 still
 
11776
  // uses the runtime system to retreive property a whereas f2 uses global load
 
11777
  // inline cache.
 
11778
  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11779
  for (int i = 0; i < 4; i++) {
 
11780
    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11781
  }
 
11782
 
 
11783
  // Same for g1 and g2.
 
11784
  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11785
  for (int i = 0; i < 4; i++) {
 
11786
    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11787
  }
 
11788
 
 
11789
  // Detach the global and turn on access check.
 
11790
  context->DetachGlobal();
 
11791
  context->Global()->TurnOnAccessCheck();
 
11792
 
 
11793
  // Failing access check to property get results in undefined.
 
11794
  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
 
11795
  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
 
11796
 
 
11797
  // Failing access check to function call results in exception.
 
11798
  CHECK(g1->Call(global, 0, NULL).IsEmpty());
 
11799
  CHECK(g2->Call(global, 0, NULL).IsEmpty());
 
11800
 
 
11801
  // No failing access check when just returning a constant.
 
11802
  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11803
}
 
11804
 
 
11805
 
 
11806
static const char* kPropertyA = "a";
 
11807
static const char* kPropertyH = "h";
 
11808
 
 
11809
static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
 
11810
                                       Local<Value> name,
 
11811
                                       v8::AccessType type,
 
11812
                                       Local<Value> data) {
 
11813
  if (!name->IsString()) return false;
 
11814
  i::Handle<i::String> name_handle =
 
11815
      v8::Utils::OpenHandle(String::Cast(*name));
 
11816
  return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
 
11817
      && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
 
11818
}
 
11819
 
 
11820
 
 
11821
THREADED_TEST(TurnOnAccessCheckAndRecompile) {
 
11822
  v8::HandleScope handle_scope;
 
11823
 
 
11824
  // Create an environment with access check to the global object disabled by
 
11825
  // default. When the registered access checker will block access to properties
 
11826
  // a and h.
 
11827
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
11828
  global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
 
11829
                                           IndexedGetAccessBlocker,
 
11830
                                           v8::Handle<v8::Value>(),
 
11831
                                           false);
 
11832
  v8::Persistent<Context> context = Context::New(NULL, global_template);
 
11833
  Context::Scope context_scope(context);
 
11834
 
 
11835
  // Set up a property and a number of functions.
 
11836
  context->Global()->Set(v8_str("a"), v8_num(1));
 
11837
  static const char* source = "function f1() {return a;}"
 
11838
                              "function f2() {return a;}"
 
11839
                              "function g1() {return h();}"
 
11840
                              "function g2() {return h();}"
 
11841
                              "function h() {return 1;}";
 
11842
 
 
11843
  CompileRun(source);
 
11844
  Local<Function> f1;
 
11845
  Local<Function> f2;
 
11846
  Local<Function> g1;
 
11847
  Local<Function> g2;
 
11848
  Local<Function> h;
 
11849
  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
 
11850
  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
 
11851
  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
 
11852
  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
 
11853
  h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
 
11854
 
 
11855
  // Get the global object.
 
11856
  v8::Handle<v8::Object> global = context->Global();
 
11857
 
 
11858
  // Call f1 one time and f2 a number of times. This will ensure that f1 still
 
11859
  // uses the runtime system to retreive property a whereas f2 uses global load
 
11860
  // inline cache.
 
11861
  CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11862
  for (int i = 0; i < 4; i++) {
 
11863
    CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11864
  }
 
11865
 
 
11866
  // Same for g1 and g2.
 
11867
  CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11868
  for (int i = 0; i < 4; i++) {
 
11869
    CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11870
  }
 
11871
 
 
11872
  // Detach the global and turn on access check now blocking access to property
 
11873
  // a and function h.
 
11874
  context->DetachGlobal();
 
11875
  context->Global()->TurnOnAccessCheck();
 
11876
 
 
11877
  // Failing access check to property get results in undefined.
 
11878
  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
 
11879
  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
 
11880
 
 
11881
  // Failing access check to function call results in exception.
 
11882
  CHECK(g1->Call(global, 0, NULL).IsEmpty());
 
11883
  CHECK(g2->Call(global, 0, NULL).IsEmpty());
 
11884
 
 
11885
  // No failing access check when just returning a constant.
 
11886
  CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
 
11887
 
 
11888
  // Now compile the source again. And get the newly compiled functions, except
 
11889
  // for h for which access is blocked.
 
11890
  CompileRun(source);
 
11891
  f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
 
11892
  f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
 
11893
  g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
 
11894
  g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
 
11895
  CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
 
11896
 
 
11897
  // Failing access check to property get results in undefined.
 
11898
  CHECK(f1->Call(global, 0, NULL)->IsUndefined());
 
11899
  CHECK(f2->Call(global, 0, NULL)->IsUndefined());
 
11900
 
 
11901
  // Failing access check to function call results in exception.
 
11902
  CHECK(g1->Call(global, 0, NULL).IsEmpty());
 
11903
  CHECK(g2->Call(global, 0, NULL).IsEmpty());
 
11904
}
 
11905
 
 
11906
 
 
11907
// This test verifies that pre-compilation (aka preparsing) can be called
 
11908
// without initializing the whole VM. Thus we cannot run this test in a
 
11909
// multi-threaded setup.
 
11910
TEST(PreCompile) {
 
11911
  // TODO(155): This test would break without the initialization of V8. This is
 
11912
  // a workaround for now to make this test not fail.
 
11913
  v8::V8::Initialize();
 
11914
  const char* script = "function foo(a) { return a+1; }";
 
11915
  v8::ScriptData* sd =
 
11916
      v8::ScriptData::PreCompile(script, i::StrLength(script));
 
11917
  CHECK_NE(sd->Length(), 0);
 
11918
  CHECK_NE(sd->Data(), NULL);
 
11919
  CHECK(!sd->HasError());
 
11920
  delete sd;
 
11921
}
 
11922
 
 
11923
 
 
11924
TEST(PreCompileWithError) {
 
11925
  v8::V8::Initialize();
 
11926
  const char* script = "function foo(a) { return 1 * * 2; }";
 
11927
  v8::ScriptData* sd =
 
11928
      v8::ScriptData::PreCompile(script, i::StrLength(script));
 
11929
  CHECK(sd->HasError());
 
11930
  delete sd;
 
11931
}
 
11932
 
 
11933
 
 
11934
TEST(Regress31661) {
 
11935
  v8::V8::Initialize();
 
11936
  const char* script = " The Definintive Guide";
 
11937
  v8::ScriptData* sd =
 
11938
      v8::ScriptData::PreCompile(script, i::StrLength(script));
 
11939
  CHECK(sd->HasError());
 
11940
  delete sd;
 
11941
}
 
11942
 
 
11943
 
 
11944
// Tests that ScriptData can be serialized and deserialized.
 
11945
TEST(PreCompileSerialization) {
 
11946
  v8::V8::Initialize();
 
11947
  const char* script = "function foo(a) { return a+1; }";
 
11948
  v8::ScriptData* sd =
 
11949
      v8::ScriptData::PreCompile(script, i::StrLength(script));
 
11950
 
 
11951
  // Serialize.
 
11952
  int serialized_data_length = sd->Length();
 
11953
  char* serialized_data = i::NewArray<char>(serialized_data_length);
 
11954
  memcpy(serialized_data, sd->Data(), serialized_data_length);
 
11955
 
 
11956
  // Deserialize.
 
11957
  v8::ScriptData* deserialized_sd =
 
11958
      v8::ScriptData::New(serialized_data, serialized_data_length);
 
11959
 
 
11960
  // Verify that the original is the same as the deserialized.
 
11961
  CHECK_EQ(sd->Length(), deserialized_sd->Length());
 
11962
  CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
 
11963
  CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
 
11964
 
 
11965
  delete sd;
 
11966
  delete deserialized_sd;
 
11967
}
 
11968
 
 
11969
 
 
11970
// Attempts to deserialize bad data.
 
11971
TEST(PreCompileDeserializationError) {
 
11972
  v8::V8::Initialize();
 
11973
  const char* data = "DONT CARE";
 
11974
  int invalid_size = 3;
 
11975
  v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
 
11976
 
 
11977
  CHECK_EQ(0, sd->Length());
 
11978
 
 
11979
  delete sd;
 
11980
}
 
11981
 
 
11982
 
 
11983
// Attempts to deserialize bad data.
 
11984
TEST(PreCompileInvalidPreparseDataError) {
 
11985
  v8::V8::Initialize();
 
11986
  v8::HandleScope scope;
 
11987
  LocalContext context;
 
11988
 
 
11989
  const char* script = "function foo(){ return 5;}\n"
 
11990
      "function bar(){ return 6 + 7;}  foo();";
 
11991
  v8::ScriptData* sd =
 
11992
      v8::ScriptData::PreCompile(script, i::StrLength(script));
 
11993
  CHECK(!sd->HasError());
 
11994
  // ScriptDataImpl private implementation details
 
11995
  const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
 
11996
  const int kFunctionEntrySize = i::FunctionEntry::kSize;
 
11997
  const int kFunctionEntryStartOffset = 0;
 
11998
  const int kFunctionEntryEndOffset = 1;
 
11999
  unsigned* sd_data =
 
12000
      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
 
12001
 
 
12002
  // Overwrite function bar's end position with 0.
 
12003
  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
 
12004
  v8::TryCatch try_catch;
 
12005
 
 
12006
  Local<String> source = String::New(script);
 
12007
  Local<Script> compiled_script = Script::New(source, NULL, sd);
 
12008
  CHECK(try_catch.HasCaught());
 
12009
  String::AsciiValue exception_value(try_catch.Message()->Get());
 
12010
  CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
 
12011
           *exception_value);
 
12012
 
 
12013
  try_catch.Reset();
 
12014
 
 
12015
  // Overwrite function bar's start position with 200.  The function entry
 
12016
  // will not be found when searching for it by position and we should fall
 
12017
  // back on eager compilation.
 
12018
  sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
 
12019
  sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
 
12020
  sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
 
12021
      200;
 
12022
  compiled_script = Script::New(source, NULL, sd);
 
12023
  CHECK(!try_catch.HasCaught());
 
12024
 
 
12025
  delete sd;
 
12026
}
 
12027
 
 
12028
 
 
12029
// Verifies that the Handle<String> and const char* versions of the API produce
 
12030
// the same results (at least for one trivial case).
 
12031
TEST(PreCompileAPIVariationsAreSame) {
 
12032
  v8::V8::Initialize();
 
12033
  v8::HandleScope scope;
 
12034
 
 
12035
  const char* cstring = "function foo(a) { return a+1; }";
 
12036
 
 
12037
  v8::ScriptData* sd_from_cstring =
 
12038
      v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
 
12039
 
 
12040
  TestAsciiResource* resource = new TestAsciiResource(cstring);
 
12041
  v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
 
12042
      v8::String::NewExternal(resource));
 
12043
 
 
12044
  v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
 
12045
      v8::String::New(cstring));
 
12046
 
 
12047
  CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
 
12048
  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
 
12049
                     sd_from_external_string->Data(),
 
12050
                     sd_from_cstring->Length()));
 
12051
 
 
12052
  CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
 
12053
  CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
 
12054
                     sd_from_string->Data(),
 
12055
                     sd_from_cstring->Length()));
 
12056
 
 
12057
 
 
12058
  delete sd_from_cstring;
 
12059
  delete sd_from_external_string;
 
12060
  delete sd_from_string;
 
12061
}
 
12062
 
 
12063
 
 
12064
// This tests that we do not allow dictionary load/call inline caches
 
12065
// to use functions that have not yet been compiled.  The potential
 
12066
// problem of loading a function that has not yet been compiled can
 
12067
// arise because we share code between contexts via the compilation
 
12068
// cache.
 
12069
THREADED_TEST(DictionaryICLoadedFunction) {
 
12070
  v8::HandleScope scope;
 
12071
  // Test LoadIC.
 
12072
  for (int i = 0; i < 2; i++) {
 
12073
    LocalContext context;
 
12074
    context->Global()->Set(v8_str("tmp"), v8::True());
 
12075
    context->Global()->Delete(v8_str("tmp"));
 
12076
    CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
 
12077
  }
 
12078
  // Test CallIC.
 
12079
  for (int i = 0; i < 2; i++) {
 
12080
    LocalContext context;
 
12081
    context->Global()->Set(v8_str("tmp"), v8::True());
 
12082
    context->Global()->Delete(v8_str("tmp"));
 
12083
    CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
 
12084
  }
 
12085
}
 
12086
 
 
12087
 
 
12088
// Test that cross-context new calls use the context of the callee to
 
12089
// create the new JavaScript object.
 
12090
THREADED_TEST(CrossContextNew) {
 
12091
  v8::HandleScope scope;
 
12092
  v8::Persistent<Context> context0 = Context::New();
 
12093
  v8::Persistent<Context> context1 = Context::New();
 
12094
 
 
12095
  // Allow cross-domain access.
 
12096
  Local<String> token = v8_str("<security token>");
 
12097
  context0->SetSecurityToken(token);
 
12098
  context1->SetSecurityToken(token);
 
12099
 
 
12100
  // Set an 'x' property on the Object prototype and define a
 
12101
  // constructor function in context0.
 
12102
  context0->Enter();
 
12103
  CompileRun("Object.prototype.x = 42; function C() {};");
 
12104
  context0->Exit();
 
12105
 
 
12106
  // Call the constructor function from context0 and check that the
 
12107
  // result has the 'x' property.
 
12108
  context1->Enter();
 
12109
  context1->Global()->Set(v8_str("other"), context0->Global());
 
12110
  Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
 
12111
  CHECK(value->IsInt32());
 
12112
  CHECK_EQ(42, value->Int32Value());
 
12113
  context1->Exit();
 
12114
 
 
12115
  // Dispose the contexts to allow them to be garbage collected.
 
12116
  context0.Dispose();
 
12117
  context1.Dispose();
 
12118
}
 
12119
 
 
12120
 
 
12121
class RegExpInterruptTest {
 
12122
 public:
 
12123
  RegExpInterruptTest() : block_(NULL) {}
 
12124
  ~RegExpInterruptTest() { delete block_; }
 
12125
  void RunTest() {
 
12126
    block_ = i::OS::CreateSemaphore(0);
 
12127
    gc_count_ = 0;
 
12128
    gc_during_regexp_ = 0;
 
12129
    regexp_success_ = false;
 
12130
    gc_success_ = false;
 
12131
    GCThread gc_thread(this);
 
12132
    gc_thread.Start();
 
12133
    v8::Locker::StartPreemption(1);
 
12134
 
 
12135
    LongRunningRegExp();
 
12136
    {
 
12137
      v8::Unlocker unlock;
 
12138
      gc_thread.Join();
 
12139
    }
 
12140
    v8::Locker::StopPreemption();
 
12141
    CHECK(regexp_success_);
 
12142
    CHECK(gc_success_);
 
12143
  }
 
12144
 
 
12145
 private:
 
12146
  // Number of garbage collections required.
 
12147
  static const int kRequiredGCs = 5;
 
12148
 
 
12149
  class GCThread : public i::Thread {
 
12150
   public:
 
12151
    explicit GCThread(RegExpInterruptTest* test)
 
12152
        : Thread("GCThread"), test_(test) {}
 
12153
    virtual void Run() {
 
12154
      test_->CollectGarbage();
 
12155
    }
 
12156
   private:
 
12157
     RegExpInterruptTest* test_;
 
12158
  };
 
12159
 
 
12160
  void CollectGarbage() {
 
12161
    block_->Wait();
 
12162
    while (gc_during_regexp_ < kRequiredGCs) {
 
12163
      {
 
12164
        v8::Locker lock;
 
12165
        // TODO(lrn): Perhaps create some garbage before collecting.
 
12166
        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
12167
        gc_count_++;
 
12168
      }
 
12169
      i::OS::Sleep(1);
 
12170
    }
 
12171
    gc_success_ = true;
 
12172
  }
 
12173
 
 
12174
  void LongRunningRegExp() {
 
12175
    block_->Signal();  // Enable garbage collection thread on next preemption.
 
12176
    int rounds = 0;
 
12177
    while (gc_during_regexp_ < kRequiredGCs) {
 
12178
      int gc_before = gc_count_;
 
12179
      {
 
12180
        // Match 15-30 "a"'s against 14 and a "b".
 
12181
        const char* c_source =
 
12182
            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
 
12183
            ".exec('aaaaaaaaaaaaaaab') === null";
 
12184
        Local<String> source = String::New(c_source);
 
12185
        Local<Script> script = Script::Compile(source);
 
12186
        Local<Value> result = script->Run();
 
12187
        if (!result->BooleanValue()) {
 
12188
          gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
 
12189
          return;
 
12190
        }
 
12191
      }
 
12192
      {
 
12193
        // Match 15-30 "a"'s against 15 and a "b".
 
12194
        const char* c_source =
 
12195
            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
 
12196
            ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
 
12197
        Local<String> source = String::New(c_source);
 
12198
        Local<Script> script = Script::Compile(source);
 
12199
        Local<Value> result = script->Run();
 
12200
        if (!result->BooleanValue()) {
 
12201
          gc_during_regexp_ = kRequiredGCs;
 
12202
          return;
 
12203
        }
 
12204
      }
 
12205
      int gc_after = gc_count_;
 
12206
      gc_during_regexp_ += gc_after - gc_before;
 
12207
      rounds++;
 
12208
      i::OS::Sleep(1);
 
12209
    }
 
12210
    regexp_success_ = true;
 
12211
  }
 
12212
 
 
12213
  i::Semaphore* block_;
 
12214
  int gc_count_;
 
12215
  int gc_during_regexp_;
 
12216
  bool regexp_success_;
 
12217
  bool gc_success_;
 
12218
};
 
12219
 
 
12220
 
 
12221
// Test that a regular expression execution can be interrupted and
 
12222
// survive a garbage collection.
 
12223
TEST(RegExpInterruption) {
 
12224
  v8::Locker lock;
 
12225
  v8::V8::Initialize();
 
12226
  v8::HandleScope scope;
 
12227
  Local<Context> local_env;
 
12228
  {
 
12229
    LocalContext env;
 
12230
    local_env = env.local();
 
12231
  }
 
12232
 
 
12233
  // Local context should still be live.
 
12234
  CHECK(!local_env.IsEmpty());
 
12235
  local_env->Enter();
 
12236
 
 
12237
  // Should complete without problems.
 
12238
  RegExpInterruptTest().RunTest();
 
12239
 
 
12240
  local_env->Exit();
 
12241
}
 
12242
 
 
12243
 
 
12244
class ApplyInterruptTest {
 
12245
 public:
 
12246
  ApplyInterruptTest() : block_(NULL) {}
 
12247
  ~ApplyInterruptTest() { delete block_; }
 
12248
  void RunTest() {
 
12249
    block_ = i::OS::CreateSemaphore(0);
 
12250
    gc_count_ = 0;
 
12251
    gc_during_apply_ = 0;
 
12252
    apply_success_ = false;
 
12253
    gc_success_ = false;
 
12254
    GCThread gc_thread(this);
 
12255
    gc_thread.Start();
 
12256
    v8::Locker::StartPreemption(1);
 
12257
 
 
12258
    LongRunningApply();
 
12259
    {
 
12260
      v8::Unlocker unlock;
 
12261
      gc_thread.Join();
 
12262
    }
 
12263
    v8::Locker::StopPreemption();
 
12264
    CHECK(apply_success_);
 
12265
    CHECK(gc_success_);
 
12266
  }
 
12267
 
 
12268
 private:
 
12269
  // Number of garbage collections required.
 
12270
  static const int kRequiredGCs = 2;
 
12271
 
 
12272
  class GCThread : public i::Thread {
 
12273
   public:
 
12274
    explicit GCThread(ApplyInterruptTest* test)
 
12275
        : Thread("GCThread"), test_(test) {}
 
12276
    virtual void Run() {
 
12277
      test_->CollectGarbage();
 
12278
    }
 
12279
   private:
 
12280
     ApplyInterruptTest* test_;
 
12281
  };
 
12282
 
 
12283
  void CollectGarbage() {
 
12284
    block_->Wait();
 
12285
    while (gc_during_apply_ < kRequiredGCs) {
 
12286
      {
 
12287
        v8::Locker lock;
 
12288
        HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
12289
        gc_count_++;
 
12290
      }
 
12291
      i::OS::Sleep(1);
 
12292
    }
 
12293
    gc_success_ = true;
 
12294
  }
 
12295
 
 
12296
  void LongRunningApply() {
 
12297
    block_->Signal();
 
12298
    int rounds = 0;
 
12299
    while (gc_during_apply_ < kRequiredGCs) {
 
12300
      int gc_before = gc_count_;
 
12301
      {
 
12302
        const char* c_source =
 
12303
            "function do_very_little(bar) {"
 
12304
            "  this.foo = bar;"
 
12305
            "}"
 
12306
            "for (var i = 0; i < 100000; i++) {"
 
12307
            "  do_very_little.apply(this, ['bar']);"
 
12308
            "}";
 
12309
        Local<String> source = String::New(c_source);
 
12310
        Local<Script> script = Script::Compile(source);
 
12311
        Local<Value> result = script->Run();
 
12312
        // Check that no exception was thrown.
 
12313
        CHECK(!result.IsEmpty());
 
12314
      }
 
12315
      int gc_after = gc_count_;
 
12316
      gc_during_apply_ += gc_after - gc_before;
 
12317
      rounds++;
 
12318
    }
 
12319
    apply_success_ = true;
 
12320
  }
 
12321
 
 
12322
  i::Semaphore* block_;
 
12323
  int gc_count_;
 
12324
  int gc_during_apply_;
 
12325
  bool apply_success_;
 
12326
  bool gc_success_;
 
12327
};
 
12328
 
 
12329
 
 
12330
// Test that nothing bad happens if we get a preemption just when we were
 
12331
// about to do an apply().
 
12332
TEST(ApplyInterruption) {
 
12333
  v8::Locker lock;
 
12334
  v8::V8::Initialize();
 
12335
  v8::HandleScope scope;
 
12336
  Local<Context> local_env;
 
12337
  {
 
12338
    LocalContext env;
 
12339
    local_env = env.local();
 
12340
  }
 
12341
 
 
12342
  // Local context should still be live.
 
12343
  CHECK(!local_env.IsEmpty());
 
12344
  local_env->Enter();
 
12345
 
 
12346
  // Should complete without problems.
 
12347
  ApplyInterruptTest().RunTest();
 
12348
 
 
12349
  local_env->Exit();
 
12350
}
 
12351
 
 
12352
 
 
12353
// Verify that we can clone an object
 
12354
TEST(ObjectClone) {
 
12355
  v8::HandleScope scope;
 
12356
  LocalContext env;
 
12357
 
 
12358
  const char* sample =
 
12359
    "var rv = {};"      \
 
12360
    "rv.alpha = 'hello';" \
 
12361
    "rv.beta = 123;"     \
 
12362
    "rv;";
 
12363
 
 
12364
  // Create an object, verify basics.
 
12365
  Local<Value> val = CompileRun(sample);
 
12366
  CHECK(val->IsObject());
 
12367
  Local<v8::Object> obj = val.As<v8::Object>();
 
12368
  obj->Set(v8_str("gamma"), v8_str("cloneme"));
 
12369
 
 
12370
  CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
 
12371
  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
 
12372
  CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
 
12373
 
 
12374
  // Clone it.
 
12375
  Local<v8::Object> clone = obj->Clone();
 
12376
  CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
 
12377
  CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
 
12378
  CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
 
12379
 
 
12380
  // Set a property on the clone, verify each object.
 
12381
  clone->Set(v8_str("beta"), v8::Integer::New(456));
 
12382
  CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
 
12383
  CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
 
12384
}
 
12385
 
 
12386
 
 
12387
class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
 
12388
 public:
 
12389
  explicit AsciiVectorResource(i::Vector<const char> vector)
 
12390
      : data_(vector) {}
 
12391
  virtual ~AsciiVectorResource() {}
 
12392
  virtual size_t length() const { return data_.length(); }
 
12393
  virtual const char* data() const { return data_.start(); }
 
12394
 private:
 
12395
  i::Vector<const char> data_;
 
12396
};
 
12397
 
 
12398
 
 
12399
class UC16VectorResource : public v8::String::ExternalStringResource {
 
12400
 public:
 
12401
  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
 
12402
      : data_(vector) {}
 
12403
  virtual ~UC16VectorResource() {}
 
12404
  virtual size_t length() const { return data_.length(); }
 
12405
  virtual const i::uc16* data() const { return data_.start(); }
 
12406
 private:
 
12407
  i::Vector<const i::uc16> data_;
 
12408
};
 
12409
 
 
12410
 
 
12411
static void MorphAString(i::String* string,
 
12412
                         AsciiVectorResource* ascii_resource,
 
12413
                         UC16VectorResource* uc16_resource) {
 
12414
  CHECK(i::StringShape(string).IsExternal());
 
12415
  if (string->IsAsciiRepresentation()) {
 
12416
    // Check old map is not symbol or long.
 
12417
    CHECK(string->map() == HEAP->external_ascii_string_map());
 
12418
    // Morph external string to be TwoByte string.
 
12419
    string->set_map(HEAP->external_string_map());
 
12420
    i::ExternalTwoByteString* morphed =
 
12421
         i::ExternalTwoByteString::cast(string);
 
12422
    morphed->set_resource(uc16_resource);
 
12423
  } else {
 
12424
    // Check old map is not symbol or long.
 
12425
    CHECK(string->map() == HEAP->external_string_map());
 
12426
    // Morph external string to be ASCII string.
 
12427
    string->set_map(HEAP->external_ascii_string_map());
 
12428
    i::ExternalAsciiString* morphed =
 
12429
         i::ExternalAsciiString::cast(string);
 
12430
    morphed->set_resource(ascii_resource);
 
12431
  }
 
12432
}
 
12433
 
 
12434
 
 
12435
// Test that we can still flatten a string if the components it is built up
 
12436
// from have been turned into 16 bit strings in the mean time.
 
12437
THREADED_TEST(MorphCompositeStringTest) {
 
12438
  char utf_buffer[129];
 
12439
  const char* c_string = "Now is the time for all good men"
 
12440
                         " to come to the aid of the party";
 
12441
  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
 
12442
  {
 
12443
    v8::HandleScope scope;
 
12444
    LocalContext env;
 
12445
    AsciiVectorResource ascii_resource(
 
12446
        i::Vector<const char>(c_string, i::StrLength(c_string)));
 
12447
    UC16VectorResource uc16_resource(
 
12448
        i::Vector<const uint16_t>(two_byte_string,
 
12449
                                  i::StrLength(c_string)));
 
12450
 
 
12451
    Local<String> lhs(v8::Utils::ToLocal(
 
12452
        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
 
12453
    Local<String> rhs(v8::Utils::ToLocal(
 
12454
        FACTORY->NewExternalStringFromAscii(&ascii_resource)));
 
12455
 
 
12456
    env->Global()->Set(v8_str("lhs"), lhs);
 
12457
    env->Global()->Set(v8_str("rhs"), rhs);
 
12458
 
 
12459
    CompileRun(
 
12460
        "var cons = lhs + rhs;"
 
12461
        "var slice = lhs.substring(1, lhs.length - 1);"
 
12462
        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
 
12463
 
 
12464
    CHECK(!lhs->MayContainNonAscii());
 
12465
    CHECK(!rhs->MayContainNonAscii());
 
12466
 
 
12467
    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
 
12468
    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
 
12469
 
 
12470
    // This should UTF-8 without flattening, since everything is ASCII.
 
12471
    Handle<String> cons = v8_compile("cons")->Run().As<String>();
 
12472
    CHECK_EQ(128, cons->Utf8Length());
 
12473
    int nchars = -1;
 
12474
    CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
 
12475
    CHECK_EQ(128, nchars);
 
12476
    CHECK_EQ(0, strcmp(
 
12477
        utf_buffer,
 
12478
        "Now is the time for all good men to come to the aid of the party"
 
12479
        "Now is the time for all good men to come to the aid of the party"));
 
12480
 
 
12481
    // Now do some stuff to make sure the strings are flattened, etc.
 
12482
    CompileRun(
 
12483
        "/[^a-z]/.test(cons);"
 
12484
        "/[^a-z]/.test(slice);"
 
12485
        "/[^a-z]/.test(slice_on_cons);");
 
12486
    const char* expected_cons =
 
12487
        "Now is the time for all good men to come to the aid of the party"
 
12488
        "Now is the time for all good men to come to the aid of the party";
 
12489
    const char* expected_slice =
 
12490
        "ow is the time for all good men to come to the aid of the part";
 
12491
    const char* expected_slice_on_cons =
 
12492
        "ow is the time for all good men to come to the aid of the party"
 
12493
        "Now is the time for all good men to come to the aid of the part";
 
12494
    CHECK_EQ(String::New(expected_cons),
 
12495
             env->Global()->Get(v8_str("cons")));
 
12496
    CHECK_EQ(String::New(expected_slice),
 
12497
             env->Global()->Get(v8_str("slice")));
 
12498
    CHECK_EQ(String::New(expected_slice_on_cons),
 
12499
             env->Global()->Get(v8_str("slice_on_cons")));
 
12500
  }
 
12501
  i::DeleteArray(two_byte_string);
 
12502
}
 
12503
 
 
12504
 
 
12505
TEST(CompileExternalTwoByteSource) {
 
12506
  v8::HandleScope scope;
 
12507
  LocalContext context;
 
12508
 
 
12509
  // This is a very short list of sources, which currently is to check for a
 
12510
  // regression caused by r2703.
 
12511
  const char* ascii_sources[] = {
 
12512
    "0.5",
 
12513
    "-0.5",   // This mainly testes PushBack in the Scanner.
 
12514
    "--0.5",  // This mainly testes PushBack in the Scanner.
 
12515
    NULL
 
12516
  };
 
12517
 
 
12518
  // Compile the sources as external two byte strings.
 
12519
  for (int i = 0; ascii_sources[i] != NULL; i++) {
 
12520
    uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
 
12521
    UC16VectorResource uc16_resource(
 
12522
        i::Vector<const uint16_t>(two_byte_string,
 
12523
                                  i::StrLength(ascii_sources[i])));
 
12524
    v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
 
12525
    v8::Script::Compile(source);
 
12526
    i::DeleteArray(two_byte_string);
 
12527
  }
 
12528
}
 
12529
 
 
12530
 
 
12531
class RegExpStringModificationTest {
 
12532
 public:
 
12533
  RegExpStringModificationTest()
 
12534
      : block_(i::OS::CreateSemaphore(0)),
 
12535
        morphs_(0),
 
12536
        morphs_during_regexp_(0),
 
12537
        ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
 
12538
        uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
 
12539
  ~RegExpStringModificationTest() { delete block_; }
 
12540
  void RunTest() {
 
12541
    regexp_success_ = false;
 
12542
    morph_success_ = false;
 
12543
 
 
12544
    // Initialize the contents of two_byte_content_ to be a uc16 representation
 
12545
    // of "aaaaaaaaaaaaaab".
 
12546
    for (int i = 0; i < 14; i++) {
 
12547
      two_byte_content_[i] = 'a';
 
12548
    }
 
12549
    two_byte_content_[14] = 'b';
 
12550
 
 
12551
    // Create the input string for the regexp - the one we are going to change
 
12552
    // properties of.
 
12553
    input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
 
12554
 
 
12555
    // Inject the input as a global variable.
 
12556
    i::Handle<i::String> input_name =
 
12557
        FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
 
12558
    i::Isolate::Current()->native_context()->global_object()->SetProperty(
 
12559
        *input_name,
 
12560
        *input_,
 
12561
        NONE,
 
12562
        i::kNonStrictMode)->ToObjectChecked();
 
12563
 
 
12564
    MorphThread morph_thread(this);
 
12565
    morph_thread.Start();
 
12566
    v8::Locker::StartPreemption(1);
 
12567
    LongRunningRegExp();
 
12568
    {
 
12569
      v8::Unlocker unlock;
 
12570
      morph_thread.Join();
 
12571
    }
 
12572
    v8::Locker::StopPreemption();
 
12573
    CHECK(regexp_success_);
 
12574
    CHECK(morph_success_);
 
12575
  }
 
12576
 
 
12577
 private:
 
12578
  // Number of string modifications required.
 
12579
  static const int kRequiredModifications = 5;
 
12580
  static const int kMaxModifications = 100;
 
12581
 
 
12582
  class MorphThread : public i::Thread {
 
12583
   public:
 
12584
    explicit MorphThread(RegExpStringModificationTest* test)
 
12585
        : Thread("MorphThread"), test_(test) {}
 
12586
    virtual void Run() {
 
12587
      test_->MorphString();
 
12588
    }
 
12589
   private:
 
12590
     RegExpStringModificationTest* test_;
 
12591
  };
 
12592
 
 
12593
  void MorphString() {
 
12594
    block_->Wait();
 
12595
    while (morphs_during_regexp_ < kRequiredModifications &&
 
12596
           morphs_ < kMaxModifications) {
 
12597
      {
 
12598
        v8::Locker lock;
 
12599
        // Swap string between ascii and two-byte representation.
 
12600
        i::String* string = *input_;
 
12601
        MorphAString(string, &ascii_resource_, &uc16_resource_);
 
12602
        morphs_++;
 
12603
      }
 
12604
      i::OS::Sleep(1);
 
12605
    }
 
12606
    morph_success_ = true;
 
12607
  }
 
12608
 
 
12609
  void LongRunningRegExp() {
 
12610
    block_->Signal();  // Enable morphing thread on next preemption.
 
12611
    while (morphs_during_regexp_ < kRequiredModifications &&
 
12612
           morphs_ < kMaxModifications) {
 
12613
      int morphs_before = morphs_;
 
12614
      {
 
12615
        v8::HandleScope scope;
 
12616
        // Match 15-30 "a"'s against 14 and a "b".
 
12617
        const char* c_source =
 
12618
            "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
 
12619
            ".exec(input) === null";
 
12620
        Local<String> source = String::New(c_source);
 
12621
        Local<Script> script = Script::Compile(source);
 
12622
        Local<Value> result = script->Run();
 
12623
        CHECK(result->IsTrue());
 
12624
      }
 
12625
      int morphs_after = morphs_;
 
12626
      morphs_during_regexp_ += morphs_after - morphs_before;
 
12627
    }
 
12628
    regexp_success_ = true;
 
12629
  }
 
12630
 
 
12631
  i::uc16 two_byte_content_[15];
 
12632
  i::Semaphore* block_;
 
12633
  int morphs_;
 
12634
  int morphs_during_regexp_;
 
12635
  bool regexp_success_;
 
12636
  bool morph_success_;
 
12637
  i::Handle<i::String> input_;
 
12638
  AsciiVectorResource ascii_resource_;
 
12639
  UC16VectorResource uc16_resource_;
 
12640
};
 
12641
 
 
12642
 
 
12643
// Test that a regular expression execution can be interrupted and
 
12644
// the string changed without failing.
 
12645
TEST(RegExpStringModification) {
 
12646
  v8::Locker lock;
 
12647
  v8::V8::Initialize();
 
12648
  v8::HandleScope scope;
 
12649
  Local<Context> local_env;
 
12650
  {
 
12651
    LocalContext env;
 
12652
    local_env = env.local();
 
12653
  }
 
12654
 
 
12655
  // Local context should still be live.
 
12656
  CHECK(!local_env.IsEmpty());
 
12657
  local_env->Enter();
 
12658
 
 
12659
  // Should complete without problems.
 
12660
  RegExpStringModificationTest().RunTest();
 
12661
 
 
12662
  local_env->Exit();
 
12663
}
 
12664
 
 
12665
 
 
12666
// Test that we cannot set a property on the global object if there
 
12667
// is a read-only property in the prototype chain.
 
12668
TEST(ReadOnlyPropertyInGlobalProto) {
 
12669
  i::FLAG_es5_readonly = true;
 
12670
  v8::HandleScope scope;
 
12671
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
12672
  LocalContext context(0, templ);
 
12673
  v8::Handle<v8::Object> global = context->Global();
 
12674
  v8::Handle<v8::Object> global_proto =
 
12675
      v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
 
12676
  global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
 
12677
  global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
 
12678
  // Check without 'eval' or 'with'.
 
12679
  v8::Handle<v8::Value> res =
 
12680
      CompileRun("function f() { x = 42; return x; }; f()");
 
12681
  CHECK_EQ(v8::Integer::New(0), res);
 
12682
  // Check with 'eval'.
 
12683
  res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
 
12684
  CHECK_EQ(v8::Integer::New(0), res);
 
12685
  // Check with 'with'.
 
12686
  res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
 
12687
  CHECK_EQ(v8::Integer::New(0), res);
 
12688
}
 
12689
 
 
12690
static int force_set_set_count = 0;
 
12691
static int force_set_get_count = 0;
 
12692
bool pass_on_get = false;
 
12693
 
 
12694
static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
 
12695
                                            const v8::AccessorInfo& info) {
 
12696
  force_set_get_count++;
 
12697
  if (pass_on_get) {
 
12698
    return v8::Handle<v8::Value>();
 
12699
  } else {
 
12700
    return v8::Int32::New(3);
 
12701
  }
 
12702
}
 
12703
 
 
12704
static void ForceSetSetter(v8::Local<v8::String> name,
 
12705
                           v8::Local<v8::Value> value,
 
12706
                           const v8::AccessorInfo& info) {
 
12707
  force_set_set_count++;
 
12708
}
 
12709
 
 
12710
static v8::Handle<v8::Value> ForceSetInterceptSetter(
 
12711
    v8::Local<v8::String> name,
 
12712
    v8::Local<v8::Value> value,
 
12713
    const v8::AccessorInfo& info) {
 
12714
  force_set_set_count++;
 
12715
  return v8::Undefined();
 
12716
}
 
12717
 
 
12718
TEST(ForceSet) {
 
12719
  force_set_get_count = 0;
 
12720
  force_set_set_count = 0;
 
12721
  pass_on_get = false;
 
12722
 
 
12723
  v8::HandleScope scope;
 
12724
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
12725
  v8::Handle<v8::String> access_property = v8::String::New("a");
 
12726
  templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
 
12727
  LocalContext context(NULL, templ);
 
12728
  v8::Handle<v8::Object> global = context->Global();
 
12729
 
 
12730
  // Ordinary properties
 
12731
  v8::Handle<v8::String> simple_property = v8::String::New("p");
 
12732
  global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
 
12733
  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
 
12734
  // This should fail because the property is read-only
 
12735
  global->Set(simple_property, v8::Int32::New(5));
 
12736
  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
 
12737
  // This should succeed even though the property is read-only
 
12738
  global->ForceSet(simple_property, v8::Int32::New(6));
 
12739
  CHECK_EQ(6, global->Get(simple_property)->Int32Value());
 
12740
 
 
12741
  // Accessors
 
12742
  CHECK_EQ(0, force_set_set_count);
 
12743
  CHECK_EQ(0, force_set_get_count);
 
12744
  CHECK_EQ(3, global->Get(access_property)->Int32Value());
 
12745
  // CHECK_EQ the property shouldn't override it, just call the setter
 
12746
  // which in this case does nothing.
 
12747
  global->Set(access_property, v8::Int32::New(7));
 
12748
  CHECK_EQ(3, global->Get(access_property)->Int32Value());
 
12749
  CHECK_EQ(1, force_set_set_count);
 
12750
  CHECK_EQ(2, force_set_get_count);
 
12751
  // Forcing the property to be set should override the accessor without
 
12752
  // calling it
 
12753
  global->ForceSet(access_property, v8::Int32::New(8));
 
12754
  CHECK_EQ(8, global->Get(access_property)->Int32Value());
 
12755
  CHECK_EQ(1, force_set_set_count);
 
12756
  CHECK_EQ(2, force_set_get_count);
 
12757
}
 
12758
 
 
12759
TEST(ForceSetWithInterceptor) {
 
12760
  force_set_get_count = 0;
 
12761
  force_set_set_count = 0;
 
12762
  pass_on_get = false;
 
12763
 
 
12764
  v8::HandleScope scope;
 
12765
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
12766
  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
 
12767
  LocalContext context(NULL, templ);
 
12768
  v8::Handle<v8::Object> global = context->Global();
 
12769
 
 
12770
  v8::Handle<v8::String> some_property = v8::String::New("a");
 
12771
  CHECK_EQ(0, force_set_set_count);
 
12772
  CHECK_EQ(0, force_set_get_count);
 
12773
  CHECK_EQ(3, global->Get(some_property)->Int32Value());
 
12774
  // Setting the property shouldn't override it, just call the setter
 
12775
  // which in this case does nothing.
 
12776
  global->Set(some_property, v8::Int32::New(7));
 
12777
  CHECK_EQ(3, global->Get(some_property)->Int32Value());
 
12778
  CHECK_EQ(1, force_set_set_count);
 
12779
  CHECK_EQ(2, force_set_get_count);
 
12780
  // Getting the property when the interceptor returns an empty handle
 
12781
  // should yield undefined, since the property isn't present on the
 
12782
  // object itself yet.
 
12783
  pass_on_get = true;
 
12784
  CHECK(global->Get(some_property)->IsUndefined());
 
12785
  CHECK_EQ(1, force_set_set_count);
 
12786
  CHECK_EQ(3, force_set_get_count);
 
12787
  // Forcing the property to be set should cause the value to be
 
12788
  // set locally without calling the interceptor.
 
12789
  global->ForceSet(some_property, v8::Int32::New(8));
 
12790
  CHECK_EQ(8, global->Get(some_property)->Int32Value());
 
12791
  CHECK_EQ(1, force_set_set_count);
 
12792
  CHECK_EQ(4, force_set_get_count);
 
12793
  // Reenabling the interceptor should cause it to take precedence over
 
12794
  // the property
 
12795
  pass_on_get = false;
 
12796
  CHECK_EQ(3, global->Get(some_property)->Int32Value());
 
12797
  CHECK_EQ(1, force_set_set_count);
 
12798
  CHECK_EQ(5, force_set_get_count);
 
12799
  // The interceptor should also work for other properties
 
12800
  CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
 
12801
  CHECK_EQ(1, force_set_set_count);
 
12802
  CHECK_EQ(6, force_set_get_count);
 
12803
}
 
12804
 
 
12805
 
 
12806
THREADED_TEST(ForceDelete) {
 
12807
  v8::HandleScope scope;
 
12808
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
12809
  LocalContext context(NULL, templ);
 
12810
  v8::Handle<v8::Object> global = context->Global();
 
12811
 
 
12812
  // Ordinary properties
 
12813
  v8::Handle<v8::String> simple_property = v8::String::New("p");
 
12814
  global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
 
12815
  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
 
12816
  // This should fail because the property is dont-delete.
 
12817
  CHECK(!global->Delete(simple_property));
 
12818
  CHECK_EQ(4, global->Get(simple_property)->Int32Value());
 
12819
  // This should succeed even though the property is dont-delete.
 
12820
  CHECK(global->ForceDelete(simple_property));
 
12821
  CHECK(global->Get(simple_property)->IsUndefined());
 
12822
}
 
12823
 
 
12824
 
 
12825
static int force_delete_interceptor_count = 0;
 
12826
static bool pass_on_delete = false;
 
12827
 
 
12828
 
 
12829
static v8::Handle<v8::Boolean> ForceDeleteDeleter(
 
12830
    v8::Local<v8::String> name,
 
12831
    const v8::AccessorInfo& info) {
 
12832
  force_delete_interceptor_count++;
 
12833
  if (pass_on_delete) {
 
12834
    return v8::Handle<v8::Boolean>();
 
12835
  } else {
 
12836
    return v8::True();
 
12837
  }
 
12838
}
 
12839
 
 
12840
 
 
12841
THREADED_TEST(ForceDeleteWithInterceptor) {
 
12842
  force_delete_interceptor_count = 0;
 
12843
  pass_on_delete = false;
 
12844
 
 
12845
  v8::HandleScope scope;
 
12846
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
12847
  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
 
12848
  LocalContext context(NULL, templ);
 
12849
  v8::Handle<v8::Object> global = context->Global();
 
12850
 
 
12851
  v8::Handle<v8::String> some_property = v8::String::New("a");
 
12852
  global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
 
12853
 
 
12854
  // Deleting a property should get intercepted and nothing should
 
12855
  // happen.
 
12856
  CHECK_EQ(0, force_delete_interceptor_count);
 
12857
  CHECK(global->Delete(some_property));
 
12858
  CHECK_EQ(1, force_delete_interceptor_count);
 
12859
  CHECK_EQ(42, global->Get(some_property)->Int32Value());
 
12860
  // Deleting the property when the interceptor returns an empty
 
12861
  // handle should not delete the property since it is DontDelete.
 
12862
  pass_on_delete = true;
 
12863
  CHECK(!global->Delete(some_property));
 
12864
  CHECK_EQ(2, force_delete_interceptor_count);
 
12865
  CHECK_EQ(42, global->Get(some_property)->Int32Value());
 
12866
  // Forcing the property to be deleted should delete the value
 
12867
  // without calling the interceptor.
 
12868
  CHECK(global->ForceDelete(some_property));
 
12869
  CHECK(global->Get(some_property)->IsUndefined());
 
12870
  CHECK_EQ(2, force_delete_interceptor_count);
 
12871
}
 
12872
 
 
12873
 
 
12874
// Make sure that forcing a delete invalidates any IC stubs, so we
 
12875
// don't read the hole value.
 
12876
THREADED_TEST(ForceDeleteIC) {
 
12877
  v8::HandleScope scope;
 
12878
  LocalContext context;
 
12879
  // Create a DontDelete variable on the global object.
 
12880
  CompileRun("this.__proto__ = { foo: 'horse' };"
 
12881
             "var foo = 'fish';"
 
12882
             "function f() { return foo.length; }");
 
12883
  // Initialize the IC for foo in f.
 
12884
  CompileRun("for (var i = 0; i < 4; i++) f();");
 
12885
  // Make sure the value of foo is correct before the deletion.
 
12886
  CHECK_EQ(4, CompileRun("f()")->Int32Value());
 
12887
  // Force the deletion of foo.
 
12888
  CHECK(context->Global()->ForceDelete(v8_str("foo")));
 
12889
  // Make sure the value for foo is read from the prototype, and that
 
12890
  // we don't get in trouble with reading the deleted cell value
 
12891
  // sentinel.
 
12892
  CHECK_EQ(5, CompileRun("f()")->Int32Value());
 
12893
}
 
12894
 
 
12895
 
 
12896
TEST(InlinedFunctionAcrossContexts) {
 
12897
  i::FLAG_allow_natives_syntax = true;
 
12898
  v8::HandleScope outer_scope;
 
12899
  v8::Persistent<v8::Context> ctx1 = v8::Context::New();
 
12900
  v8::Persistent<v8::Context> ctx2 = v8::Context::New();
 
12901
  ctx1->Enter();
 
12902
 
 
12903
  {
 
12904
    v8::HandleScope inner_scope;
 
12905
    CompileRun("var G = 42; function foo() { return G; }");
 
12906
    v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
 
12907
    ctx2->Enter();
 
12908
    ctx2->Global()->Set(v8_str("o"), foo);
 
12909
    v8::Local<v8::Value> res = CompileRun(
 
12910
        "function f() { return o(); }"
 
12911
        "for (var i = 0; i < 10; ++i) f();"
 
12912
        "%OptimizeFunctionOnNextCall(f);"
 
12913
        "f();");
 
12914
    CHECK_EQ(42, res->Int32Value());
 
12915
    ctx2->Exit();
 
12916
    v8::Handle<v8::String> G_property = v8::String::New("G");
 
12917
    CHECK(ctx1->Global()->ForceDelete(G_property));
 
12918
    ctx2->Enter();
 
12919
    ExpectString(
 
12920
        "(function() {"
 
12921
        "  try {"
 
12922
        "    return f();"
 
12923
        "  } catch(e) {"
 
12924
        "    return e.toString();"
 
12925
        "  }"
 
12926
        " })()",
 
12927
        "ReferenceError: G is not defined");
 
12928
    ctx2->Exit();
 
12929
    ctx1->Exit();
 
12930
    ctx1.Dispose();
 
12931
  }
 
12932
  ctx2.Dispose();
 
12933
}
 
12934
 
 
12935
 
 
12936
v8::Persistent<Context> calling_context0;
 
12937
v8::Persistent<Context> calling_context1;
 
12938
v8::Persistent<Context> calling_context2;
 
12939
 
 
12940
 
 
12941
// Check that the call to the callback is initiated in
 
12942
// calling_context2, the directly calling context is calling_context1
 
12943
// and the callback itself is in calling_context0.
 
12944
static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
 
12945
  ApiTestFuzzer::Fuzz();
 
12946
  CHECK(Context::GetCurrent() == calling_context0);
 
12947
  CHECK(Context::GetCalling() == calling_context1);
 
12948
  CHECK(Context::GetEntered() == calling_context2);
 
12949
  return v8::Integer::New(42);
 
12950
}
 
12951
 
 
12952
 
 
12953
THREADED_TEST(GetCallingContext) {
 
12954
  v8::HandleScope scope;
 
12955
 
 
12956
  calling_context0 = Context::New();
 
12957
  calling_context1 = Context::New();
 
12958
  calling_context2 = Context::New();
 
12959
 
 
12960
  // Allow cross-domain access.
 
12961
  Local<String> token = v8_str("<security token>");
 
12962
  calling_context0->SetSecurityToken(token);
 
12963
  calling_context1->SetSecurityToken(token);
 
12964
  calling_context2->SetSecurityToken(token);
 
12965
 
 
12966
  // Create an object with a C++ callback in context0.
 
12967
  calling_context0->Enter();
 
12968
  Local<v8::FunctionTemplate> callback_templ =
 
12969
      v8::FunctionTemplate::New(GetCallingContextCallback);
 
12970
  calling_context0->Global()->Set(v8_str("callback"),
 
12971
                                  callback_templ->GetFunction());
 
12972
  calling_context0->Exit();
 
12973
 
 
12974
  // Expose context0 in context1 and set up a function that calls the
 
12975
  // callback function.
 
12976
  calling_context1->Enter();
 
12977
  calling_context1->Global()->Set(v8_str("context0"),
 
12978
                                  calling_context0->Global());
 
12979
  CompileRun("function f() { context0.callback() }");
 
12980
  calling_context1->Exit();
 
12981
 
 
12982
  // Expose context1 in context2 and call the callback function in
 
12983
  // context0 indirectly through f in context1.
 
12984
  calling_context2->Enter();
 
12985
  calling_context2->Global()->Set(v8_str("context1"),
 
12986
                                  calling_context1->Global());
 
12987
  CompileRun("context1.f()");
 
12988
  calling_context2->Exit();
 
12989
 
 
12990
  // Dispose the contexts to allow them to be garbage collected.
 
12991
  calling_context0.Dispose();
 
12992
  calling_context1.Dispose();
 
12993
  calling_context2.Dispose();
 
12994
  calling_context0.Clear();
 
12995
  calling_context1.Clear();
 
12996
  calling_context2.Clear();
 
12997
}
 
12998
 
 
12999
 
 
13000
// Check that a variable declaration with no explicit initialization
 
13001
// value does shadow an existing property in the prototype chain.
 
13002
THREADED_TEST(InitGlobalVarInProtoChain) {
 
13003
  i::FLAG_es52_globals = true;
 
13004
  v8::HandleScope scope;
 
13005
  LocalContext context;
 
13006
  // Introduce a variable in the prototype chain.
 
13007
  CompileRun("__proto__.x = 42");
 
13008
  v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
 
13009
  CHECK(!result->IsUndefined());
 
13010
  CHECK_EQ(43, result->Int32Value());
 
13011
}
 
13012
 
 
13013
 
 
13014
// Regression test for issue 398.
 
13015
// If a function is added to an object, creating a constant function
 
13016
// field, and the result is cloned, replacing the constant function on the
 
13017
// original should not affect the clone.
 
13018
// See http://code.google.com/p/v8/issues/detail?id=398
 
13019
THREADED_TEST(ReplaceConstantFunction) {
 
13020
  v8::HandleScope scope;
 
13021
  LocalContext context;
 
13022
  v8::Handle<v8::Object> obj = v8::Object::New();
 
13023
  v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
 
13024
  v8::Handle<v8::String> foo_string = v8::String::New("foo");
 
13025
  obj->Set(foo_string, func_templ->GetFunction());
 
13026
  v8::Handle<v8::Object> obj_clone = obj->Clone();
 
13027
  obj_clone->Set(foo_string, v8::String::New("Hello"));
 
13028
  CHECK(!obj->Get(foo_string)->IsUndefined());
 
13029
}
 
13030
 
 
13031
 
 
13032
// Regression test for http://crbug.com/16276.
 
13033
THREADED_TEST(Regress16276) {
 
13034
  v8::HandleScope scope;
 
13035
  LocalContext context;
 
13036
  // Force the IC in f to be a dictionary load IC.
 
13037
  CompileRun("function f(obj) { return obj.x; }\n"
 
13038
             "var obj = { x: { foo: 42 }, y: 87 };\n"
 
13039
             "var x = obj.x;\n"
 
13040
             "delete obj.y;\n"
 
13041
             "for (var i = 0; i < 5; i++) f(obj);");
 
13042
  // Detach the global object to make 'this' refer directly to the
 
13043
  // global object (not the proxy), and make sure that the dictionary
 
13044
  // load IC doesn't mess up loading directly from the global object.
 
13045
  context->DetachGlobal();
 
13046
  CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
 
13047
}
 
13048
 
 
13049
 
 
13050
THREADED_TEST(PixelArray) {
 
13051
  v8::HandleScope scope;
 
13052
  LocalContext context;
 
13053
  const int kElementCount = 260;
 
13054
  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
 
13055
  i::Handle<i::ExternalPixelArray> pixels =
 
13056
      i::Handle<i::ExternalPixelArray>::cast(
 
13057
          FACTORY->NewExternalArray(kElementCount,
 
13058
                                    v8::kExternalPixelArray,
 
13059
                                    pixel_data));
 
13060
  // Force GC to trigger verification.
 
13061
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
13062
  for (int i = 0; i < kElementCount; i++) {
 
13063
    pixels->set(i, i % 256);
 
13064
  }
 
13065
  // Force GC to trigger verification.
 
13066
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
13067
  for (int i = 0; i < kElementCount; i++) {
 
13068
    CHECK_EQ(i % 256, pixels->get_scalar(i));
 
13069
    CHECK_EQ(i % 256, pixel_data[i]);
 
13070
  }
 
13071
 
 
13072
  v8::Handle<v8::Object> obj = v8::Object::New();
 
13073
  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
 
13074
  // Set the elements to be the pixels.
 
13075
  // jsobj->set_elements(*pixels);
 
13076
  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
 
13077
  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13078
  obj->Set(v8_str("field"), v8::Int32::New(1503));
 
13079
  context->Global()->Set(v8_str("pixels"), obj);
 
13080
  v8::Handle<v8::Value> result = CompileRun("pixels.field");
 
13081
  CHECK_EQ(1503, result->Int32Value());
 
13082
  result = CompileRun("pixels[1]");
 
13083
  CHECK_EQ(1, result->Int32Value());
 
13084
 
 
13085
  result = CompileRun("var sum = 0;"
 
13086
                      "for (var i = 0; i < 8; i++) {"
 
13087
                      "  sum += pixels[i] = pixels[i] = -i;"
 
13088
                      "}"
 
13089
                      "sum;");
 
13090
  CHECK_EQ(-28, result->Int32Value());
 
13091
 
 
13092
  result = CompileRun("var sum = 0;"
 
13093
                      "for (var i = 0; i < 8; i++) {"
 
13094
                      "  sum += pixels[i] = pixels[i] = 0;"
 
13095
                      "}"
 
13096
                      "sum;");
 
13097
  CHECK_EQ(0, result->Int32Value());
 
13098
 
 
13099
  result = CompileRun("var sum = 0;"
 
13100
                      "for (var i = 0; i < 8; i++) {"
 
13101
                      "  sum += pixels[i] = pixels[i] = 255;"
 
13102
                      "}"
 
13103
                      "sum;");
 
13104
  CHECK_EQ(8 * 255, result->Int32Value());
 
13105
 
 
13106
  result = CompileRun("var sum = 0;"
 
13107
                      "for (var i = 0; i < 8; i++) {"
 
13108
                      "  sum += pixels[i] = pixels[i] = 256 + i;"
 
13109
                      "}"
 
13110
                      "sum;");
 
13111
  CHECK_EQ(2076, result->Int32Value());
 
13112
 
 
13113
  result = CompileRun("var sum = 0;"
 
13114
                      "for (var i = 0; i < 8; i++) {"
 
13115
                      "  sum += pixels[i] = pixels[i] = i;"
 
13116
                      "}"
 
13117
                      "sum;");
 
13118
  CHECK_EQ(28, result->Int32Value());
 
13119
 
 
13120
  result = CompileRun("var sum = 0;"
 
13121
                      "for (var i = 0; i < 8; i++) {"
 
13122
                      "  sum += pixels[i];"
 
13123
                      "}"
 
13124
                      "sum;");
 
13125
  CHECK_EQ(28, result->Int32Value());
 
13126
 
 
13127
  i::Handle<i::Smi> value(i::Smi::FromInt(2));
 
13128
  i::Handle<i::Object> no_failure;
 
13129
  no_failure =
 
13130
      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
 
13131
  ASSERT(!no_failure.is_null());
 
13132
  i::USE(no_failure);
 
13133
  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13134
  *value.location() = i::Smi::FromInt(256);
 
13135
  no_failure =
 
13136
      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
 
13137
  ASSERT(!no_failure.is_null());
 
13138
  i::USE(no_failure);
 
13139
  CHECK_EQ(255,
 
13140
           i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13141
  *value.location() = i::Smi::FromInt(-1);
 
13142
  no_failure =
 
13143
      i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
 
13144
  ASSERT(!no_failure.is_null());
 
13145
  i::USE(no_failure);
 
13146
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13147
 
 
13148
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13149
                      "  pixels[i] = (i * 65) - 109;"
 
13150
                      "}"
 
13151
                      "pixels[1] + pixels[6];");
 
13152
  CHECK_EQ(255, result->Int32Value());
 
13153
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
 
13154
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13155
  CHECK_EQ(21,
 
13156
           i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
 
13157
  CHECK_EQ(86,
 
13158
           i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
 
13159
  CHECK_EQ(151,
 
13160
           i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
 
13161
  CHECK_EQ(216,
 
13162
           i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13163
  CHECK_EQ(255,
 
13164
           i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
 
13165
  CHECK_EQ(255,
 
13166
           i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
 
13167
  result = CompileRun("var sum = 0;"
 
13168
                      "for (var i = 0; i < 8; i++) {"
 
13169
                      "  sum += pixels[i];"
 
13170
                      "}"
 
13171
                      "sum;");
 
13172
  CHECK_EQ(984, result->Int32Value());
 
13173
 
 
13174
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13175
                      "  pixels[i] = (i * 1.1);"
 
13176
                      "}"
 
13177
                      "pixels[1] + pixels[6];");
 
13178
  CHECK_EQ(8, result->Int32Value());
 
13179
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
 
13180
  CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
 
13181
  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
 
13182
  CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
 
13183
  CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
 
13184
  CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13185
  CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
 
13186
  CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
 
13187
 
 
13188
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13189
                      "  pixels[7] = undefined;"
 
13190
                      "}"
 
13191
                      "pixels[7];");
 
13192
  CHECK_EQ(0, result->Int32Value());
 
13193
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
 
13194
 
 
13195
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13196
                      "  pixels[6] = '2.3';"
 
13197
                      "}"
 
13198
                      "pixels[6];");
 
13199
  CHECK_EQ(2, result->Int32Value());
 
13200
  CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
 
13201
 
 
13202
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13203
                      "  pixels[5] = NaN;"
 
13204
                      "}"
 
13205
                      "pixels[5];");
 
13206
  CHECK_EQ(0, result->Int32Value());
 
13207
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13208
 
 
13209
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13210
                      "  pixels[8] = Infinity;"
 
13211
                      "}"
 
13212
                      "pixels[8];");
 
13213
  CHECK_EQ(255, result->Int32Value());
 
13214
  CHECK_EQ(255,
 
13215
           i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
 
13216
 
 
13217
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13218
                      "  pixels[9] = -Infinity;"
 
13219
                      "}"
 
13220
                      "pixels[9];");
 
13221
  CHECK_EQ(0, result->Int32Value());
 
13222
  CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
 
13223
 
 
13224
  result = CompileRun("pixels[3] = 33;"
 
13225
                      "delete pixels[3];"
 
13226
                      "pixels[3];");
 
13227
  CHECK_EQ(33, result->Int32Value());
 
13228
 
 
13229
  result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
 
13230
                      "pixels[2] = 12; pixels[3] = 13;"
 
13231
                      "pixels.__defineGetter__('2',"
 
13232
                      "function() { return 120; });"
 
13233
                      "pixels[2];");
 
13234
  CHECK_EQ(12, result->Int32Value());
 
13235
 
 
13236
  result = CompileRun("var js_array = new Array(40);"
 
13237
                      "js_array[0] = 77;"
 
13238
                      "js_array;");
 
13239
  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
 
13240
 
 
13241
  result = CompileRun("pixels[1] = 23;"
 
13242
                      "pixels.__proto__ = [];"
 
13243
                      "js_array.__proto__ = pixels;"
 
13244
                      "js_array.concat(pixels);");
 
13245
  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
 
13246
  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
 
13247
 
 
13248
  result = CompileRun("pixels[1] = 23;");
 
13249
  CHECK_EQ(23, result->Int32Value());
 
13250
 
 
13251
  // Test for index greater than 255.  Regression test for:
 
13252
  // http://code.google.com/p/chromium/issues/detail?id=26337.
 
13253
  result = CompileRun("pixels[256] = 255;");
 
13254
  CHECK_EQ(255, result->Int32Value());
 
13255
  result = CompileRun("var i = 0;"
 
13256
                      "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
 
13257
                      "i");
 
13258
  CHECK_EQ(255, result->Int32Value());
 
13259
 
 
13260
  // Make sure that pixel array ICs recognize when a non-pixel array
 
13261
  // is passed to it.
 
13262
  result = CompileRun("function pa_load(p) {"
 
13263
                      "  var sum = 0;"
 
13264
                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
 
13265
                      "  return sum;"
 
13266
                      "}"
 
13267
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13268
                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
 
13269
                      "just_ints = new Object();"
 
13270
                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
 
13271
                      "for (var i = 0; i < 10; ++i) {"
 
13272
                      "  result = pa_load(just_ints);"
 
13273
                      "}"
 
13274
                      "result");
 
13275
  CHECK_EQ(32640, result->Int32Value());
 
13276
 
 
13277
  // Make sure that pixel array ICs recognize out-of-bound accesses.
 
13278
  result = CompileRun("function pa_load(p, start) {"
 
13279
                      "  var sum = 0;"
 
13280
                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
 
13281
                      "  return sum;"
 
13282
                      "}"
 
13283
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13284
                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
 
13285
                      "for (var i = 0; i < 10; ++i) {"
 
13286
                      "  result = pa_load(pixels,-10);"
 
13287
                      "}"
 
13288
                      "result");
 
13289
  CHECK_EQ(0, result->Int32Value());
 
13290
 
 
13291
  // Make sure that generic ICs properly handles a pixel array.
 
13292
  result = CompileRun("function pa_load(p) {"
 
13293
                      "  var sum = 0;"
 
13294
                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
 
13295
                      "  return sum;"
 
13296
                      "}"
 
13297
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13298
                      "just_ints = new Object();"
 
13299
                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
 
13300
                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
 
13301
                      "for (var i = 0; i < 10; ++i) {"
 
13302
                      "  result = pa_load(pixels);"
 
13303
                      "}"
 
13304
                      "result");
 
13305
  CHECK_EQ(32640, result->Int32Value());
 
13306
 
 
13307
  // Make sure that generic load ICs recognize out-of-bound accesses in
 
13308
  // pixel arrays.
 
13309
  result = CompileRun("function pa_load(p, start) {"
 
13310
                      "  var sum = 0;"
 
13311
                      "  for (var j = start; j < 256; j++) { sum += p[j]; }"
 
13312
                      "  return sum;"
 
13313
                      "}"
 
13314
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13315
                      "just_ints = new Object();"
 
13316
                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
 
13317
                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
 
13318
                      "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
 
13319
                      "for (var i = 0; i < 10; ++i) {"
 
13320
                      "  result = pa_load(pixels,-10);"
 
13321
                      "}"
 
13322
                      "result");
 
13323
  CHECK_EQ(0, result->Int32Value());
 
13324
 
 
13325
  // Make sure that generic ICs properly handles other types than pixel
 
13326
  // arrays (that the inlined fast pixel array test leaves the right information
 
13327
  // in the right registers).
 
13328
  result = CompileRun("function pa_load(p) {"
 
13329
                      "  var sum = 0;"
 
13330
                      "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
 
13331
                      "  return sum;"
 
13332
                      "}"
 
13333
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13334
                      "just_ints = new Object();"
 
13335
                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
 
13336
                      "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
 
13337
                      "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
 
13338
                      "sparse_array = new Object();"
 
13339
                      "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
 
13340
                      "sparse_array[1000000] = 3;"
 
13341
                      "for (var i = 0; i < 10; ++i) {"
 
13342
                      "  result = pa_load(sparse_array);"
 
13343
                      "}"
 
13344
                      "result");
 
13345
  CHECK_EQ(32640, result->Int32Value());
 
13346
 
 
13347
  // Make sure that pixel array store ICs clamp values correctly.
 
13348
  result = CompileRun("function pa_store(p) {"
 
13349
                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
 
13350
                      "}"
 
13351
                      "pa_store(pixels);"
 
13352
                      "var sum = 0;"
 
13353
                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
 
13354
                      "sum");
 
13355
  CHECK_EQ(48896, result->Int32Value());
 
13356
 
 
13357
  // Make sure that pixel array stores correctly handle accesses outside
 
13358
  // of the pixel array..
 
13359
  result = CompileRun("function pa_store(p,start) {"
 
13360
                      "  for (var j = 0; j < 256; j++) {"
 
13361
                      "    p[j+start] = j * 2;"
 
13362
                      "  }"
 
13363
                      "}"
 
13364
                      "pa_store(pixels,0);"
 
13365
                      "pa_store(pixels,-128);"
 
13366
                      "var sum = 0;"
 
13367
                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
 
13368
                      "sum");
 
13369
  CHECK_EQ(65280, result->Int32Value());
 
13370
 
 
13371
  // Make sure that the generic store stub correctly handle accesses outside
 
13372
  // of the pixel array..
 
13373
  result = CompileRun("function pa_store(p,start) {"
 
13374
                      "  for (var j = 0; j < 256; j++) {"
 
13375
                      "    p[j+start] = j * 2;"
 
13376
                      "  }"
 
13377
                      "}"
 
13378
                      "pa_store(pixels,0);"
 
13379
                      "just_ints = new Object();"
 
13380
                      "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
 
13381
                      "pa_store(just_ints, 0);"
 
13382
                      "pa_store(pixels,-128);"
 
13383
                      "var sum = 0;"
 
13384
                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
 
13385
                      "sum");
 
13386
  CHECK_EQ(65280, result->Int32Value());
 
13387
 
 
13388
  // Make sure that the generic keyed store stub clamps pixel array values
 
13389
  // correctly.
 
13390
  result = CompileRun("function pa_store(p) {"
 
13391
                      "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
 
13392
                      "}"
 
13393
                      "pa_store(pixels);"
 
13394
                      "just_ints = new Object();"
 
13395
                      "pa_store(just_ints);"
 
13396
                      "pa_store(pixels);"
 
13397
                      "var sum = 0;"
 
13398
                      "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
 
13399
                      "sum");
 
13400
  CHECK_EQ(48896, result->Int32Value());
 
13401
 
 
13402
  // Make sure that pixel array loads are optimized by crankshaft.
 
13403
  result = CompileRun("function pa_load(p) {"
 
13404
                      "  var sum = 0;"
 
13405
                      "  for (var i=0; i<256; ++i) {"
 
13406
                      "    sum += p[i];"
 
13407
                      "  }"
 
13408
                      "  return sum; "
 
13409
                      "}"
 
13410
                      "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
 
13411
                      "for (var i = 0; i < 5000; ++i) {"
 
13412
                      "  result = pa_load(pixels);"
 
13413
                      "}"
 
13414
                      "result");
 
13415
  CHECK_EQ(32640, result->Int32Value());
 
13416
 
 
13417
  // Make sure that pixel array stores are optimized by crankshaft.
 
13418
  result = CompileRun("function pa_init(p) {"
 
13419
                      "for (var i = 0; i < 256; ++i) { p[i] = i; }"
 
13420
                      "}"
 
13421
                      "function pa_load(p) {"
 
13422
                      "  var sum = 0;"
 
13423
                      "  for (var i=0; i<256; ++i) {"
 
13424
                      "    sum += p[i];"
 
13425
                      "  }"
 
13426
                      "  return sum; "
 
13427
                      "}"
 
13428
                      "for (var i = 0; i < 5000; ++i) {"
 
13429
                      "  pa_init(pixels);"
 
13430
                      "}"
 
13431
                      "result = pa_load(pixels);"
 
13432
                      "result");
 
13433
  CHECK_EQ(32640, result->Int32Value());
 
13434
 
 
13435
  free(pixel_data);
 
13436
}
 
13437
 
 
13438
 
 
13439
THREADED_TEST(PixelArrayInfo) {
 
13440
  v8::HandleScope scope;
 
13441
  LocalContext context;
 
13442
  for (int size = 0; size < 100; size += 10) {
 
13443
    uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
 
13444
    v8::Handle<v8::Object> obj = v8::Object::New();
 
13445
    obj->SetIndexedPropertiesToPixelData(pixel_data, size);
 
13446
    CHECK(obj->HasIndexedPropertiesInPixelData());
 
13447
    CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
 
13448
    CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
 
13449
    free(pixel_data);
 
13450
  }
 
13451
}
 
13452
 
 
13453
 
 
13454
static v8::Handle<Value> NotHandledIndexedPropertyGetter(
 
13455
    uint32_t index,
 
13456
    const AccessorInfo& info) {
 
13457
  ApiTestFuzzer::Fuzz();
 
13458
  return v8::Handle<Value>();
 
13459
}
 
13460
 
 
13461
 
 
13462
static v8::Handle<Value> NotHandledIndexedPropertySetter(
 
13463
    uint32_t index,
 
13464
    Local<Value> value,
 
13465
    const AccessorInfo& info) {
 
13466
  ApiTestFuzzer::Fuzz();
 
13467
  return v8::Handle<Value>();
 
13468
}
 
13469
 
 
13470
 
 
13471
THREADED_TEST(PixelArrayWithInterceptor) {
 
13472
  v8::HandleScope scope;
 
13473
  LocalContext context;
 
13474
  const int kElementCount = 260;
 
13475
  uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
 
13476
  i::Handle<i::ExternalPixelArray> pixels =
 
13477
      i::Handle<i::ExternalPixelArray>::cast(
 
13478
          FACTORY->NewExternalArray(kElementCount,
 
13479
                                    v8::kExternalPixelArray,
 
13480
                                    pixel_data));
 
13481
  for (int i = 0; i < kElementCount; i++) {
 
13482
    pixels->set(i, i % 256);
 
13483
  }
 
13484
  v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
 
13485
  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
 
13486
                                   NotHandledIndexedPropertySetter);
 
13487
  v8::Handle<v8::Object> obj = templ->NewInstance();
 
13488
  obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
 
13489
  context->Global()->Set(v8_str("pixels"), obj);
 
13490
  v8::Handle<v8::Value> result = CompileRun("pixels[1]");
 
13491
  CHECK_EQ(1, result->Int32Value());
 
13492
  result = CompileRun("var sum = 0;"
 
13493
                      "for (var i = 0; i < 8; i++) {"
 
13494
                      "  sum += pixels[i] = pixels[i] = -i;"
 
13495
                      "}"
 
13496
                      "sum;");
 
13497
  CHECK_EQ(-28, result->Int32Value());
 
13498
  result = CompileRun("pixels.hasOwnProperty('1')");
 
13499
  CHECK(result->BooleanValue());
 
13500
  free(pixel_data);
 
13501
}
 
13502
 
 
13503
 
 
13504
static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
 
13505
  switch (array_type) {
 
13506
    case v8::kExternalByteArray:
 
13507
    case v8::kExternalUnsignedByteArray:
 
13508
    case v8::kExternalPixelArray:
 
13509
      return 1;
 
13510
      break;
 
13511
    case v8::kExternalShortArray:
 
13512
    case v8::kExternalUnsignedShortArray:
 
13513
      return 2;
 
13514
      break;
 
13515
    case v8::kExternalIntArray:
 
13516
    case v8::kExternalUnsignedIntArray:
 
13517
    case v8::kExternalFloatArray:
 
13518
      return 4;
 
13519
      break;
 
13520
    case v8::kExternalDoubleArray:
 
13521
      return 8;
 
13522
      break;
 
13523
    default:
 
13524
      UNREACHABLE();
 
13525
      return -1;
 
13526
  }
 
13527
  UNREACHABLE();
 
13528
  return -1;
 
13529
}
 
13530
 
 
13531
 
 
13532
template <class ExternalArrayClass, class ElementType>
 
13533
static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
 
13534
                                    int64_t low,
 
13535
                                    int64_t high) {
 
13536
  v8::HandleScope scope;
 
13537
  LocalContext context;
 
13538
  const int kElementCount = 40;
 
13539
  int element_size = ExternalArrayElementSize(array_type);
 
13540
  ElementType* array_data =
 
13541
      static_cast<ElementType*>(malloc(kElementCount * element_size));
 
13542
  i::Handle<ExternalArrayClass> array =
 
13543
      i::Handle<ExternalArrayClass>::cast(
 
13544
          FACTORY->NewExternalArray(kElementCount, array_type, array_data));
 
13545
  // Force GC to trigger verification.
 
13546
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
13547
  for (int i = 0; i < kElementCount; i++) {
 
13548
    array->set(i, static_cast<ElementType>(i));
 
13549
  }
 
13550
  // Force GC to trigger verification.
 
13551
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
13552
  for (int i = 0; i < kElementCount; i++) {
 
13553
    CHECK_EQ(static_cast<int64_t>(i),
 
13554
             static_cast<int64_t>(array->get_scalar(i)));
 
13555
    CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
 
13556
  }
 
13557
 
 
13558
  v8::Handle<v8::Object> obj = v8::Object::New();
 
13559
  i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
 
13560
  // Set the elements to be the external array.
 
13561
  obj->SetIndexedPropertiesToExternalArrayData(array_data,
 
13562
                                               array_type,
 
13563
                                               kElementCount);
 
13564
  CHECK_EQ(
 
13565
      1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
 
13566
  obj->Set(v8_str("field"), v8::Int32::New(1503));
 
13567
  context->Global()->Set(v8_str("ext_array"), obj);
 
13568
  v8::Handle<v8::Value> result = CompileRun("ext_array.field");
 
13569
  CHECK_EQ(1503, result->Int32Value());
 
13570
  result = CompileRun("ext_array[1]");
 
13571
  CHECK_EQ(1, result->Int32Value());
 
13572
 
 
13573
  // Check pass through of assigned smis
 
13574
  result = CompileRun("var sum = 0;"
 
13575
                      "for (var i = 0; i < 8; i++) {"
 
13576
                      "  sum += ext_array[i] = ext_array[i] = -i;"
 
13577
                      "}"
 
13578
                      "sum;");
 
13579
  CHECK_EQ(-28, result->Int32Value());
 
13580
 
 
13581
  // Check assigned smis
 
13582
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13583
                      "  ext_array[i] = i;"
 
13584
                      "}"
 
13585
                      "var sum = 0;"
 
13586
                      "for (var i = 0; i < 8; i++) {"
 
13587
                      "  sum += ext_array[i];"
 
13588
                      "}"
 
13589
                      "sum;");
 
13590
  CHECK_EQ(28, result->Int32Value());
 
13591
 
 
13592
  // Check assigned smis in reverse order
 
13593
  result = CompileRun("for (var i = 8; --i >= 0; ) {"
 
13594
                      "  ext_array[i] = i;"
 
13595
                      "}"
 
13596
                      "var sum = 0;"
 
13597
                      "for (var i = 0; i < 8; i++) {"
 
13598
                      "  sum += ext_array[i];"
 
13599
                      "}"
 
13600
                      "sum;");
 
13601
  CHECK_EQ(28, result->Int32Value());
 
13602
 
 
13603
  // Check pass through of assigned HeapNumbers
 
13604
  result = CompileRun("var sum = 0;"
 
13605
                      "for (var i = 0; i < 16; i+=2) {"
 
13606
                      "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
 
13607
                      "}"
 
13608
                      "sum;");
 
13609
  CHECK_EQ(-28, result->Int32Value());
 
13610
 
 
13611
  // Check assigned HeapNumbers
 
13612
  result = CompileRun("for (var i = 0; i < 16; i+=2) {"
 
13613
                      "  ext_array[i] = (i * 0.5);"
 
13614
                      "}"
 
13615
                      "var sum = 0;"
 
13616
                      "for (var i = 0; i < 16; i+=2) {"
 
13617
                      "  sum += ext_array[i];"
 
13618
                      "}"
 
13619
                      "sum;");
 
13620
  CHECK_EQ(28, result->Int32Value());
 
13621
 
 
13622
  // Check assigned HeapNumbers in reverse order
 
13623
  result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
 
13624
                      "  ext_array[i] = (i * 0.5);"
 
13625
                      "}"
 
13626
                      "var sum = 0;"
 
13627
                      "for (var i = 0; i < 16; i+=2) {"
 
13628
                      "  sum += ext_array[i];"
 
13629
                      "}"
 
13630
                      "sum;");
 
13631
  CHECK_EQ(28, result->Int32Value());
 
13632
 
 
13633
  i::ScopedVector<char> test_buf(1024);
 
13634
 
 
13635
  // Check legal boundary conditions.
 
13636
  // The repeated loads and stores ensure the ICs are exercised.
 
13637
  const char* boundary_program =
 
13638
      "var res = 0;"
 
13639
      "for (var i = 0; i < 16; i++) {"
 
13640
      "  ext_array[i] = %lld;"
 
13641
      "  if (i > 8) {"
 
13642
      "    res = ext_array[i];"
 
13643
      "  }"
 
13644
      "}"
 
13645
      "res;";
 
13646
  i::OS::SNPrintF(test_buf,
 
13647
                  boundary_program,
 
13648
                  low);
 
13649
  result = CompileRun(test_buf.start());
 
13650
  CHECK_EQ(low, result->IntegerValue());
 
13651
 
 
13652
  i::OS::SNPrintF(test_buf,
 
13653
                  boundary_program,
 
13654
                  high);
 
13655
  result = CompileRun(test_buf.start());
 
13656
  CHECK_EQ(high, result->IntegerValue());
 
13657
 
 
13658
  // Check misprediction of type in IC.
 
13659
  result = CompileRun("var tmp_array = ext_array;"
 
13660
                      "var sum = 0;"
 
13661
                      "for (var i = 0; i < 8; i++) {"
 
13662
                      "  tmp_array[i] = i;"
 
13663
                      "  sum += tmp_array[i];"
 
13664
                      "  if (i == 4) {"
 
13665
                      "    tmp_array = {};"
 
13666
                      "  }"
 
13667
                      "}"
 
13668
                      "sum;");
 
13669
  // Force GC to trigger verification.
 
13670
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
13671
  CHECK_EQ(28, result->Int32Value());
 
13672
 
 
13673
  // Make sure out-of-range loads do not throw.
 
13674
  i::OS::SNPrintF(test_buf,
 
13675
                  "var caught_exception = false;"
 
13676
                  "try {"
 
13677
                  "  ext_array[%d];"
 
13678
                  "} catch (e) {"
 
13679
                  "  caught_exception = true;"
 
13680
                  "}"
 
13681
                  "caught_exception;",
 
13682
                  kElementCount);
 
13683
  result = CompileRun(test_buf.start());
 
13684
  CHECK_EQ(false, result->BooleanValue());
 
13685
 
 
13686
  // Make sure out-of-range stores do not throw.
 
13687
  i::OS::SNPrintF(test_buf,
 
13688
                  "var caught_exception = false;"
 
13689
                  "try {"
 
13690
                  "  ext_array[%d] = 1;"
 
13691
                  "} catch (e) {"
 
13692
                  "  caught_exception = true;"
 
13693
                  "}"
 
13694
                  "caught_exception;",
 
13695
                  kElementCount);
 
13696
  result = CompileRun(test_buf.start());
 
13697
  CHECK_EQ(false, result->BooleanValue());
 
13698
 
 
13699
  // Check other boundary conditions, values and operations.
 
13700
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13701
                      "  ext_array[7] = undefined;"
 
13702
                      "}"
 
13703
                      "ext_array[7];");
 
13704
  CHECK_EQ(0, result->Int32Value());
 
13705
  if (array_type == v8::kExternalDoubleArray ||
 
13706
      array_type == v8::kExternalFloatArray) {
 
13707
    CHECK_EQ(
 
13708
        static_cast<int>(i::OS::nan_value()),
 
13709
        static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
 
13710
  } else {
 
13711
    CHECK_EQ(0, static_cast<int>(
 
13712
        jsobj->GetElement(7)->ToObjectChecked()->Number()));
 
13713
  }
 
13714
 
 
13715
  result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13716
                      "  ext_array[6] = '2.3';"
 
13717
                      "}"
 
13718
                      "ext_array[6];");
 
13719
  CHECK_EQ(2, result->Int32Value());
 
13720
  CHECK_EQ(
 
13721
      2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
 
13722
 
 
13723
  if (array_type != v8::kExternalFloatArray &&
 
13724
      array_type != v8::kExternalDoubleArray) {
 
13725
    // Though the specification doesn't state it, be explicit about
 
13726
    // converting NaNs and +/-Infinity to zero.
 
13727
    result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13728
                        "  ext_array[i] = 5;"
 
13729
                        "}"
 
13730
                        "for (var i = 0; i < 8; i++) {"
 
13731
                        "  ext_array[i] = NaN;"
 
13732
                        "}"
 
13733
                        "ext_array[5];");
 
13734
    CHECK_EQ(0, result->Int32Value());
 
13735
    CHECK_EQ(0,
 
13736
             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13737
 
 
13738
    result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13739
                        "  ext_array[i] = 5;"
 
13740
                        "}"
 
13741
                        "for (var i = 0; i < 8; i++) {"
 
13742
                        "  ext_array[i] = Infinity;"
 
13743
                        "}"
 
13744
                        "ext_array[5];");
 
13745
    int expected_value =
 
13746
        (array_type == v8::kExternalPixelArray) ? 255 : 0;
 
13747
    CHECK_EQ(expected_value, result->Int32Value());
 
13748
    CHECK_EQ(expected_value,
 
13749
             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13750
 
 
13751
    result = CompileRun("for (var i = 0; i < 8; i++) {"
 
13752
                        "  ext_array[i] = 5;"
 
13753
                        "}"
 
13754
                        "for (var i = 0; i < 8; i++) {"
 
13755
                        "  ext_array[i] = -Infinity;"
 
13756
                        "}"
 
13757
                        "ext_array[5];");
 
13758
    CHECK_EQ(0, result->Int32Value());
 
13759
    CHECK_EQ(0,
 
13760
             i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
 
13761
 
 
13762
    // Check truncation behavior of integral arrays.
 
13763
    const char* unsigned_data =
 
13764
        "var source_data = [0.6, 10.6];"
 
13765
        "var expected_results = [0, 10];";
 
13766
    const char* signed_data =
 
13767
        "var source_data = [0.6, 10.6, -0.6, -10.6];"
 
13768
        "var expected_results = [0, 10, 0, -10];";
 
13769
    const char* pixel_data =
 
13770
        "var source_data = [0.6, 10.6];"
 
13771
        "var expected_results = [1, 11];";
 
13772
    bool is_unsigned =
 
13773
        (array_type == v8::kExternalUnsignedByteArray ||
 
13774
         array_type == v8::kExternalUnsignedShortArray ||
 
13775
         array_type == v8::kExternalUnsignedIntArray);
 
13776
    bool is_pixel_data = array_type == v8::kExternalPixelArray;
 
13777
 
 
13778
    i::OS::SNPrintF(test_buf,
 
13779
                    "%s"
 
13780
                    "var all_passed = true;"
 
13781
                    "for (var i = 0; i < source_data.length; i++) {"
 
13782
                    "  for (var j = 0; j < 8; j++) {"
 
13783
                    "    ext_array[j] = source_data[i];"
 
13784
                    "  }"
 
13785
                    "  all_passed = all_passed &&"
 
13786
                    "               (ext_array[5] == expected_results[i]);"
 
13787
                    "}"
 
13788
                    "all_passed;",
 
13789
                    (is_unsigned ?
 
13790
                         unsigned_data :
 
13791
                         (is_pixel_data ? pixel_data : signed_data)));
 
13792
    result = CompileRun(test_buf.start());
 
13793
    CHECK_EQ(true, result->BooleanValue());
 
13794
  }
 
13795
 
 
13796
  for (int i = 0; i < kElementCount; i++) {
 
13797
    array->set(i, static_cast<ElementType>(i));
 
13798
  }
 
13799
  // Test complex assignments
 
13800
  result = CompileRun("function ee_op_test_complex_func(sum) {"
 
13801
                      " for (var i = 0; i < 40; ++i) {"
 
13802
                      "   sum += (ext_array[i] += 1);"
 
13803
                      "   sum += (ext_array[i] -= 1);"
 
13804
                      " } "
 
13805
                      " return sum;"
 
13806
                      "}"
 
13807
                      "sum=0;"
 
13808
                      "for (var i=0;i<10000;++i) {"
 
13809
                      "  sum=ee_op_test_complex_func(sum);"
 
13810
                      "}"
 
13811
                      "sum;");
 
13812
  CHECK_EQ(16000000, result->Int32Value());
 
13813
 
 
13814
  // Test count operations
 
13815
  result = CompileRun("function ee_op_test_count_func(sum) {"
 
13816
                      " for (var i = 0; i < 40; ++i) {"
 
13817
                      "   sum += (++ext_array[i]);"
 
13818
                      "   sum += (--ext_array[i]);"
 
13819
                      " } "
 
13820
                      " return sum;"
 
13821
                      "}"
 
13822
                      "sum=0;"
 
13823
                      "for (var i=0;i<10000;++i) {"
 
13824
                      "  sum=ee_op_test_count_func(sum);"
 
13825
                      "}"
 
13826
                      "sum;");
 
13827
  CHECK_EQ(16000000, result->Int32Value());
 
13828
 
 
13829
  result = CompileRun("ext_array[3] = 33;"
 
13830
                      "delete ext_array[3];"
 
13831
                      "ext_array[3];");
 
13832
  CHECK_EQ(33, result->Int32Value());
 
13833
 
 
13834
  result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
 
13835
                      "ext_array[2] = 12; ext_array[3] = 13;"
 
13836
                      "ext_array.__defineGetter__('2',"
 
13837
                      "function() { return 120; });"
 
13838
                      "ext_array[2];");
 
13839
  CHECK_EQ(12, result->Int32Value());
 
13840
 
 
13841
  result = CompileRun("var js_array = new Array(40);"
 
13842
                      "js_array[0] = 77;"
 
13843
                      "js_array;");
 
13844
  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
 
13845
 
 
13846
  result = CompileRun("ext_array[1] = 23;"
 
13847
                      "ext_array.__proto__ = [];"
 
13848
                      "js_array.__proto__ = ext_array;"
 
13849
                      "js_array.concat(ext_array);");
 
13850
  CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
 
13851
  CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
 
13852
 
 
13853
  result = CompileRun("ext_array[1] = 23;");
 
13854
  CHECK_EQ(23, result->Int32Value());
 
13855
 
 
13856
  // Test more complex manipulations which cause eax to contain values
 
13857
  // that won't be completely overwritten by loads from the arrays.
 
13858
  // This catches bugs in the instructions used for the KeyedLoadIC
 
13859
  // for byte and word types.
 
13860
  {
 
13861
    const int kXSize = 300;
 
13862
    const int kYSize = 300;
 
13863
    const int kLargeElementCount = kXSize * kYSize * 4;
 
13864
    ElementType* large_array_data =
 
13865
        static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
 
13866
    v8::Handle<v8::Object> large_obj = v8::Object::New();
 
13867
    // Set the elements to be the external array.
 
13868
    large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
 
13869
                                                       array_type,
 
13870
                                                       kLargeElementCount);
 
13871
    context->Global()->Set(v8_str("large_array"), large_obj);
 
13872
    // Initialize contents of a few rows.
 
13873
    for (int x = 0; x < 300; x++) {
 
13874
      int row = 0;
 
13875
      int offset = row * 300 * 4;
 
13876
      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
 
13877
      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
 
13878
      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
 
13879
      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
 
13880
      row = 150;
 
13881
      offset = row * 300 * 4;
 
13882
      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
 
13883
      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
 
13884
      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
 
13885
      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
 
13886
      row = 298;
 
13887
      offset = row * 300 * 4;
 
13888
      large_array_data[offset + 4 * x + 0] = (ElementType) 127;
 
13889
      large_array_data[offset + 4 * x + 1] = (ElementType) 0;
 
13890
      large_array_data[offset + 4 * x + 2] = (ElementType) 0;
 
13891
      large_array_data[offset + 4 * x + 3] = (ElementType) 127;
 
13892
    }
 
13893
    // The goal of the code below is to make "offset" large enough
 
13894
    // that the computation of the index (which goes into eax) has
 
13895
    // high bits set which will not be overwritten by a byte or short
 
13896
    // load.
 
13897
    result = CompileRun("var failed = false;"
 
13898
                        "var offset = 0;"
 
13899
                        "for (var i = 0; i < 300; i++) {"
 
13900
                        "  if (large_array[4 * i] != 127 ||"
 
13901
                        "      large_array[4 * i + 1] != 0 ||"
 
13902
                        "      large_array[4 * i + 2] != 0 ||"
 
13903
                        "      large_array[4 * i + 3] != 127) {"
 
13904
                        "    failed = true;"
 
13905
                        "  }"
 
13906
                        "}"
 
13907
                        "offset = 150 * 300 * 4;"
 
13908
                        "for (var i = 0; i < 300; i++) {"
 
13909
                        "  if (large_array[offset + 4 * i] != 127 ||"
 
13910
                        "      large_array[offset + 4 * i + 1] != 0 ||"
 
13911
                        "      large_array[offset + 4 * i + 2] != 0 ||"
 
13912
                        "      large_array[offset + 4 * i + 3] != 127) {"
 
13913
                        "    failed = true;"
 
13914
                        "  }"
 
13915
                        "}"
 
13916
                        "offset = 298 * 300 * 4;"
 
13917
                        "for (var i = 0; i < 300; i++) {"
 
13918
                        "  if (large_array[offset + 4 * i] != 127 ||"
 
13919
                        "      large_array[offset + 4 * i + 1] != 0 ||"
 
13920
                        "      large_array[offset + 4 * i + 2] != 0 ||"
 
13921
                        "      large_array[offset + 4 * i + 3] != 127) {"
 
13922
                        "    failed = true;"
 
13923
                        "  }"
 
13924
                        "}"
 
13925
                        "!failed;");
 
13926
    CHECK_EQ(true, result->BooleanValue());
 
13927
    free(large_array_data);
 
13928
  }
 
13929
 
 
13930
  // The "" property descriptor is overloaded to store information about
 
13931
  // the external array. Ensure that setting and accessing the "" property
 
13932
  // works (it should overwrite the information cached about the external
 
13933
  // array in the DescriptorArray) in various situations.
 
13934
  result = CompileRun("ext_array[''] = 23; ext_array['']");
 
13935
  CHECK_EQ(23, result->Int32Value());
 
13936
 
 
13937
  // Property "" set after the external array is associated with the object.
 
13938
  {
 
13939
    v8::Handle<v8::Object> obj2 = v8::Object::New();
 
13940
    obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
 
13941
    obj2->Set(v8_str(""), v8::Int32::New(1503));
 
13942
    // Set the elements to be the external array.
 
13943
    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
 
13944
                                                  array_type,
 
13945
                                                  kElementCount);
 
13946
    context->Global()->Set(v8_str("ext_array"), obj2);
 
13947
    result = CompileRun("ext_array['']");
 
13948
    CHECK_EQ(1503, result->Int32Value());
 
13949
  }
 
13950
 
 
13951
  // Property "" set after the external array is associated with the object.
 
13952
  {
 
13953
    v8::Handle<v8::Object> obj2 = v8::Object::New();
 
13954
    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
 
13955
    // Set the elements to be the external array.
 
13956
    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
 
13957
                                                  array_type,
 
13958
                                                  kElementCount);
 
13959
    obj2->Set(v8_str(""), v8::Int32::New(1503));
 
13960
    context->Global()->Set(v8_str("ext_array"), obj2);
 
13961
    result = CompileRun("ext_array['']");
 
13962
    CHECK_EQ(1503, result->Int32Value());
 
13963
  }
 
13964
 
 
13965
  // Should reuse the map from previous test.
 
13966
  {
 
13967
    v8::Handle<v8::Object> obj2 = v8::Object::New();
 
13968
    obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
 
13969
    // Set the elements to be the external array. Should re-use the map
 
13970
    // from previous test.
 
13971
    obj2->SetIndexedPropertiesToExternalArrayData(array_data,
 
13972
                                                  array_type,
 
13973
                                                  kElementCount);
 
13974
    context->Global()->Set(v8_str("ext_array"), obj2);
 
13975
    result = CompileRun("ext_array['']");
 
13976
  }
 
13977
 
 
13978
  // Property "" is a constant function that shouldn't not be interfered with
 
13979
  // when an external array is set.
 
13980
  {
 
13981
    v8::Handle<v8::Object> obj2 = v8::Object::New();
 
13982
    // Start
 
13983
    obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
 
13984
 
 
13985
    // Add a constant function to an object.
 
13986
    context->Global()->Set(v8_str("ext_array"), obj2);
 
13987
    result = CompileRun("ext_array[''] = function() {return 1503;};"
 
13988
                        "ext_array['']();");
 
13989
 
 
13990
    // Add an external array transition to the same map that
 
13991
    // has the constant transition.
 
13992
    v8::Handle<v8::Object> obj3 = v8::Object::New();
 
13993
    obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
 
13994
    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
 
13995
                                                  array_type,
 
13996
                                                  kElementCount);
 
13997
    context->Global()->Set(v8_str("ext_array"), obj3);
 
13998
  }
 
13999
 
 
14000
  // If a external array transition is in the map, it should get clobbered
 
14001
  // by a constant function.
 
14002
  {
 
14003
    // Add an external array transition.
 
14004
    v8::Handle<v8::Object> obj3 = v8::Object::New();
 
14005
    obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
 
14006
    obj3->SetIndexedPropertiesToExternalArrayData(array_data,
 
14007
                                                  array_type,
 
14008
                                                  kElementCount);
 
14009
 
 
14010
    // Add a constant function to the same map that just got an external array
 
14011
    // transition.
 
14012
    v8::Handle<v8::Object> obj2 = v8::Object::New();
 
14013
    obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
 
14014
    context->Global()->Set(v8_str("ext_array"), obj2);
 
14015
    result = CompileRun("ext_array[''] = function() {return 1503;};"
 
14016
                        "ext_array['']();");
 
14017
  }
 
14018
 
 
14019
  free(array_data);
 
14020
}
 
14021
 
 
14022
 
 
14023
THREADED_TEST(ExternalByteArray) {
 
14024
  ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
 
14025
      v8::kExternalByteArray,
 
14026
      -128,
 
14027
      127);
 
14028
}
 
14029
 
 
14030
 
 
14031
THREADED_TEST(ExternalUnsignedByteArray) {
 
14032
  ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
 
14033
      v8::kExternalUnsignedByteArray,
 
14034
      0,
 
14035
      255);
 
14036
}
 
14037
 
 
14038
 
 
14039
THREADED_TEST(ExternalPixelArray) {
 
14040
  ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
 
14041
      v8::kExternalPixelArray,
 
14042
      0,
 
14043
      255);
 
14044
}
 
14045
 
 
14046
 
 
14047
THREADED_TEST(ExternalShortArray) {
 
14048
  ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
 
14049
      v8::kExternalShortArray,
 
14050
      -32768,
 
14051
      32767);
 
14052
}
 
14053
 
 
14054
 
 
14055
THREADED_TEST(ExternalUnsignedShortArray) {
 
14056
  ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
 
14057
      v8::kExternalUnsignedShortArray,
 
14058
      0,
 
14059
      65535);
 
14060
}
 
14061
 
 
14062
 
 
14063
THREADED_TEST(ExternalIntArray) {
 
14064
  ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
 
14065
      v8::kExternalIntArray,
 
14066
      INT_MIN,   // -2147483648
 
14067
      INT_MAX);  //  2147483647
 
14068
}
 
14069
 
 
14070
 
 
14071
THREADED_TEST(ExternalUnsignedIntArray) {
 
14072
  ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
 
14073
      v8::kExternalUnsignedIntArray,
 
14074
      0,
 
14075
      UINT_MAX);  // 4294967295
 
14076
}
 
14077
 
 
14078
 
 
14079
THREADED_TEST(ExternalFloatArray) {
 
14080
  ExternalArrayTestHelper<i::ExternalFloatArray, float>(
 
14081
      v8::kExternalFloatArray,
 
14082
      -500,
 
14083
      500);
 
14084
}
 
14085
 
 
14086
 
 
14087
THREADED_TEST(ExternalDoubleArray) {
 
14088
  ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
 
14089
      v8::kExternalDoubleArray,
 
14090
      -500,
 
14091
      500);
 
14092
}
 
14093
 
 
14094
 
 
14095
THREADED_TEST(ExternalArrays) {
 
14096
  TestExternalByteArray();
 
14097
  TestExternalUnsignedByteArray();
 
14098
  TestExternalShortArray();
 
14099
  TestExternalUnsignedShortArray();
 
14100
  TestExternalIntArray();
 
14101
  TestExternalUnsignedIntArray();
 
14102
  TestExternalFloatArray();
 
14103
}
 
14104
 
 
14105
 
 
14106
void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
 
14107
  v8::HandleScope scope;
 
14108
  LocalContext context;
 
14109
  for (int size = 0; size < 100; size += 10) {
 
14110
    int element_size = ExternalArrayElementSize(array_type);
 
14111
    void* external_data = malloc(size * element_size);
 
14112
    v8::Handle<v8::Object> obj = v8::Object::New();
 
14113
    obj->SetIndexedPropertiesToExternalArrayData(
 
14114
        external_data, array_type, size);
 
14115
    CHECK(obj->HasIndexedPropertiesInExternalArrayData());
 
14116
    CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
 
14117
    CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
 
14118
    CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
 
14119
    free(external_data);
 
14120
  }
 
14121
}
 
14122
 
 
14123
 
 
14124
THREADED_TEST(ExternalArrayInfo) {
 
14125
  ExternalArrayInfoTestHelper(v8::kExternalByteArray);
 
14126
  ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
 
14127
  ExternalArrayInfoTestHelper(v8::kExternalShortArray);
 
14128
  ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
 
14129
  ExternalArrayInfoTestHelper(v8::kExternalIntArray);
 
14130
  ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
 
14131
  ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
 
14132
  ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
 
14133
  ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
 
14134
}
 
14135
 
 
14136
 
 
14137
void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
 
14138
  v8::Handle<v8::Object> obj = v8::Object::New();
 
14139
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
14140
  last_location = last_message = NULL;
 
14141
  obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
 
14142
  CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
 
14143
  CHECK_NE(NULL, last_location);
 
14144
  CHECK_NE(NULL, last_message);
 
14145
}
 
14146
 
 
14147
 
 
14148
TEST(ExternalArrayLimits) {
 
14149
  v8::HandleScope scope;
 
14150
  LocalContext context;
 
14151
  ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
 
14152
  ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
 
14153
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
 
14154
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
 
14155
  ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
 
14156
  ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
 
14157
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
 
14158
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
 
14159
  ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
 
14160
  ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
 
14161
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
 
14162
  ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
 
14163
  ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
 
14164
  ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
 
14165
  ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
 
14166
  ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
 
14167
  ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
 
14168
  ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
 
14169
}
 
14170
 
 
14171
 
 
14172
THREADED_TEST(ScriptContextDependence) {
 
14173
  v8::HandleScope scope;
 
14174
  LocalContext c1;
 
14175
  const char *source = "foo";
 
14176
  v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
 
14177
  v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
 
14178
  c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
 
14179
  CHECK_EQ(dep->Run()->Int32Value(), 100);
 
14180
  CHECK_EQ(indep->Run()->Int32Value(), 100);
 
14181
  LocalContext c2;
 
14182
  c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
 
14183
  CHECK_EQ(dep->Run()->Int32Value(), 100);
 
14184
  CHECK_EQ(indep->Run()->Int32Value(), 101);
 
14185
}
 
14186
 
 
14187
 
 
14188
THREADED_TEST(StackTrace) {
 
14189
  v8::HandleScope scope;
 
14190
  LocalContext context;
 
14191
  v8::TryCatch try_catch;
 
14192
  const char *source = "function foo() { FAIL.FAIL; }; foo();";
 
14193
  v8::Handle<v8::String> src = v8::String::New(source);
 
14194
  v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
 
14195
  v8::Script::New(src, origin)->Run();
 
14196
  CHECK(try_catch.HasCaught());
 
14197
  v8::String::Utf8Value stack(try_catch.StackTrace());
 
14198
  CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
 
14199
}
 
14200
 
 
14201
 
 
14202
// Checks that a StackFrame has certain expected values.
 
14203
void checkStackFrame(const char* expected_script_name,
 
14204
    const char* expected_func_name, int expected_line_number,
 
14205
    int expected_column, bool is_eval, bool is_constructor,
 
14206
    v8::Handle<v8::StackFrame> frame) {
 
14207
  v8::HandleScope scope;
 
14208
  v8::String::Utf8Value func_name(frame->GetFunctionName());
 
14209
  v8::String::Utf8Value script_name(frame->GetScriptName());
 
14210
  if (*script_name == NULL) {
 
14211
    // The situation where there is no associated script, like for evals.
 
14212
    CHECK(expected_script_name == NULL);
 
14213
  } else {
 
14214
    CHECK(strstr(*script_name, expected_script_name) != NULL);
 
14215
  }
 
14216
  CHECK(strstr(*func_name, expected_func_name) != NULL);
 
14217
  CHECK_EQ(expected_line_number, frame->GetLineNumber());
 
14218
  CHECK_EQ(expected_column, frame->GetColumn());
 
14219
  CHECK_EQ(is_eval, frame->IsEval());
 
14220
  CHECK_EQ(is_constructor, frame->IsConstructor());
 
14221
}
 
14222
 
 
14223
 
 
14224
v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
 
14225
  v8::HandleScope scope;
 
14226
  const char* origin = "capture-stack-trace-test";
 
14227
  const int kOverviewTest = 1;
 
14228
  const int kDetailedTest = 2;
 
14229
 
 
14230
  ASSERT(args.Length() == 1);
 
14231
 
 
14232
  int testGroup = args[0]->Int32Value();
 
14233
  if (testGroup == kOverviewTest) {
 
14234
    v8::Handle<v8::StackTrace> stackTrace =
 
14235
        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
 
14236
    CHECK_EQ(4, stackTrace->GetFrameCount());
 
14237
    checkStackFrame(origin, "bar", 2, 10, false, false,
 
14238
                    stackTrace->GetFrame(0));
 
14239
    checkStackFrame(origin, "foo", 6, 3, false, false,
 
14240
                    stackTrace->GetFrame(1));
 
14241
    // This is the source string inside the eval which has the call to foo.
 
14242
    checkStackFrame(NULL, "", 1, 5, false, false,
 
14243
                    stackTrace->GetFrame(2));
 
14244
    // The last frame is an anonymous function which has the initial eval call.
 
14245
    checkStackFrame(origin, "", 8, 7, false, false,
 
14246
                    stackTrace->GetFrame(3));
 
14247
 
 
14248
    CHECK(stackTrace->AsArray()->IsArray());
 
14249
  } else if (testGroup == kDetailedTest) {
 
14250
    v8::Handle<v8::StackTrace> stackTrace =
 
14251
        v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
 
14252
    CHECK_EQ(4, stackTrace->GetFrameCount());
 
14253
    checkStackFrame(origin, "bat", 4, 22, false, false,
 
14254
                    stackTrace->GetFrame(0));
 
14255
    checkStackFrame(origin, "baz", 8, 3, false, true,
 
14256
                    stackTrace->GetFrame(1));
 
14257
#ifdef ENABLE_DEBUGGER_SUPPORT
 
14258
    bool is_eval = true;
 
14259
#else  // ENABLE_DEBUGGER_SUPPORT
 
14260
    bool is_eval = false;
 
14261
#endif  // ENABLE_DEBUGGER_SUPPORT
 
14262
 
 
14263
    // This is the source string inside the eval which has the call to baz.
 
14264
    checkStackFrame(NULL, "", 1, 5, is_eval, false,
 
14265
                    stackTrace->GetFrame(2));
 
14266
    // The last frame is an anonymous function which has the initial eval call.
 
14267
    checkStackFrame(origin, "", 10, 1, false, false,
 
14268
                    stackTrace->GetFrame(3));
 
14269
 
 
14270
    CHECK(stackTrace->AsArray()->IsArray());
 
14271
  }
 
14272
  return v8::Undefined();
 
14273
}
 
14274
 
 
14275
 
 
14276
// Tests the C++ StackTrace API.
 
14277
// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
 
14278
// THREADED_TEST(CaptureStackTrace) {
 
14279
TEST(CaptureStackTrace) {
 
14280
  v8::HandleScope scope;
 
14281
  v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
 
14282
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
14283
  templ->Set(v8_str("AnalyzeStackInNativeCode"),
 
14284
             v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
 
14285
  LocalContext context(0, templ);
 
14286
 
 
14287
  // Test getting OVERVIEW information. Should ignore information that is not
 
14288
  // script name, function name, line number, and column offset.
 
14289
  const char *overview_source =
 
14290
    "function bar() {\n"
 
14291
    "  var y; AnalyzeStackInNativeCode(1);\n"
 
14292
    "}\n"
 
14293
    "function foo() {\n"
 
14294
    "\n"
 
14295
    "  bar();\n"
 
14296
    "}\n"
 
14297
    "var x;eval('new foo();');";
 
14298
  v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
 
14299
  v8::Handle<Value> overview_result(
 
14300
      v8::Script::New(overview_src, origin)->Run());
 
14301
  CHECK(!overview_result.IsEmpty());
 
14302
  CHECK(overview_result->IsObject());
 
14303
 
 
14304
  // Test getting DETAILED information.
 
14305
  const char *detailed_source =
 
14306
    "function bat() {AnalyzeStackInNativeCode(2);\n"
 
14307
    "}\n"
 
14308
    "\n"
 
14309
    "function baz() {\n"
 
14310
    "  bat();\n"
 
14311
    "}\n"
 
14312
    "eval('new baz();');";
 
14313
  v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
 
14314
  // Make the script using a non-zero line and column offset.
 
14315
  v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
 
14316
  v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
 
14317
  v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
 
14318
  v8::Handle<v8::Script> detailed_script(
 
14319
      v8::Script::New(detailed_src, &detailed_origin));
 
14320
  v8::Handle<Value> detailed_result(detailed_script->Run());
 
14321
  CHECK(!detailed_result.IsEmpty());
 
14322
  CHECK(detailed_result->IsObject());
 
14323
}
 
14324
 
 
14325
 
 
14326
static void StackTraceForUncaughtExceptionListener(
 
14327
    v8::Handle<v8::Message> message,
 
14328
    v8::Handle<Value>) {
 
14329
  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
 
14330
  CHECK_EQ(2, stack_trace->GetFrameCount());
 
14331
  checkStackFrame("origin", "foo", 2, 3, false, false,
 
14332
                  stack_trace->GetFrame(0));
 
14333
  checkStackFrame("origin", "bar", 5, 3, false, false,
 
14334
                  stack_trace->GetFrame(1));
 
14335
}
 
14336
 
 
14337
TEST(CaptureStackTraceForUncaughtException) {
 
14338
  report_count = 0;
 
14339
  v8::HandleScope scope;
 
14340
  LocalContext env;
 
14341
  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
 
14342
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
 
14343
 
 
14344
  Script::Compile(v8_str("function foo() {\n"
 
14345
                         "  throw 1;\n"
 
14346
                         "};\n"
 
14347
                         "function bar() {\n"
 
14348
                         "  foo();\n"
 
14349
                         "};"),
 
14350
                  v8_str("origin"))->Run();
 
14351
  v8::Local<v8::Object> global = env->Global();
 
14352
  Local<Value> trouble = global->Get(v8_str("bar"));
 
14353
  CHECK(trouble->IsFunction());
 
14354
  Function::Cast(*trouble)->Call(global, 0, NULL);
 
14355
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14356
  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
 
14357
}
 
14358
 
 
14359
 
 
14360
TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
 
14361
  v8::HandleScope scope;
 
14362
  LocalContext env;
 
14363
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
 
14364
                                                    1024,
 
14365
                                                    v8::StackTrace::kDetailed);
 
14366
 
 
14367
  CompileRun(
 
14368
      "var setters = ['column', 'lineNumber', 'scriptName',\n"
 
14369
      "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
 
14370
      "    'isConstructor'];\n"
 
14371
      "for (var i = 0; i < setters.length; i++) {\n"
 
14372
      "  var prop = setters[i];\n"
 
14373
      "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
 
14374
      "}\n");
 
14375
  CompileRun("throw 'exception';");
 
14376
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14377
}
 
14378
 
 
14379
 
 
14380
static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
 
14381
                                     v8::Handle<v8::Value> data) {
 
14382
  // Use the frame where JavaScript is called from.
 
14383
  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
 
14384
  CHECK(!stack_trace.IsEmpty());
 
14385
  int frame_count = stack_trace->GetFrameCount();
 
14386
  CHECK_EQ(3, frame_count);
 
14387
  int line_number[] = {1, 2, 5};
 
14388
  for (int i = 0; i < frame_count; i++) {
 
14389
    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
 
14390
  }
 
14391
}
 
14392
 
 
14393
 
 
14394
// Test that we only return the stack trace at the site where the exception
 
14395
// is first thrown (not where it is rethrown).
 
14396
TEST(RethrowStackTrace) {
 
14397
  v8::HandleScope scope;
 
14398
  LocalContext env;
 
14399
  // We make sure that
 
14400
  // - the stack trace of the ReferenceError in g() is reported.
 
14401
  // - the stack trace is not overwritten when e1 is rethrown by t().
 
14402
  // - the stack trace of e2 does not overwrite that of e1.
 
14403
  const char* source =
 
14404
      "function g() { error; }          \n"
 
14405
      "function f() { g(); }            \n"
 
14406
      "function t(e) { throw e; }       \n"
 
14407
      "try {                            \n"
 
14408
      "  f();                           \n"
 
14409
      "} catch (e1) {                   \n"
 
14410
      "  try {                          \n"
 
14411
      "    error;                       \n"
 
14412
      "  } catch (e2) {                 \n"
 
14413
      "    t(e1);                       \n"
 
14414
      "  }                              \n"
 
14415
      "}                                \n";
 
14416
  v8::V8::AddMessageListener(RethrowStackTraceHandler);
 
14417
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
 
14418
  CompileRun(source);
 
14419
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14420
  v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
 
14421
}
 
14422
 
 
14423
 
 
14424
static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
 
14425
                                              v8::Handle<v8::Value> data) {
 
14426
  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
 
14427
  CHECK(!stack_trace.IsEmpty());
 
14428
  int frame_count = stack_trace->GetFrameCount();
 
14429
  CHECK_EQ(2, frame_count);
 
14430
  int line_number[] = {3, 7};
 
14431
  for (int i = 0; i < frame_count; i++) {
 
14432
    CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
 
14433
  }
 
14434
}
 
14435
 
 
14436
 
 
14437
// Test that we do not recognize identity for primitive exceptions.
 
14438
TEST(RethrowPrimitiveStackTrace) {
 
14439
  v8::HandleScope scope;
 
14440
  LocalContext env;
 
14441
  // We do not capture stack trace for non Error objects on creation time.
 
14442
  // Instead, we capture the stack trace on last throw.
 
14443
  const char* source =
 
14444
      "function g() { throw 404; }      \n"
 
14445
      "function f() { g(); }            \n"
 
14446
      "function t(e) { throw e; }       \n"
 
14447
      "try {                            \n"
 
14448
      "  f();                           \n"
 
14449
      "} catch (e1) {                   \n"
 
14450
      "  t(e1)                          \n"
 
14451
      "}                                \n";
 
14452
  v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
 
14453
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
 
14454
  CompileRun(source);
 
14455
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14456
  v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
 
14457
}
 
14458
 
 
14459
 
 
14460
static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
 
14461
                                              v8::Handle<v8::Value> data) {
 
14462
  // Use the frame where JavaScript is called from.
 
14463
  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
 
14464
  CHECK(!stack_trace.IsEmpty());
 
14465
  CHECK_EQ(1, stack_trace->GetFrameCount());
 
14466
  CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
 
14467
}
 
14468
 
 
14469
 
 
14470
// Test that the stack trace is captured when the error object is created and
 
14471
// not where it is thrown.
 
14472
TEST(RethrowExistingStackTrace) {
 
14473
  v8::HandleScope scope;
 
14474
  LocalContext env;
 
14475
  const char* source =
 
14476
      "var e = new Error();           \n"
 
14477
      "throw e;                       \n";
 
14478
  v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
 
14479
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
 
14480
  CompileRun(source);
 
14481
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14482
  v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
 
14483
}
 
14484
 
 
14485
 
 
14486
static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
 
14487
                                               v8::Handle<v8::Value> data) {
 
14488
  // Use the frame where JavaScript is called from.
 
14489
  v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
 
14490
  CHECK(!stack_trace.IsEmpty());
 
14491
  CHECK_EQ(1, stack_trace->GetFrameCount());
 
14492
  CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
 
14493
}
 
14494
 
 
14495
 
 
14496
// Test that the stack trace is captured where the bogus Error object is thrown.
 
14497
TEST(RethrowBogusErrorStackTrace) {
 
14498
  v8::HandleScope scope;
 
14499
  LocalContext env;
 
14500
  const char* source =
 
14501
      "var e = {__proto__: new Error()} \n"
 
14502
      "throw e;                         \n";
 
14503
  v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
 
14504
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
 
14505
  CompileRun(source);
 
14506
  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
 
14507
  v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
 
14508
}
 
14509
 
 
14510
 
 
14511
v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
 
14512
  v8::HandleScope scope;
 
14513
  v8::Handle<v8::StackTrace> stackTrace =
 
14514
      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
 
14515
  CHECK_EQ(5, stackTrace->GetFrameCount());
 
14516
  v8::Handle<v8::String> url = v8_str("eval_url");
 
14517
  for (int i = 0; i < 3; i++) {
 
14518
    v8::Handle<v8::String> name =
 
14519
        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
 
14520
    CHECK(!name.IsEmpty());
 
14521
    CHECK_EQ(url, name);
 
14522
  }
 
14523
  return v8::Undefined();
 
14524
}
 
14525
 
 
14526
 
 
14527
TEST(SourceURLInStackTrace) {
 
14528
  v8::HandleScope scope;
 
14529
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
14530
  templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
 
14531
             v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
 
14532
  LocalContext context(0, templ);
 
14533
 
 
14534
  const char *source =
 
14535
    "function outer() {\n"
 
14536
    "function bar() {\n"
 
14537
    "  AnalyzeStackOfEvalWithSourceURL();\n"
 
14538
    "}\n"
 
14539
    "function foo() {\n"
 
14540
    "\n"
 
14541
    "  bar();\n"
 
14542
    "}\n"
 
14543
    "foo();\n"
 
14544
    "}\n"
 
14545
    "eval('(' + outer +')()//@ sourceURL=eval_url');";
 
14546
  CHECK(CompileRun(source)->IsUndefined());
 
14547
}
 
14548
 
 
14549
 
 
14550
v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
 
14551
    const v8::Arguments& args) {
 
14552
  v8::HandleScope scope;
 
14553
  v8::Handle<v8::StackTrace> stackTrace =
 
14554
      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
 
14555
  CHECK_EQ(4, stackTrace->GetFrameCount());
 
14556
  v8::Handle<v8::String> url = v8_str("url");
 
14557
  for (int i = 0; i < 3; i++) {
 
14558
    v8::Handle<v8::String> name =
 
14559
        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
 
14560
    CHECK(!name.IsEmpty());
 
14561
    CHECK_EQ(url, name);
 
14562
  }
 
14563
  return v8::Undefined();
 
14564
}
 
14565
 
 
14566
 
 
14567
TEST(InlineScriptWithSourceURLInStackTrace) {
 
14568
  v8::HandleScope scope;
 
14569
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
14570
  templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
 
14571
             v8::FunctionTemplate::New(
 
14572
                 AnalyzeStackOfInlineScriptWithSourceURL));
 
14573
  LocalContext context(0, templ);
 
14574
 
 
14575
  const char *source =
 
14576
    "function outer() {\n"
 
14577
    "function bar() {\n"
 
14578
    "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
 
14579
    "}\n"
 
14580
    "function foo() {\n"
 
14581
    "\n"
 
14582
    "  bar();\n"
 
14583
    "}\n"
 
14584
    "foo();\n"
 
14585
    "}\n"
 
14586
    "outer()\n"
 
14587
    "//@ sourceURL=source_url";
 
14588
  CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
 
14589
}
 
14590
 
 
14591
 
 
14592
v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
 
14593
    const v8::Arguments& args) {
 
14594
  v8::HandleScope scope;
 
14595
  v8::Handle<v8::StackTrace> stackTrace =
 
14596
      v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
 
14597
  CHECK_EQ(4, stackTrace->GetFrameCount());
 
14598
  v8::Handle<v8::String> url = v8_str("source_url");
 
14599
  for (int i = 0; i < 3; i++) {
 
14600
    v8::Handle<v8::String> name =
 
14601
        stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
 
14602
    CHECK(!name.IsEmpty());
 
14603
    CHECK_EQ(url, name);
 
14604
  }
 
14605
  return v8::Undefined();
 
14606
}
 
14607
 
 
14608
 
 
14609
TEST(DynamicWithSourceURLInStackTrace) {
 
14610
  v8::HandleScope scope;
 
14611
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
14612
  templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
 
14613
             v8::FunctionTemplate::New(
 
14614
                 AnalyzeStackOfDynamicScriptWithSourceURL));
 
14615
  LocalContext context(0, templ);
 
14616
 
 
14617
  const char *source =
 
14618
    "function outer() {\n"
 
14619
    "function bar() {\n"
 
14620
    "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
 
14621
    "}\n"
 
14622
    "function foo() {\n"
 
14623
    "\n"
 
14624
    "  bar();\n"
 
14625
    "}\n"
 
14626
    "foo();\n"
 
14627
    "}\n"
 
14628
    "outer()\n"
 
14629
    "//@ sourceURL=source_url";
 
14630
  CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
 
14631
}
 
14632
 
 
14633
static void CreateGarbageInOldSpace() {
 
14634
  v8::HandleScope scope;
 
14635
  i::AlwaysAllocateScope always_allocate;
 
14636
  for (int i = 0; i < 1000; i++) {
 
14637
    FACTORY->NewFixedArray(1000, i::TENURED);
 
14638
  }
 
14639
}
 
14640
 
 
14641
// Test that idle notification can be handled and eventually returns true.
 
14642
TEST(IdleNotification) {
 
14643
  const intptr_t MB = 1024 * 1024;
 
14644
  v8::HandleScope scope;
 
14645
  LocalContext env;
 
14646
  intptr_t initial_size = HEAP->SizeOfObjects();
 
14647
  CreateGarbageInOldSpace();
 
14648
  intptr_t size_with_garbage = HEAP->SizeOfObjects();
 
14649
  CHECK_GT(size_with_garbage, initial_size + MB);
 
14650
  bool finished = false;
 
14651
  for (int i = 0; i < 200 && !finished; i++) {
 
14652
    finished = v8::V8::IdleNotification();
 
14653
  }
 
14654
  intptr_t final_size = HEAP->SizeOfObjects();
 
14655
  CHECK(finished);
 
14656
  CHECK_LT(final_size, initial_size + 1);
 
14657
}
 
14658
 
 
14659
 
 
14660
// Test that idle notification can be handled and eventually collects garbage.
 
14661
TEST(IdleNotificationWithSmallHint) {
 
14662
  const intptr_t MB = 1024 * 1024;
 
14663
  const int IdlePauseInMs = 900;
 
14664
  v8::HandleScope scope;
 
14665
  LocalContext env;
 
14666
  intptr_t initial_size = HEAP->SizeOfObjects();
 
14667
  CreateGarbageInOldSpace();
 
14668
  intptr_t size_with_garbage = HEAP->SizeOfObjects();
 
14669
  CHECK_GT(size_with_garbage, initial_size + MB);
 
14670
  bool finished = false;
 
14671
  for (int i = 0; i < 200 && !finished; i++) {
 
14672
    finished = v8::V8::IdleNotification(IdlePauseInMs);
 
14673
  }
 
14674
  intptr_t final_size = HEAP->SizeOfObjects();
 
14675
  CHECK(finished);
 
14676
  CHECK_LT(final_size, initial_size + 1);
 
14677
}
 
14678
 
 
14679
 
 
14680
// Test that idle notification can be handled and eventually collects garbage.
 
14681
TEST(IdleNotificationWithLargeHint) {
 
14682
  const intptr_t MB = 1024 * 1024;
 
14683
  const int IdlePauseInMs = 900;
 
14684
  v8::HandleScope scope;
 
14685
  LocalContext env;
 
14686
  intptr_t initial_size = HEAP->SizeOfObjects();
 
14687
  CreateGarbageInOldSpace();
 
14688
  intptr_t size_with_garbage = HEAP->SizeOfObjects();
 
14689
  CHECK_GT(size_with_garbage, initial_size + MB);
 
14690
  bool finished = false;
 
14691
  for (int i = 0; i < 200 && !finished; i++) {
 
14692
    finished = v8::V8::IdleNotification(IdlePauseInMs);
 
14693
  }
 
14694
  intptr_t final_size = HEAP->SizeOfObjects();
 
14695
  CHECK(finished);
 
14696
  CHECK_LT(final_size, initial_size + 1);
 
14697
}
 
14698
 
 
14699
 
 
14700
TEST(Regress2107) {
 
14701
  const intptr_t MB = 1024 * 1024;
 
14702
  const int kShortIdlePauseInMs = 100;
 
14703
  const int kLongIdlePauseInMs = 1000;
 
14704
  v8::HandleScope scope;
 
14705
  LocalContext env;
 
14706
  intptr_t initial_size = HEAP->SizeOfObjects();
 
14707
  // Send idle notification to start a round of incremental GCs.
 
14708
  v8::V8::IdleNotification(kShortIdlePauseInMs);
 
14709
  // Emulate 7 page reloads.
 
14710
  for (int i = 0; i < 7; i++) {
 
14711
    v8::Persistent<v8::Context> ctx = v8::Context::New();
 
14712
    ctx->Enter();
 
14713
    CreateGarbageInOldSpace();
 
14714
    ctx->Exit();
 
14715
    ctx.Dispose();
 
14716
    v8::V8::ContextDisposedNotification();
 
14717
    v8::V8::IdleNotification(kLongIdlePauseInMs);
 
14718
  }
 
14719
  // Create garbage and check that idle notification still collects it.
 
14720
  CreateGarbageInOldSpace();
 
14721
  intptr_t size_with_garbage = HEAP->SizeOfObjects();
 
14722
  CHECK_GT(size_with_garbage, initial_size + MB);
 
14723
  bool finished = false;
 
14724
  for (int i = 0; i < 200 && !finished; i++) {
 
14725
    finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
 
14726
  }
 
14727
  intptr_t final_size = HEAP->SizeOfObjects();
 
14728
  CHECK_LT(final_size, initial_size + 1);
 
14729
}
 
14730
 
 
14731
static uint32_t* stack_limit;
 
14732
 
 
14733
static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
 
14734
  stack_limit = reinterpret_cast<uint32_t*>(
 
14735
      i::Isolate::Current()->stack_guard()->real_climit());
 
14736
  return v8::Undefined();
 
14737
}
 
14738
 
 
14739
 
 
14740
// Uses the address of a local variable to determine the stack top now.
 
14741
// Given a size, returns an address that is that far from the current
 
14742
// top of stack.
 
14743
static uint32_t* ComputeStackLimit(uint32_t size) {
 
14744
  uint32_t* answer = &size - (size / sizeof(size));
 
14745
  // If the size is very large and the stack is very near the bottom of
 
14746
  // memory then the calculation above may wrap around and give an address
 
14747
  // that is above the (downwards-growing) stack.  In that case we return
 
14748
  // a very low address.
 
14749
  if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
 
14750
  return answer;
 
14751
}
 
14752
 
 
14753
 
 
14754
TEST(SetResourceConstraints) {
 
14755
  static const int K = 1024;
 
14756
  uint32_t* set_limit = ComputeStackLimit(128 * K);
 
14757
 
 
14758
  // Set stack limit.
 
14759
  v8::ResourceConstraints constraints;
 
14760
  constraints.set_stack_limit(set_limit);
 
14761
  CHECK(v8::SetResourceConstraints(&constraints));
 
14762
 
 
14763
  // Execute a script.
 
14764
  v8::HandleScope scope;
 
14765
  LocalContext env;
 
14766
  Local<v8::FunctionTemplate> fun_templ =
 
14767
      v8::FunctionTemplate::New(GetStackLimitCallback);
 
14768
  Local<Function> fun = fun_templ->GetFunction();
 
14769
  env->Global()->Set(v8_str("get_stack_limit"), fun);
 
14770
  CompileRun("get_stack_limit();");
 
14771
 
 
14772
  CHECK(stack_limit == set_limit);
 
14773
}
 
14774
 
 
14775
 
 
14776
TEST(SetResourceConstraintsInThread) {
 
14777
  uint32_t* set_limit;
 
14778
  {
 
14779
    v8::Locker locker;
 
14780
    static const int K = 1024;
 
14781
    set_limit = ComputeStackLimit(128 * K);
 
14782
 
 
14783
    // Set stack limit.
 
14784
    v8::ResourceConstraints constraints;
 
14785
    constraints.set_stack_limit(set_limit);
 
14786
    CHECK(v8::SetResourceConstraints(&constraints));
 
14787
 
 
14788
    // Execute a script.
 
14789
    v8::HandleScope scope;
 
14790
    LocalContext env;
 
14791
    Local<v8::FunctionTemplate> fun_templ =
 
14792
        v8::FunctionTemplate::New(GetStackLimitCallback);
 
14793
    Local<Function> fun = fun_templ->GetFunction();
 
14794
    env->Global()->Set(v8_str("get_stack_limit"), fun);
 
14795
    CompileRun("get_stack_limit();");
 
14796
 
 
14797
    CHECK(stack_limit == set_limit);
 
14798
  }
 
14799
  {
 
14800
    v8::Locker locker;
 
14801
    CHECK(stack_limit == set_limit);
 
14802
  }
 
14803
}
 
14804
 
 
14805
 
 
14806
THREADED_TEST(GetHeapStatistics) {
 
14807
  v8::HandleScope scope;
 
14808
  LocalContext c1;
 
14809
  v8::HeapStatistics heap_statistics;
 
14810
  CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
 
14811
  CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
 
14812
  v8::V8::GetHeapStatistics(&heap_statistics);
 
14813
  CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
 
14814
  CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
 
14815
}
 
14816
 
 
14817
 
 
14818
class VisitorImpl : public v8::ExternalResourceVisitor {
 
14819
 public:
 
14820
  VisitorImpl(TestResource* r1, TestResource* r2)
 
14821
      : resource1_(r1),
 
14822
        resource2_(r2),
 
14823
        found_resource1_(false),
 
14824
        found_resource2_(false) {}
 
14825
  virtual ~VisitorImpl() {}
 
14826
  virtual void VisitExternalString(v8::Handle<v8::String> string) {
 
14827
    if (!string->IsExternal()) {
 
14828
      CHECK(string->IsExternalAscii());
 
14829
      return;
 
14830
    }
 
14831
    v8::String::ExternalStringResource* resource =
 
14832
        string->GetExternalStringResource();
 
14833
    CHECK(resource);
 
14834
    if (resource1_ == resource) {
 
14835
      CHECK(!found_resource1_);
 
14836
      found_resource1_ = true;
 
14837
    }
 
14838
    if (resource2_ == resource) {
 
14839
      CHECK(!found_resource2_);
 
14840
      found_resource2_ = true;
 
14841
    }
 
14842
  }
 
14843
  void CheckVisitedResources() {
 
14844
    CHECK(found_resource1_);
 
14845
    CHECK(found_resource2_);
 
14846
  }
 
14847
 
 
14848
 private:
 
14849
  v8::String::ExternalStringResource* resource1_;
 
14850
  v8::String::ExternalStringResource* resource2_;
 
14851
  bool found_resource1_;
 
14852
  bool found_resource2_;
 
14853
};
 
14854
 
 
14855
TEST(VisitExternalStrings) {
 
14856
  v8::HandleScope scope;
 
14857
  LocalContext env;
 
14858
  const char* string = "Some string";
 
14859
  uint16_t* two_byte_string = AsciiToTwoByteString(string);
 
14860
  TestResource* resource1 = new TestResource(two_byte_string);
 
14861
  v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
 
14862
  TestResource* resource2 = new TestResource(two_byte_string);
 
14863
  v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
 
14864
 
 
14865
  // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
 
14866
  CHECK(string1->IsExternal());
 
14867
  CHECK(string2->IsExternal());
 
14868
 
 
14869
  VisitorImpl visitor(resource1, resource2);
 
14870
  v8::V8::VisitExternalResources(&visitor);
 
14871
  visitor.CheckVisitedResources();
 
14872
}
 
14873
 
 
14874
 
 
14875
static double DoubleFromBits(uint64_t value) {
 
14876
  double target;
 
14877
  memcpy(&target, &value, sizeof(target));
 
14878
  return target;
 
14879
}
 
14880
 
 
14881
 
 
14882
static uint64_t DoubleToBits(double value) {
 
14883
  uint64_t target;
 
14884
  memcpy(&target, &value, sizeof(target));
 
14885
  return target;
 
14886
}
 
14887
 
 
14888
 
 
14889
static double DoubleToDateTime(double input) {
 
14890
  double date_limit = 864e13;
 
14891
  if (IsNaN(input) || input < -date_limit || input > date_limit) {
 
14892
    return i::OS::nan_value();
 
14893
  }
 
14894
  return (input < 0) ? -(floor(-input)) : floor(input);
 
14895
}
 
14896
 
 
14897
// We don't have a consistent way to write 64-bit constants syntactically, so we
 
14898
// split them into two 32-bit constants and combine them programmatically.
 
14899
static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
 
14900
  return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
 
14901
}
 
14902
 
 
14903
 
 
14904
THREADED_TEST(QuietSignalingNaNs) {
 
14905
  v8::HandleScope scope;
 
14906
  LocalContext context;
 
14907
  v8::TryCatch try_catch;
 
14908
 
 
14909
  // Special double values.
 
14910
  double snan = DoubleFromBits(0x7ff00000, 0x00000001);
 
14911
  double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
 
14912
  double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
 
14913
  double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
 
14914
  double min_normal = DoubleFromBits(0x00100000, 0x00000000);
 
14915
  double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
 
14916
  double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
 
14917
 
 
14918
  // Date values are capped at +/-100000000 days (times 864e5 ms per day)
 
14919
  // on either side of the epoch.
 
14920
  double date_limit = 864e13;
 
14921
 
 
14922
  double test_values[] = {
 
14923
      snan,
 
14924
      qnan,
 
14925
      infinity,
 
14926
      max_normal,
 
14927
      date_limit + 1,
 
14928
      date_limit,
 
14929
      min_normal,
 
14930
      max_denormal,
 
14931
      min_denormal,
 
14932
      0,
 
14933
      -0,
 
14934
      -min_denormal,
 
14935
      -max_denormal,
 
14936
      -min_normal,
 
14937
      -date_limit,
 
14938
      -date_limit - 1,
 
14939
      -max_normal,
 
14940
      -infinity,
 
14941
      -qnan,
 
14942
      -snan
 
14943
  };
 
14944
  int num_test_values = 20;
 
14945
 
 
14946
  for (int i = 0; i < num_test_values; i++) {
 
14947
    double test_value = test_values[i];
 
14948
 
 
14949
    // Check that Number::New preserves non-NaNs and quiets SNaNs.
 
14950
    v8::Handle<v8::Value> number = v8::Number::New(test_value);
 
14951
    double stored_number = number->NumberValue();
 
14952
    if (!IsNaN(test_value)) {
 
14953
      CHECK_EQ(test_value, stored_number);
 
14954
    } else {
 
14955
      uint64_t stored_bits = DoubleToBits(stored_number);
 
14956
      // Check if quiet nan (bits 51..62 all set).
 
14957
#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
 
14958
      // Most significant fraction bit for quiet nan is set to 0
 
14959
      // on MIPS architecture. Allowed by IEEE-754.
 
14960
      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
 
14961
#else
 
14962
      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
 
14963
#endif
 
14964
    }
 
14965
 
 
14966
    // Check that Date::New preserves non-NaNs in the date range and
 
14967
    // quiets SNaNs.
 
14968
    v8::Handle<v8::Value> date = v8::Date::New(test_value);
 
14969
    double expected_stored_date = DoubleToDateTime(test_value);
 
14970
    double stored_date = date->NumberValue();
 
14971
    if (!IsNaN(expected_stored_date)) {
 
14972
      CHECK_EQ(expected_stored_date, stored_date);
 
14973
    } else {
 
14974
      uint64_t stored_bits = DoubleToBits(stored_date);
 
14975
      // Check if quiet nan (bits 51..62 all set).
 
14976
#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
 
14977
      // Most significant fraction bit for quiet nan is set to 0
 
14978
      // on MIPS architecture. Allowed by IEEE-754.
 
14979
      CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
 
14980
#else
 
14981
      CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
 
14982
#endif
 
14983
    }
 
14984
  }
 
14985
}
 
14986
 
 
14987
 
 
14988
static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
 
14989
  v8::HandleScope scope;
 
14990
  v8::TryCatch tc;
 
14991
  v8::Handle<v8::String> str(args[0]->ToString());
 
14992
  USE(str);
 
14993
  if (tc.HasCaught())
 
14994
    return tc.ReThrow();
 
14995
  return v8::Undefined();
 
14996
}
 
14997
 
 
14998
 
 
14999
// Test that an exception can be propagated down through a spaghetti
 
15000
// stack using ReThrow.
 
15001
THREADED_TEST(SpaghettiStackReThrow) {
 
15002
  v8::HandleScope scope;
 
15003
  LocalContext context;
 
15004
  context->Global()->Set(
 
15005
      v8::String::New("s"),
 
15006
      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
 
15007
  v8::TryCatch try_catch;
 
15008
  CompileRun(
 
15009
      "var i = 0;"
 
15010
      "var o = {"
 
15011
      "  toString: function () {"
 
15012
      "    if (i == 10) {"
 
15013
      "      throw 'Hey!';"
 
15014
      "    } else {"
 
15015
      "      i++;"
 
15016
      "      return s(o);"
 
15017
      "    }"
 
15018
      "  }"
 
15019
      "};"
 
15020
      "s(o);");
 
15021
  CHECK(try_catch.HasCaught());
 
15022
  v8::String::Utf8Value value(try_catch.Exception());
 
15023
  CHECK_EQ(0, strcmp(*value, "Hey!"));
 
15024
}
 
15025
 
 
15026
 
 
15027
TEST(Regress528) {
 
15028
  v8::V8::Initialize();
 
15029
 
 
15030
  v8::HandleScope scope;
 
15031
  v8::Persistent<Context> context;
 
15032
  v8::Persistent<Context> other_context;
 
15033
  int gc_count;
 
15034
 
 
15035
  // Create a context used to keep the code from aging in the compilation
 
15036
  // cache.
 
15037
  other_context = Context::New();
 
15038
 
 
15039
  // Context-dependent context data creates reference from the compilation
 
15040
  // cache to the global object.
 
15041
  const char* source_simple = "1";
 
15042
  context = Context::New();
 
15043
  {
 
15044
    v8::HandleScope scope;
 
15045
 
 
15046
    context->Enter();
 
15047
    Local<v8::String> obj = v8::String::New("");
 
15048
    context->SetData(obj);
 
15049
    CompileRun(source_simple);
 
15050
    context->Exit();
 
15051
  }
 
15052
  context.Dispose();
 
15053
  v8::V8::ContextDisposedNotification();
 
15054
  for (gc_count = 1; gc_count < 10; gc_count++) {
 
15055
    other_context->Enter();
 
15056
    CompileRun(source_simple);
 
15057
    other_context->Exit();
 
15058
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15059
    if (GetGlobalObjectsCount() == 1) break;
 
15060
  }
 
15061
  CHECK_GE(2, gc_count);
 
15062
  CHECK_EQ(1, GetGlobalObjectsCount());
 
15063
 
 
15064
  // Eval in a function creates reference from the compilation cache to the
 
15065
  // global object.
 
15066
  const char* source_eval = "function f(){eval('1')}; f()";
 
15067
  context = Context::New();
 
15068
  {
 
15069
    v8::HandleScope scope;
 
15070
 
 
15071
    context->Enter();
 
15072
    CompileRun(source_eval);
 
15073
    context->Exit();
 
15074
  }
 
15075
  context.Dispose();
 
15076
  v8::V8::ContextDisposedNotification();
 
15077
  for (gc_count = 1; gc_count < 10; gc_count++) {
 
15078
    other_context->Enter();
 
15079
    CompileRun(source_eval);
 
15080
    other_context->Exit();
 
15081
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15082
    if (GetGlobalObjectsCount() == 1) break;
 
15083
  }
 
15084
  CHECK_GE(2, gc_count);
 
15085
  CHECK_EQ(1, GetGlobalObjectsCount());
 
15086
 
 
15087
  // Looking up the line number for an exception creates reference from the
 
15088
  // compilation cache to the global object.
 
15089
  const char* source_exception = "function f(){throw 1;} f()";
 
15090
  context = Context::New();
 
15091
  {
 
15092
    v8::HandleScope scope;
 
15093
 
 
15094
    context->Enter();
 
15095
    v8::TryCatch try_catch;
 
15096
    CompileRun(source_exception);
 
15097
    CHECK(try_catch.HasCaught());
 
15098
    v8::Handle<v8::Message> message = try_catch.Message();
 
15099
    CHECK(!message.IsEmpty());
 
15100
    CHECK_EQ(1, message->GetLineNumber());
 
15101
    context->Exit();
 
15102
  }
 
15103
  context.Dispose();
 
15104
  v8::V8::ContextDisposedNotification();
 
15105
  for (gc_count = 1; gc_count < 10; gc_count++) {
 
15106
    other_context->Enter();
 
15107
    CompileRun(source_exception);
 
15108
    other_context->Exit();
 
15109
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15110
    if (GetGlobalObjectsCount() == 1) break;
 
15111
  }
 
15112
  CHECK_GE(2, gc_count);
 
15113
  CHECK_EQ(1, GetGlobalObjectsCount());
 
15114
 
 
15115
  other_context.Dispose();
 
15116
  v8::V8::ContextDisposedNotification();
 
15117
}
 
15118
 
 
15119
 
 
15120
THREADED_TEST(ScriptOrigin) {
 
15121
  v8::HandleScope scope;
 
15122
  LocalContext env;
 
15123
  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
 
15124
  v8::Handle<v8::String> script = v8::String::New(
 
15125
      "function f() {}\n\nfunction g() {}");
 
15126
  v8::Script::Compile(script, &origin)->Run();
 
15127
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
 
15128
      env->Global()->Get(v8::String::New("f")));
 
15129
  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
 
15130
      env->Global()->Get(v8::String::New("g")));
 
15131
 
 
15132
  v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
 
15133
  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
 
15134
  CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
 
15135
 
 
15136
  v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
 
15137
  CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
 
15138
  CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
 
15139
}
 
15140
 
 
15141
THREADED_TEST(FunctionGetInferredName) {
 
15142
  v8::HandleScope scope;
 
15143
  LocalContext env;
 
15144
  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
 
15145
  v8::Handle<v8::String> script = v8::String::New(
 
15146
      "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
 
15147
  v8::Script::Compile(script, &origin)->Run();
 
15148
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
 
15149
      env->Global()->Get(v8::String::New("f")));
 
15150
  CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
 
15151
}
 
15152
 
 
15153
THREADED_TEST(ScriptLineNumber) {
 
15154
  v8::HandleScope scope;
 
15155
  LocalContext env;
 
15156
  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
 
15157
  v8::Handle<v8::String> script = v8::String::New(
 
15158
      "function f() {}\n\nfunction g() {}");
 
15159
  v8::Script::Compile(script, &origin)->Run();
 
15160
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
 
15161
      env->Global()->Get(v8::String::New("f")));
 
15162
  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
 
15163
      env->Global()->Get(v8::String::New("g")));
 
15164
  CHECK_EQ(0, f->GetScriptLineNumber());
 
15165
  CHECK_EQ(2, g->GetScriptLineNumber());
 
15166
}
 
15167
 
 
15168
 
 
15169
THREADED_TEST(ScriptColumnNumber) {
 
15170
  v8::HandleScope scope;
 
15171
  LocalContext env;
 
15172
  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
 
15173
      v8::Integer::New(3), v8::Integer::New(2));
 
15174
  v8::Handle<v8::String> script = v8::String::New(
 
15175
      "function foo() {}\n\n     function bar() {}");
 
15176
  v8::Script::Compile(script, &origin)->Run();
 
15177
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
 
15178
      env->Global()->Get(v8::String::New("foo")));
 
15179
  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
 
15180
      env->Global()->Get(v8::String::New("bar")));
 
15181
  CHECK_EQ(14, foo->GetScriptColumnNumber());
 
15182
  CHECK_EQ(17, bar->GetScriptColumnNumber());
 
15183
}
 
15184
 
 
15185
 
 
15186
THREADED_TEST(FunctionGetScriptId) {
 
15187
  v8::HandleScope scope;
 
15188
  LocalContext env;
 
15189
  v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
 
15190
      v8::Integer::New(3), v8::Integer::New(2));
 
15191
  v8::Handle<v8::String> scriptSource = v8::String::New(
 
15192
      "function foo() {}\n\n     function bar() {}");
 
15193
  v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
 
15194
  script->Run();
 
15195
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
 
15196
      env->Global()->Get(v8::String::New("foo")));
 
15197
  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
 
15198
      env->Global()->Get(v8::String::New("bar")));
 
15199
  CHECK_EQ(script->Id(), foo->GetScriptId());
 
15200
  CHECK_EQ(script->Id(), bar->GetScriptId());
 
15201
}
 
15202
 
 
15203
 
 
15204
static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
 
15205
                                              const AccessorInfo& info) {
 
15206
  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
 
15207
  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
 
15208
  return v8_num(42);
 
15209
}
 
15210
 
 
15211
 
 
15212
static void SetterWhichSetsYOnThisTo23(Local<String> name,
 
15213
                                       Local<Value> value,
 
15214
                                       const AccessorInfo& info) {
 
15215
  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
 
15216
  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
 
15217
  info.This()->Set(v8_str("y"), v8_num(23));
 
15218
}
 
15219
 
 
15220
 
 
15221
Handle<Value> FooGetInterceptor(Local<String> name,
 
15222
                                const AccessorInfo& info) {
 
15223
  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
 
15224
  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
 
15225
  if (!name->Equals(v8_str("foo"))) return Handle<Value>();
 
15226
  return v8_num(42);
 
15227
}
 
15228
 
 
15229
 
 
15230
Handle<Value> FooSetInterceptor(Local<String> name,
 
15231
                                Local<Value> value,
 
15232
                                const AccessorInfo& info) {
 
15233
  CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
 
15234
  CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
 
15235
  if (!name->Equals(v8_str("foo"))) return Handle<Value>();
 
15236
  info.This()->Set(v8_str("y"), v8_num(23));
 
15237
  return v8_num(23);
 
15238
}
 
15239
 
 
15240
 
 
15241
TEST(SetterOnConstructorPrototype) {
 
15242
  v8::HandleScope scope;
 
15243
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
15244
  templ->SetAccessor(v8_str("x"),
 
15245
                     GetterWhichReturns42,
 
15246
                     SetterWhichSetsYOnThisTo23);
 
15247
  LocalContext context;
 
15248
  context->Global()->Set(v8_str("P"), templ->NewInstance());
 
15249
  CompileRun("function C1() {"
 
15250
             "  this.x = 23;"
 
15251
             "};"
 
15252
             "C1.prototype = P;"
 
15253
             "function C2() {"
 
15254
             "  this.x = 23"
 
15255
             "};"
 
15256
             "C2.prototype = { };"
 
15257
             "C2.prototype.__proto__ = P;");
 
15258
 
 
15259
  v8::Local<v8::Script> script;
 
15260
  script = v8::Script::Compile(v8_str("new C1();"));
 
15261
  for (int i = 0; i < 10; i++) {
 
15262
    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
 
15263
    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
 
15264
    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
 
15265
  }
 
15266
 
 
15267
  script = v8::Script::Compile(v8_str("new C2();"));
 
15268
  for (int i = 0; i < 10; i++) {
 
15269
    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
 
15270
    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
 
15271
    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
 
15272
  }
 
15273
}
 
15274
 
 
15275
 
 
15276
static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
 
15277
    Local<String> name, const AccessorInfo& info) {
 
15278
  return v8_num(42);
 
15279
}
 
15280
 
 
15281
 
 
15282
static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
 
15283
    Local<String> name, Local<Value> value, const AccessorInfo& info) {
 
15284
  if (name->Equals(v8_str("x"))) {
 
15285
    info.This()->Set(v8_str("y"), v8_num(23));
 
15286
  }
 
15287
  return v8::Handle<Value>();
 
15288
}
 
15289
 
 
15290
 
 
15291
THREADED_TEST(InterceptorOnConstructorPrototype) {
 
15292
  v8::HandleScope scope;
 
15293
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
15294
  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
 
15295
                                 NamedPropertySetterWhichSetsYOnThisTo23);
 
15296
  LocalContext context;
 
15297
  context->Global()->Set(v8_str("P"), templ->NewInstance());
 
15298
  CompileRun("function C1() {"
 
15299
             "  this.x = 23;"
 
15300
             "};"
 
15301
             "C1.prototype = P;"
 
15302
             "function C2() {"
 
15303
             "  this.x = 23"
 
15304
             "};"
 
15305
             "C2.prototype = { };"
 
15306
             "C2.prototype.__proto__ = P;");
 
15307
 
 
15308
  v8::Local<v8::Script> script;
 
15309
  script = v8::Script::Compile(v8_str("new C1();"));
 
15310
  for (int i = 0; i < 10; i++) {
 
15311
    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
 
15312
    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
 
15313
    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
 
15314
  }
 
15315
 
 
15316
  script = v8::Script::Compile(v8_str("new C2();"));
 
15317
  for (int i = 0; i < 10; i++) {
 
15318
    v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
 
15319
    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
 
15320
    CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
 
15321
  }
 
15322
}
 
15323
 
 
15324
 
 
15325
TEST(Bug618) {
 
15326
  const char* source = "function C1() {"
 
15327
                       "  this.x = 23;"
 
15328
                       "};"
 
15329
                       "C1.prototype = P;";
 
15330
 
 
15331
  v8::HandleScope scope;
 
15332
  LocalContext context;
 
15333
  v8::Local<v8::Script> script;
 
15334
 
 
15335
  // Use a simple object as prototype.
 
15336
  v8::Local<v8::Object> prototype = v8::Object::New();
 
15337
  prototype->Set(v8_str("y"), v8_num(42));
 
15338
  context->Global()->Set(v8_str("P"), prototype);
 
15339
 
 
15340
  // This compile will add the code to the compilation cache.
 
15341
  CompileRun(source);
 
15342
 
 
15343
  script = v8::Script::Compile(v8_str("new C1();"));
 
15344
  // Allow enough iterations for the inobject slack tracking logic
 
15345
  // to finalize instance size and install the fast construct stub.
 
15346
  for (int i = 0; i < 256; i++) {
 
15347
    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
 
15348
    CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
 
15349
    CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
 
15350
  }
 
15351
 
 
15352
  // Use an API object with accessors as prototype.
 
15353
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
15354
  templ->SetAccessor(v8_str("x"),
 
15355
                     GetterWhichReturns42,
 
15356
                     SetterWhichSetsYOnThisTo23);
 
15357
  context->Global()->Set(v8_str("P"), templ->NewInstance());
 
15358
 
 
15359
  // This compile will get the code from the compilation cache.
 
15360
  CompileRun(source);
 
15361
 
 
15362
  script = v8::Script::Compile(v8_str("new C1();"));
 
15363
  for (int i = 0; i < 10; i++) {
 
15364
    v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
 
15365
    CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
 
15366
    CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
 
15367
  }
 
15368
}
 
15369
 
 
15370
int prologue_call_count = 0;
 
15371
int epilogue_call_count = 0;
 
15372
int prologue_call_count_second = 0;
 
15373
int epilogue_call_count_second = 0;
 
15374
 
 
15375
void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
 
15376
  ++prologue_call_count;
 
15377
}
 
15378
 
 
15379
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
 
15380
  ++epilogue_call_count;
 
15381
}
 
15382
 
 
15383
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
 
15384
  ++prologue_call_count_second;
 
15385
}
 
15386
 
 
15387
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
 
15388
  ++epilogue_call_count_second;
 
15389
}
 
15390
 
 
15391
TEST(GCCallbacks) {
 
15392
  LocalContext context;
 
15393
 
 
15394
  v8::V8::AddGCPrologueCallback(PrologueCallback);
 
15395
  v8::V8::AddGCEpilogueCallback(EpilogueCallback);
 
15396
  CHECK_EQ(0, prologue_call_count);
 
15397
  CHECK_EQ(0, epilogue_call_count);
 
15398
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15399
  CHECK_EQ(1, prologue_call_count);
 
15400
  CHECK_EQ(1, epilogue_call_count);
 
15401
  v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
 
15402
  v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
 
15403
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15404
  CHECK_EQ(2, prologue_call_count);
 
15405
  CHECK_EQ(2, epilogue_call_count);
 
15406
  CHECK_EQ(1, prologue_call_count_second);
 
15407
  CHECK_EQ(1, epilogue_call_count_second);
 
15408
  v8::V8::RemoveGCPrologueCallback(PrologueCallback);
 
15409
  v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
 
15410
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15411
  CHECK_EQ(2, prologue_call_count);
 
15412
  CHECK_EQ(2, epilogue_call_count);
 
15413
  CHECK_EQ(2, prologue_call_count_second);
 
15414
  CHECK_EQ(2, epilogue_call_count_second);
 
15415
  v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
 
15416
  v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
 
15417
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15418
  CHECK_EQ(2, prologue_call_count);
 
15419
  CHECK_EQ(2, epilogue_call_count);
 
15420
  CHECK_EQ(2, prologue_call_count_second);
 
15421
  CHECK_EQ(2, epilogue_call_count_second);
 
15422
}
 
15423
 
 
15424
 
 
15425
THREADED_TEST(AddToJSFunctionResultCache) {
 
15426
  i::FLAG_allow_natives_syntax = true;
 
15427
  v8::HandleScope scope;
 
15428
 
 
15429
  LocalContext context;
 
15430
 
 
15431
  const char* code =
 
15432
      "(function() {"
 
15433
      "  var key0 = 'a';"
 
15434
      "  var key1 = 'b';"
 
15435
      "  var r0 = %_GetFromCache(0, key0);"
 
15436
      "  var r1 = %_GetFromCache(0, key1);"
 
15437
      "  var r0_ = %_GetFromCache(0, key0);"
 
15438
      "  if (r0 !== r0_)"
 
15439
      "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
 
15440
      "  var r1_ = %_GetFromCache(0, key1);"
 
15441
      "  if (r1 !== r1_)"
 
15442
      "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
 
15443
      "  return 'PASSED';"
 
15444
      "})()";
 
15445
  HEAP->ClearJSFunctionResultCaches();
 
15446
  ExpectString(code, "PASSED");
 
15447
}
 
15448
 
 
15449
 
 
15450
static const int k0CacheSize = 16;
 
15451
 
 
15452
THREADED_TEST(FillJSFunctionResultCache) {
 
15453
  i::FLAG_allow_natives_syntax = true;
 
15454
  v8::HandleScope scope;
 
15455
 
 
15456
  LocalContext context;
 
15457
 
 
15458
  const char* code =
 
15459
      "(function() {"
 
15460
      "  var k = 'a';"
 
15461
      "  var r = %_GetFromCache(0, k);"
 
15462
      "  for (var i = 0; i < 16; i++) {"
 
15463
      "    %_GetFromCache(0, 'a' + i);"
 
15464
      "  };"
 
15465
      "  if (r === %_GetFromCache(0, k))"
 
15466
      "    return 'FAILED: k0CacheSize is too small';"
 
15467
      "  return 'PASSED';"
 
15468
      "})()";
 
15469
  HEAP->ClearJSFunctionResultCaches();
 
15470
  ExpectString(code, "PASSED");
 
15471
}
 
15472
 
 
15473
 
 
15474
THREADED_TEST(RoundRobinGetFromCache) {
 
15475
  i::FLAG_allow_natives_syntax = true;
 
15476
  v8::HandleScope scope;
 
15477
 
 
15478
  LocalContext context;
 
15479
 
 
15480
  const char* code =
 
15481
      "(function() {"
 
15482
      "  var keys = [];"
 
15483
      "  for (var i = 0; i < 16; i++) keys.push(i);"
 
15484
      "  var values = [];"
 
15485
      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
 
15486
      "  for (var i = 0; i < 16; i++) {"
 
15487
      "    var v = %_GetFromCache(0, keys[i]);"
 
15488
      "    if (v.toString() !== values[i].toString())"
 
15489
      "      return 'Wrong value for ' + "
 
15490
      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
 
15491
      "  };"
 
15492
      "  return 'PASSED';"
 
15493
      "})()";
 
15494
  HEAP->ClearJSFunctionResultCaches();
 
15495
  ExpectString(code, "PASSED");
 
15496
}
 
15497
 
 
15498
 
 
15499
THREADED_TEST(ReverseGetFromCache) {
 
15500
  i::FLAG_allow_natives_syntax = true;
 
15501
  v8::HandleScope scope;
 
15502
 
 
15503
  LocalContext context;
 
15504
 
 
15505
  const char* code =
 
15506
      "(function() {"
 
15507
      "  var keys = [];"
 
15508
      "  for (var i = 0; i < 16; i++) keys.push(i);"
 
15509
      "  var values = [];"
 
15510
      "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
 
15511
      "  for (var i = 15; i >= 16; i--) {"
 
15512
      "    var v = %_GetFromCache(0, keys[i]);"
 
15513
      "    if (v !== values[i])"
 
15514
      "      return 'Wrong value for ' + "
 
15515
      "          keys[i] + ': ' + v + ' vs. ' + values[i];"
 
15516
      "  };"
 
15517
      "  return 'PASSED';"
 
15518
      "})()";
 
15519
  HEAP->ClearJSFunctionResultCaches();
 
15520
  ExpectString(code, "PASSED");
 
15521
}
 
15522
 
 
15523
 
 
15524
THREADED_TEST(TestEviction) {
 
15525
  i::FLAG_allow_natives_syntax = true;
 
15526
  v8::HandleScope scope;
 
15527
 
 
15528
  LocalContext context;
 
15529
 
 
15530
  const char* code =
 
15531
      "(function() {"
 
15532
      "  for (var i = 0; i < 2*16; i++) {"
 
15533
      "    %_GetFromCache(0, 'a' + i);"
 
15534
      "  };"
 
15535
      "  return 'PASSED';"
 
15536
      "})()";
 
15537
  HEAP->ClearJSFunctionResultCaches();
 
15538
  ExpectString(code, "PASSED");
 
15539
}
 
15540
 
 
15541
 
 
15542
THREADED_TEST(TwoByteStringInAsciiCons) {
 
15543
  // See Chromium issue 47824.
 
15544
  v8::HandleScope scope;
 
15545
 
 
15546
  LocalContext context;
 
15547
  const char* init_code =
 
15548
      "var str1 = 'abelspendabel';"
 
15549
      "var str2 = str1 + str1 + str1;"
 
15550
      "str2;";
 
15551
  Local<Value> result = CompileRun(init_code);
 
15552
 
 
15553
  Local<Value> indexof = CompileRun("str2.indexOf('els')");
 
15554
  Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
 
15555
 
 
15556
  CHECK(result->IsString());
 
15557
  i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
 
15558
  int length = string->length();
 
15559
  CHECK(string->IsAsciiRepresentation());
 
15560
 
 
15561
  FlattenString(string);
 
15562
  i::Handle<i::String> flat_string = FlattenGetString(string);
 
15563
 
 
15564
  CHECK(string->IsAsciiRepresentation());
 
15565
  CHECK(flat_string->IsAsciiRepresentation());
 
15566
 
 
15567
  // Create external resource.
 
15568
  uint16_t* uc16_buffer = new uint16_t[length + 1];
 
15569
 
 
15570
  i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
 
15571
  uc16_buffer[length] = 0;
 
15572
 
 
15573
  TestResource resource(uc16_buffer);
 
15574
 
 
15575
  flat_string->MakeExternal(&resource);
 
15576
 
 
15577
  CHECK(flat_string->IsTwoByteRepresentation());
 
15578
 
 
15579
  // At this point, we should have a Cons string which is flat and ASCII,
 
15580
  // with a first half that is a two-byte string (although it only contains
 
15581
  // ASCII characters). This is a valid sequence of steps, and it can happen
 
15582
  // in real pages.
 
15583
 
 
15584
  CHECK(string->IsAsciiRepresentation());
 
15585
  i::ConsString* cons = i::ConsString::cast(*string);
 
15586
  CHECK_EQ(0, cons->second()->length());
 
15587
  CHECK(cons->first()->IsTwoByteRepresentation());
 
15588
 
 
15589
  // Check that some string operations work.
 
15590
 
 
15591
  // Atom RegExp.
 
15592
  Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
 
15593
  CHECK_EQ(6, reresult->Int32Value());
 
15594
 
 
15595
  // Nonatom RegExp.
 
15596
  reresult = CompileRun("str2.match(/abe./g).length;");
 
15597
  CHECK_EQ(6, reresult->Int32Value());
 
15598
 
 
15599
  reresult = CompileRun("str2.search(/bel/g);");
 
15600
  CHECK_EQ(1, reresult->Int32Value());
 
15601
 
 
15602
  reresult = CompileRun("str2.search(/be./g);");
 
15603
  CHECK_EQ(1, reresult->Int32Value());
 
15604
 
 
15605
  ExpectTrue("/bel/g.test(str2);");
 
15606
 
 
15607
  ExpectTrue("/be./g.test(str2);");
 
15608
 
 
15609
  reresult = CompileRun("/bel/g.exec(str2);");
 
15610
  CHECK(!reresult->IsNull());
 
15611
 
 
15612
  reresult = CompileRun("/be./g.exec(str2);");
 
15613
  CHECK(!reresult->IsNull());
 
15614
 
 
15615
  ExpectString("str2.substring(2, 10);", "elspenda");
 
15616
 
 
15617
  ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
 
15618
 
 
15619
  ExpectString("str2.charAt(2);", "e");
 
15620
 
 
15621
  ExpectObject("str2.indexOf('els');", indexof);
 
15622
 
 
15623
  ExpectObject("str2.lastIndexOf('dab');", lastindexof);
 
15624
 
 
15625
  reresult = CompileRun("str2.charCodeAt(2);");
 
15626
  CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
 
15627
}
 
15628
 
 
15629
 
 
15630
// Failed access check callback that performs a GC on each invocation.
 
15631
void FailedAccessCheckCallbackGC(Local<v8::Object> target,
 
15632
                                 v8::AccessType type,
 
15633
                                 Local<v8::Value> data) {
 
15634
  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
15635
}
 
15636
 
 
15637
 
 
15638
TEST(GCInFailedAccessCheckCallback) {
 
15639
  // Install a failed access check callback that performs a GC on each
 
15640
  // invocation. Then force the callback to be called from va
 
15641
 
 
15642
  v8::V8::Initialize();
 
15643
  v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
 
15644
 
 
15645
  v8::HandleScope scope;
 
15646
 
 
15647
  // Create an ObjectTemplate for global objects and install access
 
15648
  // check callbacks that will block access.
 
15649
  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
 
15650
  global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
 
15651
                                           IndexedGetAccessBlocker,
 
15652
                                           v8::Handle<v8::Value>(),
 
15653
                                           false);
 
15654
 
 
15655
  // Create a context and set an x property on it's global object.
 
15656
  LocalContext context0(NULL, global_template);
 
15657
  context0->Global()->Set(v8_str("x"), v8_num(42));
 
15658
  v8::Handle<v8::Object> global0 = context0->Global();
 
15659
 
 
15660
  // Create a context with a different security token so that the
 
15661
  // failed access check callback will be called on each access.
 
15662
  LocalContext context1(NULL, global_template);
 
15663
  context1->Global()->Set(v8_str("other"), global0);
 
15664
 
 
15665
  // Get property with failed access check.
 
15666
  ExpectUndefined("other.x");
 
15667
 
 
15668
  // Get element with failed access check.
 
15669
  ExpectUndefined("other[0]");
 
15670
 
 
15671
  // Set property with failed access check.
 
15672
  v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
 
15673
  CHECK(result->IsObject());
 
15674
 
 
15675
  // Set element with failed access check.
 
15676
  result = CompileRun("other[0] = new Object()");
 
15677
  CHECK(result->IsObject());
 
15678
 
 
15679
  // Get property attribute with failed access check.
 
15680
  ExpectFalse("\'x\' in other");
 
15681
 
 
15682
  // Get property attribute for element with failed access check.
 
15683
  ExpectFalse("0 in other");
 
15684
 
 
15685
  // Delete property.
 
15686
  ExpectFalse("delete other.x");
 
15687
 
 
15688
  // Delete element.
 
15689
  CHECK_EQ(false, global0->Delete(0));
 
15690
 
 
15691
  // DefineAccessor.
 
15692
  CHECK_EQ(false,
 
15693
           global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
 
15694
 
 
15695
  // Define JavaScript accessor.
 
15696
  ExpectUndefined("Object.prototype.__defineGetter__.call("
 
15697
                  "    other, \'x\', function() { return 42; })");
 
15698
 
 
15699
  // LookupAccessor.
 
15700
  ExpectUndefined("Object.prototype.__lookupGetter__.call("
 
15701
                  "    other, \'x\')");
 
15702
 
 
15703
  // HasLocalElement.
 
15704
  ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
 
15705
 
 
15706
  CHECK_EQ(false, global0->HasRealIndexedProperty(0));
 
15707
  CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
 
15708
  CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
 
15709
 
 
15710
  // Reset the failed access check callback so it does not influence
 
15711
  // the other tests.
 
15712
  v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
 
15713
}
 
15714
 
 
15715
TEST(DefaultIsolateGetCurrent) {
 
15716
  CHECK(v8::Isolate::GetCurrent() != NULL);
 
15717
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
15718
  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
 
15719
  printf("*** %s\n", "DefaultIsolateGetCurrent success");
 
15720
}
 
15721
 
 
15722
TEST(IsolateNewDispose) {
 
15723
  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
 
15724
  v8::Isolate* isolate = v8::Isolate::New();
 
15725
  CHECK(isolate != NULL);
 
15726
  CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
 
15727
  CHECK(current_isolate != isolate);
 
15728
  CHECK(current_isolate == v8::Isolate::GetCurrent());
 
15729
 
 
15730
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
15731
  last_location = last_message = NULL;
 
15732
  isolate->Dispose();
 
15733
  CHECK_EQ(last_location, NULL);
 
15734
  CHECK_EQ(last_message, NULL);
 
15735
}
 
15736
 
 
15737
TEST(IsolateEnterExitDefault) {
 
15738
  v8::HandleScope scope;
 
15739
  LocalContext context;
 
15740
  v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
 
15741
  CHECK(current_isolate != NULL);  // Default isolate.
 
15742
  ExpectString("'hello'", "hello");
 
15743
  current_isolate->Enter();
 
15744
  ExpectString("'still working'", "still working");
 
15745
  current_isolate->Exit();
 
15746
  ExpectString("'still working 2'", "still working 2");
 
15747
  current_isolate->Exit();
 
15748
  // Default isolate is always, well, 'default current'.
 
15749
  CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
 
15750
  // Still working since default isolate is auto-entering any thread
 
15751
  // that has no isolate and attempts to execute V8 APIs.
 
15752
  ExpectString("'still working 3'", "still working 3");
 
15753
}
 
15754
 
 
15755
TEST(DisposeDefaultIsolate) {
 
15756
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
15757
 
 
15758
  // Run some V8 code to trigger default isolate to become 'current'.
 
15759
  v8::HandleScope scope;
 
15760
  LocalContext context;
 
15761
  ExpectString("'run some V8'", "run some V8");
 
15762
 
 
15763
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
15764
  CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
 
15765
  last_location = last_message = NULL;
 
15766
  isolate->Dispose();
 
15767
  // It is not possible to dispose default isolate via Isolate API.
 
15768
  CHECK_NE(last_location, NULL);
 
15769
  CHECK_NE(last_message, NULL);
 
15770
}
 
15771
 
 
15772
TEST(RunDefaultAndAnotherIsolate) {
 
15773
  v8::HandleScope scope;
 
15774
  LocalContext context;
 
15775
 
 
15776
  // Enter new isolate.
 
15777
  v8::Isolate* isolate = v8::Isolate::New();
 
15778
  CHECK(isolate);
 
15779
  isolate->Enter();
 
15780
  { // Need this block because subsequent Exit() will deallocate Heap,
 
15781
    // so we need all scope objects to be deconstructed when it happens.
 
15782
    v8::HandleScope scope_new;
 
15783
    LocalContext context_new;
 
15784
 
 
15785
    // Run something in new isolate.
 
15786
    CompileRun("var foo = 153;");
 
15787
    ExpectTrue("function f() { return foo == 153; }; f()");
 
15788
  }
 
15789
  isolate->Exit();
 
15790
 
 
15791
  // This runs automatically in default isolate.
 
15792
  // Variables in another isolate should be not available.
 
15793
  ExpectTrue("function f() {"
 
15794
             "  try {"
 
15795
             "    foo;"
 
15796
             "    return false;"
 
15797
             "  } catch(e) {"
 
15798
             "    return true;"
 
15799
             "  }"
 
15800
             "};"
 
15801
             "var bar = 371;"
 
15802
             "f()");
 
15803
 
 
15804
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
15805
  last_location = last_message = NULL;
 
15806
  isolate->Dispose();
 
15807
  CHECK_EQ(last_location, NULL);
 
15808
  CHECK_EQ(last_message, NULL);
 
15809
 
 
15810
  // Check that default isolate still runs.
 
15811
  ExpectTrue("function f() { return bar == 371; }; f()");
 
15812
}
 
15813
 
 
15814
TEST(DisposeIsolateWhenInUse) {
 
15815
  v8::Isolate* isolate = v8::Isolate::New();
 
15816
  CHECK(isolate);
 
15817
  isolate->Enter();
 
15818
  v8::HandleScope scope;
 
15819
  LocalContext context;
 
15820
  // Run something in this isolate.
 
15821
  ExpectTrue("true");
 
15822
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
15823
  last_location = last_message = NULL;
 
15824
  // Still entered, should fail.
 
15825
  isolate->Dispose();
 
15826
  CHECK_NE(last_location, NULL);
 
15827
  CHECK_NE(last_message, NULL);
 
15828
}
 
15829
 
 
15830
TEST(RunTwoIsolatesOnSingleThread) {
 
15831
  // Run isolate 1.
 
15832
  v8::Isolate* isolate1 = v8::Isolate::New();
 
15833
  isolate1->Enter();
 
15834
  v8::Persistent<v8::Context> context1 = v8::Context::New();
 
15835
 
 
15836
  {
 
15837
    v8::Context::Scope cscope(context1);
 
15838
    v8::HandleScope scope;
 
15839
    // Run something in new isolate.
 
15840
    CompileRun("var foo = 'isolate 1';");
 
15841
    ExpectString("function f() { return foo; }; f()", "isolate 1");
 
15842
  }
 
15843
 
 
15844
  // Run isolate 2.
 
15845
  v8::Isolate* isolate2 = v8::Isolate::New();
 
15846
  v8::Persistent<v8::Context> context2;
 
15847
 
 
15848
  {
 
15849
    v8::Isolate::Scope iscope(isolate2);
 
15850
    context2 = v8::Context::New();
 
15851
    v8::Context::Scope cscope(context2);
 
15852
    v8::HandleScope scope;
 
15853
 
 
15854
    // Run something in new isolate.
 
15855
    CompileRun("var foo = 'isolate 2';");
 
15856
    ExpectString("function f() { return foo; }; f()", "isolate 2");
 
15857
  }
 
15858
 
 
15859
  {
 
15860
    v8::Context::Scope cscope(context1);
 
15861
    v8::HandleScope scope;
 
15862
    // Now again in isolate 1
 
15863
    ExpectString("function f() { return foo; }; f()", "isolate 1");
 
15864
  }
 
15865
 
 
15866
  isolate1->Exit();
 
15867
 
 
15868
  // Run some stuff in default isolate.
 
15869
  v8::Persistent<v8::Context> context_default = v8::Context::New();
 
15870
 
 
15871
  {
 
15872
    v8::Context::Scope cscope(context_default);
 
15873
    v8::HandleScope scope;
 
15874
    // Variables in other isolates should be not available, verify there
 
15875
    // is an exception.
 
15876
    ExpectTrue("function f() {"
 
15877
               "  try {"
 
15878
               "    foo;"
 
15879
               "    return false;"
 
15880
               "  } catch(e) {"
 
15881
               "    return true;"
 
15882
               "  }"
 
15883
               "};"
 
15884
               "var isDefaultIsolate = true;"
 
15885
               "f()");
 
15886
  }
 
15887
 
 
15888
  isolate1->Enter();
 
15889
 
 
15890
  {
 
15891
    v8::Isolate::Scope iscope(isolate2);
 
15892
    v8::Context::Scope cscope(context2);
 
15893
    v8::HandleScope scope;
 
15894
    ExpectString("function f() { return foo; }; f()", "isolate 2");
 
15895
  }
 
15896
 
 
15897
  {
 
15898
    v8::Context::Scope cscope(context1);
 
15899
    v8::HandleScope scope;
 
15900
    ExpectString("function f() { return foo; }; f()", "isolate 1");
 
15901
  }
 
15902
 
 
15903
  {
 
15904
    v8::Isolate::Scope iscope(isolate2);
 
15905
    context2.Dispose();
 
15906
  }
 
15907
 
 
15908
  context1.Dispose();
 
15909
  isolate1->Exit();
 
15910
 
 
15911
  v8::V8::SetFatalErrorHandler(StoringErrorCallback);
 
15912
  last_location = last_message = NULL;
 
15913
 
 
15914
  isolate1->Dispose();
 
15915
  CHECK_EQ(last_location, NULL);
 
15916
  CHECK_EQ(last_message, NULL);
 
15917
 
 
15918
  isolate2->Dispose();
 
15919
  CHECK_EQ(last_location, NULL);
 
15920
  CHECK_EQ(last_message, NULL);
 
15921
 
 
15922
  // Check that default isolate still runs.
 
15923
  {
 
15924
    v8::Context::Scope cscope(context_default);
 
15925
    v8::HandleScope scope;
 
15926
    ExpectTrue("function f() { return isDefaultIsolate; }; f()");
 
15927
  }
 
15928
}
 
15929
 
 
15930
static int CalcFibonacci(v8::Isolate* isolate, int limit) {
 
15931
  v8::Isolate::Scope isolate_scope(isolate);
 
15932
  v8::HandleScope scope;
 
15933
  LocalContext context;
 
15934
  i::ScopedVector<char> code(1024);
 
15935
  i::OS::SNPrintF(code, "function fib(n) {"
 
15936
                        "  if (n <= 2) return 1;"
 
15937
                        "  return fib(n-1) + fib(n-2);"
 
15938
                        "}"
 
15939
                        "fib(%d)", limit);
 
15940
  Local<Value> value = CompileRun(code.start());
 
15941
  CHECK(value->IsNumber());
 
15942
  return static_cast<int>(value->NumberValue());
 
15943
}
 
15944
 
 
15945
class IsolateThread : public v8::internal::Thread {
 
15946
 public:
 
15947
  IsolateThread(v8::Isolate* isolate, int fib_limit)
 
15948
      : Thread("IsolateThread"),
 
15949
        isolate_(isolate),
 
15950
        fib_limit_(fib_limit),
 
15951
        result_(0) { }
 
15952
 
 
15953
  void Run() {
 
15954
    result_ = CalcFibonacci(isolate_, fib_limit_);
 
15955
  }
 
15956
 
 
15957
  int result() { return result_; }
 
15958
 
 
15959
 private:
 
15960
  v8::Isolate* isolate_;
 
15961
  int fib_limit_;
 
15962
  int result_;
 
15963
};
 
15964
 
 
15965
TEST(MultipleIsolatesOnIndividualThreads) {
 
15966
  v8::Isolate* isolate1 = v8::Isolate::New();
 
15967
  v8::Isolate* isolate2 = v8::Isolate::New();
 
15968
 
 
15969
  IsolateThread thread1(isolate1, 21);
 
15970
  IsolateThread thread2(isolate2, 12);
 
15971
 
 
15972
  // Compute some fibonacci numbers on 3 threads in 3 isolates.
 
15973
  thread1.Start();
 
15974
  thread2.Start();
 
15975
 
 
15976
  int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
 
15977
  int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
 
15978
 
 
15979
  thread1.Join();
 
15980
  thread2.Join();
 
15981
 
 
15982
  // Compare results. The actual fibonacci numbers for 12 and 21 are taken
 
15983
  // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
 
15984
  CHECK_EQ(result1, 10946);
 
15985
  CHECK_EQ(result2, 144);
 
15986
  CHECK_EQ(result1, thread1.result());
 
15987
  CHECK_EQ(result2, thread2.result());
 
15988
 
 
15989
  isolate1->Dispose();
 
15990
  isolate2->Dispose();
 
15991
}
 
15992
 
 
15993
TEST(IsolateDifferentContexts) {
 
15994
  v8::Isolate* isolate = v8::Isolate::New();
 
15995
  Persistent<v8::Context> context;
 
15996
  {
 
15997
    v8::Isolate::Scope isolate_scope(isolate);
 
15998
    v8::HandleScope handle_scope;
 
15999
    context = v8::Context::New();
 
16000
    v8::Context::Scope context_scope(context);
 
16001
    Local<Value> v = CompileRun("2");
 
16002
    CHECK(v->IsNumber());
 
16003
    CHECK_EQ(2, static_cast<int>(v->NumberValue()));
 
16004
  }
 
16005
  {
 
16006
    v8::Isolate::Scope isolate_scope(isolate);
 
16007
    v8::HandleScope handle_scope;
 
16008
    context = v8::Context::New();
 
16009
    v8::Context::Scope context_scope(context);
 
16010
    Local<Value> v = CompileRun("22");
 
16011
    CHECK(v->IsNumber());
 
16012
    CHECK_EQ(22, static_cast<int>(v->NumberValue()));
 
16013
  }
 
16014
}
 
16015
 
 
16016
class InitDefaultIsolateThread : public v8::internal::Thread {
 
16017
 public:
 
16018
  enum TestCase {
 
16019
    IgnoreOOM,
 
16020
    SetResourceConstraints,
 
16021
    SetFatalHandler,
 
16022
    SetCounterFunction,
 
16023
    SetCreateHistogramFunction,
 
16024
    SetAddHistogramSampleFunction
 
16025
  };
 
16026
 
 
16027
  explicit InitDefaultIsolateThread(TestCase testCase)
 
16028
      : Thread("InitDefaultIsolateThread"),
 
16029
        testCase_(testCase),
 
16030
        result_(false) { }
 
16031
 
 
16032
  void Run() {
 
16033
    switch (testCase_) {
 
16034
    case IgnoreOOM:
 
16035
      v8::V8::IgnoreOutOfMemoryException();
 
16036
      break;
 
16037
 
 
16038
    case SetResourceConstraints: {
 
16039
      static const int K = 1024;
 
16040
      v8::ResourceConstraints constraints;
 
16041
      constraints.set_max_young_space_size(256 * K);
 
16042
      constraints.set_max_old_space_size(4 * K * K);
 
16043
      v8::SetResourceConstraints(&constraints);
 
16044
      break;
 
16045
    }
 
16046
 
 
16047
    case SetFatalHandler:
 
16048
      v8::V8::SetFatalErrorHandler(NULL);
 
16049
      break;
 
16050
 
 
16051
    case SetCounterFunction:
 
16052
      v8::V8::SetCounterFunction(NULL);
 
16053
      break;
 
16054
 
 
16055
    case SetCreateHistogramFunction:
 
16056
      v8::V8::SetCreateHistogramFunction(NULL);
 
16057
      break;
 
16058
 
 
16059
    case SetAddHistogramSampleFunction:
 
16060
      v8::V8::SetAddHistogramSampleFunction(NULL);
 
16061
      break;
 
16062
    }
 
16063
    result_ = true;
 
16064
  }
 
16065
 
 
16066
  bool result() { return result_; }
 
16067
 
 
16068
 private:
 
16069
  TestCase testCase_;
 
16070
  bool result_;
 
16071
};
 
16072
 
 
16073
 
 
16074
static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
 
16075
  InitDefaultIsolateThread thread(testCase);
 
16076
  thread.Start();
 
16077
  thread.Join();
 
16078
  CHECK_EQ(thread.result(), true);
 
16079
}
 
16080
 
 
16081
TEST(InitializeDefaultIsolateOnSecondaryThread1) {
 
16082
  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
 
16083
}
 
16084
 
 
16085
TEST(InitializeDefaultIsolateOnSecondaryThread2) {
 
16086
  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
 
16087
}
 
16088
 
 
16089
TEST(InitializeDefaultIsolateOnSecondaryThread3) {
 
16090
  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
 
16091
}
 
16092
 
 
16093
TEST(InitializeDefaultIsolateOnSecondaryThread4) {
 
16094
  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
 
16095
}
 
16096
 
 
16097
TEST(InitializeDefaultIsolateOnSecondaryThread5) {
 
16098
  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
 
16099
}
 
16100
 
 
16101
TEST(InitializeDefaultIsolateOnSecondaryThread6) {
 
16102
  InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
 
16103
}
 
16104
 
 
16105
 
 
16106
TEST(StringCheckMultipleContexts) {
 
16107
  const char* code =
 
16108
      "(function() { return \"a\".charAt(0); })()";
 
16109
 
 
16110
  {
 
16111
    // Run the code twice in the first context to initialize the call IC.
 
16112
    v8::HandleScope scope;
 
16113
    LocalContext context1;
 
16114
    ExpectString(code, "a");
 
16115
    ExpectString(code, "a");
 
16116
  }
 
16117
 
 
16118
  {
 
16119
    // Change the String.prototype in the second context and check
 
16120
    // that the right function gets called.
 
16121
    v8::HandleScope scope;
 
16122
    LocalContext context2;
 
16123
    CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
 
16124
    ExpectString(code, "not a");
 
16125
  }
 
16126
}
 
16127
 
 
16128
 
 
16129
TEST(NumberCheckMultipleContexts) {
 
16130
  const char* code =
 
16131
      "(function() { return (42).toString(); })()";
 
16132
 
 
16133
  {
 
16134
    // Run the code twice in the first context to initialize the call IC.
 
16135
    v8::HandleScope scope;
 
16136
    LocalContext context1;
 
16137
    ExpectString(code, "42");
 
16138
    ExpectString(code, "42");
 
16139
  }
 
16140
 
 
16141
  {
 
16142
    // Change the Number.prototype in the second context and check
 
16143
    // that the right function gets called.
 
16144
    v8::HandleScope scope;
 
16145
    LocalContext context2;
 
16146
    CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
 
16147
    ExpectString(code, "not 42");
 
16148
  }
 
16149
}
 
16150
 
 
16151
 
 
16152
TEST(BooleanCheckMultipleContexts) {
 
16153
  const char* code =
 
16154
      "(function() { return true.toString(); })()";
 
16155
 
 
16156
  {
 
16157
    // Run the code twice in the first context to initialize the call IC.
 
16158
    v8::HandleScope scope;
 
16159
    LocalContext context1;
 
16160
    ExpectString(code, "true");
 
16161
    ExpectString(code, "true");
 
16162
  }
 
16163
 
 
16164
  {
 
16165
    // Change the Boolean.prototype in the second context and check
 
16166
    // that the right function gets called.
 
16167
    v8::HandleScope scope;
 
16168
    LocalContext context2;
 
16169
    CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
 
16170
    ExpectString(code, "");
 
16171
  }
 
16172
}
 
16173
 
 
16174
 
 
16175
TEST(DontDeleteCellLoadIC) {
 
16176
  const char* function_code =
 
16177
      "function readCell() { while (true) { return cell; } }";
 
16178
 
 
16179
  {
 
16180
    // Run the code twice in the first context to initialize the load
 
16181
    // IC for a don't delete cell.
 
16182
    v8::HandleScope scope;
 
16183
    LocalContext context1;
 
16184
    CompileRun("var cell = \"first\";");
 
16185
    ExpectBoolean("delete cell", false);
 
16186
    CompileRun(function_code);
 
16187
    ExpectString("readCell()", "first");
 
16188
    ExpectString("readCell()", "first");
 
16189
  }
 
16190
 
 
16191
  {
 
16192
    // Use a deletable cell in the second context.
 
16193
    v8::HandleScope scope;
 
16194
    LocalContext context2;
 
16195
    CompileRun("cell = \"second\";");
 
16196
    CompileRun(function_code);
 
16197
    ExpectString("readCell()", "second");
 
16198
    ExpectBoolean("delete cell", true);
 
16199
    ExpectString("(function() {"
 
16200
                 "  try {"
 
16201
                 "    return readCell();"
 
16202
                 "  } catch(e) {"
 
16203
                 "    return e.toString();"
 
16204
                 "  }"
 
16205
                 "})()",
 
16206
                 "ReferenceError: cell is not defined");
 
16207
    CompileRun("cell = \"new_second\";");
 
16208
    HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
 
16209
    ExpectString("readCell()", "new_second");
 
16210
    ExpectString("readCell()", "new_second");
 
16211
  }
 
16212
}
 
16213
 
 
16214
 
 
16215
TEST(DontDeleteCellLoadICForceDelete) {
 
16216
  const char* function_code =
 
16217
      "function readCell() { while (true) { return cell; } }";
 
16218
 
 
16219
  // Run the code twice to initialize the load IC for a don't delete
 
16220
  // cell.
 
16221
  v8::HandleScope scope;
 
16222
  LocalContext context;
 
16223
  CompileRun("var cell = \"value\";");
 
16224
  ExpectBoolean("delete cell", false);
 
16225
  CompileRun(function_code);
 
16226
  ExpectString("readCell()", "value");
 
16227
  ExpectString("readCell()", "value");
 
16228
 
 
16229
  // Delete the cell using the API and check the inlined code works
 
16230
  // correctly.
 
16231
  CHECK(context->Global()->ForceDelete(v8_str("cell")));
 
16232
  ExpectString("(function() {"
 
16233
               "  try {"
 
16234
               "    return readCell();"
 
16235
               "  } catch(e) {"
 
16236
               "    return e.toString();"
 
16237
               "  }"
 
16238
               "})()",
 
16239
               "ReferenceError: cell is not defined");
 
16240
}
 
16241
 
 
16242
 
 
16243
TEST(DontDeleteCellLoadICAPI) {
 
16244
  const char* function_code =
 
16245
      "function readCell() { while (true) { return cell; } }";
 
16246
 
 
16247
  // Run the code twice to initialize the load IC for a don't delete
 
16248
  // cell created using the API.
 
16249
  v8::HandleScope scope;
 
16250
  LocalContext context;
 
16251
  context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
 
16252
  ExpectBoolean("delete cell", false);
 
16253
  CompileRun(function_code);
 
16254
  ExpectString("readCell()", "value");
 
16255
  ExpectString("readCell()", "value");
 
16256
 
 
16257
  // Delete the cell using the API and check the inlined code works
 
16258
  // correctly.
 
16259
  CHECK(context->Global()->ForceDelete(v8_str("cell")));
 
16260
  ExpectString("(function() {"
 
16261
               "  try {"
 
16262
               "    return readCell();"
 
16263
               "  } catch(e) {"
 
16264
               "    return e.toString();"
 
16265
               "  }"
 
16266
               "})()",
 
16267
               "ReferenceError: cell is not defined");
 
16268
}
 
16269
 
 
16270
 
 
16271
class Visitor42 : public v8::PersistentHandleVisitor {
 
16272
 public:
 
16273
  explicit Visitor42(v8::Persistent<v8::Object> object)
 
16274
      : counter_(0), object_(object) { }
 
16275
 
 
16276
  virtual void VisitPersistentHandle(Persistent<Value> value,
 
16277
                                     uint16_t class_id) {
 
16278
    if (class_id == 42) {
 
16279
      CHECK(value->IsObject());
 
16280
      v8::Persistent<v8::Object> visited =
 
16281
          v8::Persistent<v8::Object>::Cast(value);
 
16282
      CHECK_EQ(42, visited.WrapperClassId());
 
16283
      CHECK_EQ(object_, visited);
 
16284
      ++counter_;
 
16285
    }
 
16286
  }
 
16287
 
 
16288
  int counter_;
 
16289
  v8::Persistent<v8::Object> object_;
 
16290
};
 
16291
 
 
16292
 
 
16293
TEST(PersistentHandleVisitor) {
 
16294
  v8::HandleScope scope;
 
16295
  LocalContext context;
 
16296
  v8::Persistent<v8::Object> object =
 
16297
      v8::Persistent<v8::Object>::New(v8::Object::New());
 
16298
  CHECK_EQ(0, object.WrapperClassId());
 
16299
  object.SetWrapperClassId(42);
 
16300
  CHECK_EQ(42, object.WrapperClassId());
 
16301
 
 
16302
  Visitor42 visitor(object);
 
16303
  v8::V8::VisitHandlesWithClassIds(&visitor);
 
16304
  CHECK_EQ(1, visitor.counter_);
 
16305
 
 
16306
  object.Dispose();
 
16307
}
 
16308
 
 
16309
 
 
16310
TEST(RegExp) {
 
16311
  v8::HandleScope scope;
 
16312
  LocalContext context;
 
16313
 
 
16314
  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
 
16315
  CHECK(re->IsRegExp());
 
16316
  CHECK(re->GetSource()->Equals(v8_str("foo")));
 
16317
  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
 
16318
 
 
16319
  re = v8::RegExp::New(v8_str("bar"),
 
16320
                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
 
16321
                                                      v8::RegExp::kGlobal));
 
16322
  CHECK(re->IsRegExp());
 
16323
  CHECK(re->GetSource()->Equals(v8_str("bar")));
 
16324
  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
 
16325
           static_cast<int>(re->GetFlags()));
 
16326
 
 
16327
  re = v8::RegExp::New(v8_str("baz"),
 
16328
                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
 
16329
                                                      v8::RegExp::kMultiline));
 
16330
  CHECK(re->IsRegExp());
 
16331
  CHECK(re->GetSource()->Equals(v8_str("baz")));
 
16332
  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
 
16333
           static_cast<int>(re->GetFlags()));
 
16334
 
 
16335
  re = CompileRun("/quux/").As<v8::RegExp>();
 
16336
  CHECK(re->IsRegExp());
 
16337
  CHECK(re->GetSource()->Equals(v8_str("quux")));
 
16338
  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
 
16339
 
 
16340
  re = CompileRun("/quux/gm").As<v8::RegExp>();
 
16341
  CHECK(re->IsRegExp());
 
16342
  CHECK(re->GetSource()->Equals(v8_str("quux")));
 
16343
  CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
 
16344
           static_cast<int>(re->GetFlags()));
 
16345
 
 
16346
  // Override the RegExp constructor and check the API constructor
 
16347
  // still works.
 
16348
  CompileRun("RegExp = function() {}");
 
16349
 
 
16350
  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
 
16351
  CHECK(re->IsRegExp());
 
16352
  CHECK(re->GetSource()->Equals(v8_str("foobar")));
 
16353
  CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
 
16354
 
 
16355
  re = v8::RegExp::New(v8_str("foobarbaz"),
 
16356
                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
 
16357
                                                      v8::RegExp::kMultiline));
 
16358
  CHECK(re->IsRegExp());
 
16359
  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
 
16360
  CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
 
16361
           static_cast<int>(re->GetFlags()));
 
16362
 
 
16363
  context->Global()->Set(v8_str("re"), re);
 
16364
  ExpectTrue("re.test('FoobarbaZ')");
 
16365
 
 
16366
  // RegExps are objects on which you can set properties.
 
16367
  re->Set(v8_str("property"), v8::Integer::New(32));
 
16368
  v8::Handle<v8::Value> value(CompileRun("re.property"));
 
16369
  CHECK_EQ(32, value->Int32Value());
 
16370
 
 
16371
  v8::TryCatch try_catch;
 
16372
  re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
 
16373
  CHECK(re.IsEmpty());
 
16374
  CHECK(try_catch.HasCaught());
 
16375
  context->Global()->Set(v8_str("ex"), try_catch.Exception());
 
16376
  ExpectTrue("ex instanceof SyntaxError");
 
16377
}
 
16378
 
 
16379
 
 
16380
THREADED_TEST(Equals) {
 
16381
  v8::HandleScope handleScope;
 
16382
  LocalContext localContext;
 
16383
 
 
16384
  v8::Handle<v8::Object> globalProxy = localContext->Global();
 
16385
  v8::Handle<Value> global = globalProxy->GetPrototype();
 
16386
 
 
16387
  CHECK(global->StrictEquals(global));
 
16388
  CHECK(!global->StrictEquals(globalProxy));
 
16389
  CHECK(!globalProxy->StrictEquals(global));
 
16390
  CHECK(globalProxy->StrictEquals(globalProxy));
 
16391
 
 
16392
  CHECK(global->Equals(global));
 
16393
  CHECK(!global->Equals(globalProxy));
 
16394
  CHECK(!globalProxy->Equals(global));
 
16395
  CHECK(globalProxy->Equals(globalProxy));
 
16396
}
 
16397
 
 
16398
 
 
16399
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
 
16400
                                    const v8::AccessorInfo& info ) {
 
16401
  return v8_str("42!");
 
16402
}
 
16403
 
 
16404
 
 
16405
static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
 
16406
  v8::Handle<v8::Array> result = v8::Array::New();
 
16407
  result->Set(0, v8_str("universalAnswer"));
 
16408
  return result;
 
16409
}
 
16410
 
 
16411
 
 
16412
TEST(NamedEnumeratorAndForIn) {
 
16413
  v8::HandleScope handle_scope;
 
16414
  LocalContext context;
 
16415
  v8::Context::Scope context_scope(context.local());
 
16416
 
 
16417
  v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
 
16418
  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
 
16419
  context->Global()->Set(v8_str("o"), tmpl->NewInstance());
 
16420
  v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
 
16421
        "var result = []; for (var k in o) result.push(k); result"));
 
16422
  CHECK_EQ(1, result->Length());
 
16423
  CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
 
16424
}
 
16425
 
 
16426
 
 
16427
TEST(DefinePropertyPostDetach) {
 
16428
  v8::HandleScope scope;
 
16429
  LocalContext context;
 
16430
  v8::Handle<v8::Object> proxy = context->Global();
 
16431
  v8::Handle<v8::Function> define_property =
 
16432
      CompileRun("(function() {"
 
16433
                 "  Object.defineProperty("
 
16434
                 "    this,"
 
16435
                 "    1,"
 
16436
                 "    { configurable: true, enumerable: true, value: 3 });"
 
16437
                 "})").As<Function>();
 
16438
  context->DetachGlobal();
 
16439
  define_property->Call(proxy, 0, NULL);
 
16440
}
 
16441
 
 
16442
 
 
16443
static void InstallContextId(v8::Handle<Context> context, int id) {
 
16444
  Context::Scope scope(context);
 
16445
  CompileRun("Object.prototype").As<Object>()->
 
16446
      Set(v8_str("context_id"), v8::Integer::New(id));
 
16447
}
 
16448
 
 
16449
 
 
16450
static void CheckContextId(v8::Handle<Object> object, int expected) {
 
16451
  CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
 
16452
}
 
16453
 
 
16454
 
 
16455
THREADED_TEST(CreationContext) {
 
16456
  HandleScope handle_scope;
 
16457
  Persistent<Context> context1 = Context::New();
 
16458
  InstallContextId(context1, 1);
 
16459
  Persistent<Context> context2 = Context::New();
 
16460
  InstallContextId(context2, 2);
 
16461
  Persistent<Context> context3 = Context::New();
 
16462
  InstallContextId(context3, 3);
 
16463
 
 
16464
  Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
 
16465
 
 
16466
  Local<Object> object1;
 
16467
  Local<Function> func1;
 
16468
  {
 
16469
    Context::Scope scope(context1);
 
16470
    object1 = Object::New();
 
16471
    func1 = tmpl->GetFunction();
 
16472
  }
 
16473
 
 
16474
  Local<Object> object2;
 
16475
  Local<Function> func2;
 
16476
  {
 
16477
    Context::Scope scope(context2);
 
16478
    object2 = Object::New();
 
16479
    func2 = tmpl->GetFunction();
 
16480
  }
 
16481
 
 
16482
  Local<Object> instance1;
 
16483
  Local<Object> instance2;
 
16484
 
 
16485
  {
 
16486
    Context::Scope scope(context3);
 
16487
    instance1 = func1->NewInstance();
 
16488
    instance2 = func2->NewInstance();
 
16489
  }
 
16490
 
 
16491
  CHECK(object1->CreationContext() == context1);
 
16492
  CheckContextId(object1, 1);
 
16493
  CHECK(func1->CreationContext() == context1);
 
16494
  CheckContextId(func1, 1);
 
16495
  CHECK(instance1->CreationContext() == context1);
 
16496
  CheckContextId(instance1, 1);
 
16497
  CHECK(object2->CreationContext() == context2);
 
16498
  CheckContextId(object2, 2);
 
16499
  CHECK(func2->CreationContext() == context2);
 
16500
  CheckContextId(func2, 2);
 
16501
  CHECK(instance2->CreationContext() == context2);
 
16502
  CheckContextId(instance2, 2);
 
16503
 
 
16504
  {
 
16505
    Context::Scope scope(context1);
 
16506
    CHECK(object1->CreationContext() == context1);
 
16507
    CheckContextId(object1, 1);
 
16508
    CHECK(func1->CreationContext() == context1);
 
16509
    CheckContextId(func1, 1);
 
16510
    CHECK(instance1->CreationContext() == context1);
 
16511
    CheckContextId(instance1, 1);
 
16512
    CHECK(object2->CreationContext() == context2);
 
16513
    CheckContextId(object2, 2);
 
16514
    CHECK(func2->CreationContext() == context2);
 
16515
    CheckContextId(func2, 2);
 
16516
    CHECK(instance2->CreationContext() == context2);
 
16517
    CheckContextId(instance2, 2);
 
16518
  }
 
16519
 
 
16520
  {
 
16521
    Context::Scope scope(context2);
 
16522
    CHECK(object1->CreationContext() == context1);
 
16523
    CheckContextId(object1, 1);
 
16524
    CHECK(func1->CreationContext() == context1);
 
16525
    CheckContextId(func1, 1);
 
16526
    CHECK(instance1->CreationContext() == context1);
 
16527
    CheckContextId(instance1, 1);
 
16528
    CHECK(object2->CreationContext() == context2);
 
16529
    CheckContextId(object2, 2);
 
16530
    CHECK(func2->CreationContext() == context2);
 
16531
    CheckContextId(func2, 2);
 
16532
    CHECK(instance2->CreationContext() == context2);
 
16533
    CheckContextId(instance2, 2);
 
16534
  }
 
16535
 
 
16536
  context1.Dispose();
 
16537
  context2.Dispose();
 
16538
  context3.Dispose();
 
16539
}
 
16540
 
 
16541
 
 
16542
THREADED_TEST(CreationContextOfJsFunction) {
 
16543
  HandleScope handle_scope;
 
16544
  Persistent<Context> context = Context::New();
 
16545
  InstallContextId(context, 1);
 
16546
 
 
16547
  Local<Object> function;
 
16548
  {
 
16549
    Context::Scope scope(context);
 
16550
    function = CompileRun("function foo() {}; foo").As<Object>();
 
16551
  }
 
16552
 
 
16553
  CHECK(function->CreationContext() == context);
 
16554
  CheckContextId(function, 1);
 
16555
 
 
16556
  context.Dispose();
 
16557
}
 
16558
 
 
16559
 
 
16560
Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
 
16561
                                                  const AccessorInfo& info) {
 
16562
  if (index == 42) return v8_str("yes");
 
16563
  return Handle<v8::Integer>();
 
16564
}
 
16565
 
 
16566
 
 
16567
Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
 
16568
                                                const AccessorInfo& info) {
 
16569
  if (property->Equals(v8_str("foo"))) return v8_str("yes");
 
16570
  return Handle<Value>();
 
16571
}
 
16572
 
 
16573
 
 
16574
Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
 
16575
    uint32_t index, const AccessorInfo& info) {
 
16576
  if (index == 42) return v8_num(1).As<v8::Integer>();
 
16577
  return Handle<v8::Integer>();
 
16578
}
 
16579
 
 
16580
 
 
16581
Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
 
16582
    Local<String> property, const AccessorInfo& info) {
 
16583
  if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
 
16584
  return Handle<v8::Integer>();
 
16585
}
 
16586
 
 
16587
 
 
16588
Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
 
16589
    Local<String> property, const AccessorInfo& info) {
 
16590
  if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
 
16591
  return Handle<v8::Integer>();
 
16592
}
 
16593
 
 
16594
 
 
16595
Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
 
16596
                                           const AccessorInfo& info) {
 
16597
  return v8_str("yes");
 
16598
}
 
16599
 
 
16600
 
 
16601
TEST(HasOwnProperty) {
 
16602
  v8::HandleScope scope;
 
16603
  LocalContext env;
 
16604
  { // Check normal properties and defined getters.
 
16605
    Handle<Value> value = CompileRun(
 
16606
        "function Foo() {"
 
16607
        "    this.foo = 11;"
 
16608
        "    this.__defineGetter__('baz', function() { return 1; });"
 
16609
        "};"
 
16610
        "function Bar() { "
 
16611
        "    this.bar = 13;"
 
16612
        "    this.__defineGetter__('bla', function() { return 2; });"
 
16613
        "};"
 
16614
        "Bar.prototype = new Foo();"
 
16615
        "new Bar();");
 
16616
    CHECK(value->IsObject());
 
16617
    Handle<Object> object = value->ToObject();
 
16618
    CHECK(object->Has(v8_str("foo")));
 
16619
    CHECK(!object->HasOwnProperty(v8_str("foo")));
 
16620
    CHECK(object->HasOwnProperty(v8_str("bar")));
 
16621
    CHECK(object->Has(v8_str("baz")));
 
16622
    CHECK(!object->HasOwnProperty(v8_str("baz")));
 
16623
    CHECK(object->HasOwnProperty(v8_str("bla")));
 
16624
  }
 
16625
  { // Check named getter interceptors.
 
16626
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16627
    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
 
16628
    Handle<Object> instance = templ->NewInstance();
 
16629
    CHECK(!instance->HasOwnProperty(v8_str("42")));
 
16630
    CHECK(instance->HasOwnProperty(v8_str("foo")));
 
16631
    CHECK(!instance->HasOwnProperty(v8_str("bar")));
 
16632
  }
 
16633
  { // Check indexed getter interceptors.
 
16634
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16635
    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
 
16636
    Handle<Object> instance = templ->NewInstance();
 
16637
    CHECK(instance->HasOwnProperty(v8_str("42")));
 
16638
    CHECK(!instance->HasOwnProperty(v8_str("43")));
 
16639
    CHECK(!instance->HasOwnProperty(v8_str("foo")));
 
16640
  }
 
16641
  { // Check named query interceptors.
 
16642
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16643
    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
 
16644
    Handle<Object> instance = templ->NewInstance();
 
16645
    CHECK(instance->HasOwnProperty(v8_str("foo")));
 
16646
    CHECK(!instance->HasOwnProperty(v8_str("bar")));
 
16647
  }
 
16648
  { // Check indexed query interceptors.
 
16649
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16650
    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
 
16651
    Handle<Object> instance = templ->NewInstance();
 
16652
    CHECK(instance->HasOwnProperty(v8_str("42")));
 
16653
    CHECK(!instance->HasOwnProperty(v8_str("41")));
 
16654
  }
 
16655
  { // Check callbacks.
 
16656
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16657
    templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
 
16658
    Handle<Object> instance = templ->NewInstance();
 
16659
    CHECK(instance->HasOwnProperty(v8_str("foo")));
 
16660
    CHECK(!instance->HasOwnProperty(v8_str("bar")));
 
16661
  }
 
16662
  { // Check that query wins on disagreement.
 
16663
    Handle<ObjectTemplate> templ = ObjectTemplate::New();
 
16664
    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
 
16665
                                   0,
 
16666
                                   HasOwnPropertyNamedPropertyQuery2);
 
16667
    Handle<Object> instance = templ->NewInstance();
 
16668
    CHECK(!instance->HasOwnProperty(v8_str("foo")));
 
16669
    CHECK(instance->HasOwnProperty(v8_str("bar")));
 
16670
  }
 
16671
}
 
16672
 
 
16673
 
 
16674
void CheckCodeGenerationAllowed() {
 
16675
  Handle<Value> result = CompileRun("eval('42')");
 
16676
  CHECK_EQ(42, result->Int32Value());
 
16677
  result = CompileRun("(function(e) { return e('42'); })(eval)");
 
16678
  CHECK_EQ(42, result->Int32Value());
 
16679
  result = CompileRun("var f = new Function('return 42'); f()");
 
16680
  CHECK_EQ(42, result->Int32Value());
 
16681
}
 
16682
 
 
16683
 
 
16684
void CheckCodeGenerationDisallowed() {
 
16685
  TryCatch try_catch;
 
16686
 
 
16687
  Handle<Value> result = CompileRun("eval('42')");
 
16688
  CHECK(result.IsEmpty());
 
16689
  CHECK(try_catch.HasCaught());
 
16690
  try_catch.Reset();
 
16691
 
 
16692
  result = CompileRun("(function(e) { return e('42'); })(eval)");
 
16693
  CHECK(result.IsEmpty());
 
16694
  CHECK(try_catch.HasCaught());
 
16695
  try_catch.Reset();
 
16696
 
 
16697
  result = CompileRun("var f = new Function('return 42'); f()");
 
16698
  CHECK(result.IsEmpty());
 
16699
  CHECK(try_catch.HasCaught());
 
16700
}
 
16701
 
 
16702
 
 
16703
bool CodeGenerationAllowed(Local<Context> context) {
 
16704
  ApiTestFuzzer::Fuzz();
 
16705
  return true;
 
16706
}
 
16707
 
 
16708
 
 
16709
bool CodeGenerationDisallowed(Local<Context> context) {
 
16710
  ApiTestFuzzer::Fuzz();
 
16711
  return false;
 
16712
}
 
16713
 
 
16714
 
 
16715
THREADED_TEST(AllowCodeGenFromStrings) {
 
16716
  v8::HandleScope scope;
 
16717
  LocalContext context;
 
16718
 
 
16719
  // eval and the Function constructor allowed by default.
 
16720
  CHECK(context->IsCodeGenerationFromStringsAllowed());
 
16721
  CheckCodeGenerationAllowed();
 
16722
 
 
16723
  // Disallow eval and the Function constructor.
 
16724
  context->AllowCodeGenerationFromStrings(false);
 
16725
  CHECK(!context->IsCodeGenerationFromStringsAllowed());
 
16726
  CheckCodeGenerationDisallowed();
 
16727
 
 
16728
  // Allow again.
 
16729
  context->AllowCodeGenerationFromStrings(true);
 
16730
  CheckCodeGenerationAllowed();
 
16731
 
 
16732
  // Disallow but setting a global callback that will allow the calls.
 
16733
  context->AllowCodeGenerationFromStrings(false);
 
16734
  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
 
16735
  CHECK(!context->IsCodeGenerationFromStringsAllowed());
 
16736
  CheckCodeGenerationAllowed();
 
16737
 
 
16738
  // Set a callback that disallows the code generation.
 
16739
  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
 
16740
  CHECK(!context->IsCodeGenerationFromStringsAllowed());
 
16741
  CheckCodeGenerationDisallowed();
 
16742
}
 
16743
 
 
16744
 
 
16745
TEST(SetErrorMessageForCodeGenFromStrings) {
 
16746
  v8::HandleScope scope;
 
16747
  LocalContext context;
 
16748
  TryCatch try_catch;
 
16749
 
 
16750
  Handle<String> message = v8_str("Message") ;
 
16751
  Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
 
16752
  V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
 
16753
  context->AllowCodeGenerationFromStrings(false);
 
16754
  context->SetErrorMessageForCodeGenerationFromStrings(message);
 
16755
  Handle<Value> result = CompileRun("eval('42')");
 
16756
  CHECK(result.IsEmpty());
 
16757
  CHECK(try_catch.HasCaught());
 
16758
  Handle<String> actual_message = try_catch.Message()->Get();
 
16759
  CHECK(expected_message->Equals(actual_message));
 
16760
}
 
16761
 
 
16762
 
 
16763
static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
 
16764
  return v8::Undefined();
 
16765
}
 
16766
 
 
16767
 
 
16768
THREADED_TEST(CallAPIFunctionOnNonObject) {
 
16769
  v8::HandleScope scope;
 
16770
  LocalContext context;
 
16771
  Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
 
16772
  Handle<Function> function = templ->GetFunction();
 
16773
  context->Global()->Set(v8_str("f"), function);
 
16774
  TryCatch try_catch;
 
16775
  CompileRun("f.call(2)");
 
16776
}
 
16777
 
 
16778
 
 
16779
// Regression test for issue 1470.
 
16780
THREADED_TEST(ReadOnlyIndexedProperties) {
 
16781
  v8::HandleScope scope;
 
16782
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
16783
 
 
16784
  LocalContext context;
 
16785
  Local<v8::Object> obj = templ->NewInstance();
 
16786
  context->Global()->Set(v8_str("obj"), obj);
 
16787
  obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
 
16788
  obj->Set(v8_str("1"), v8_str("foobar"));
 
16789
  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
 
16790
  obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
 
16791
  obj->Set(v8_num(2), v8_str("foobar"));
 
16792
  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
 
16793
 
 
16794
  // Test non-smi case.
 
16795
  obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
 
16796
  obj->Set(v8_str("2000000000"), v8_str("foobar"));
 
16797
  CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
 
16798
}
 
16799
 
 
16800
 
 
16801
THREADED_TEST(Regress1516) {
 
16802
  v8::HandleScope scope;
 
16803
 
 
16804
  LocalContext context;
 
16805
  { v8::HandleScope temp_scope;
 
16806
    CompileRun("({'a': 0})");
 
16807
  }
 
16808
 
 
16809
  int elements;
 
16810
  { i::MapCache* map_cache =
 
16811
        i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
 
16812
    elements = map_cache->NumberOfElements();
 
16813
    CHECK_LE(1, elements);
 
16814
  }
 
16815
 
 
16816
  i::Isolate::Current()->heap()->CollectAllGarbage(
 
16817
      i::Heap::kAbortIncrementalMarkingMask);
 
16818
  { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
 
16819
    if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
 
16820
      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
 
16821
      CHECK_GT(elements, map_cache->NumberOfElements());
 
16822
    }
 
16823
  }
 
16824
}
 
16825
 
 
16826
 
 
16827
static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
 
16828
                                                Local<Value> name,
 
16829
                                                v8::AccessType type,
 
16830
                                                Local<Value> data) {
 
16831
  // Only block read access to __proto__.
 
16832
  if (type == v8::ACCESS_GET &&
 
16833
      name->IsString() &&
 
16834
      name->ToString()->Length() == 9 &&
 
16835
      name->ToString()->Utf8Length() == 9) {
 
16836
    char buffer[10];
 
16837
    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
 
16838
    return strncmp(buffer, "__proto__", 9) != 0;
 
16839
  }
 
16840
 
 
16841
  return true;
 
16842
}
 
16843
 
 
16844
 
 
16845
THREADED_TEST(Regress93759) {
 
16846
  HandleScope scope;
 
16847
 
 
16848
  // Template for object with security check.
 
16849
  Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
 
16850
  // We don't do indexing, so any callback can be used for that.
 
16851
  no_proto_template->SetAccessCheckCallbacks(
 
16852
      BlockProtoNamedSecurityTestCallback,
 
16853
      IndexedSecurityTestCallback);
 
16854
 
 
16855
  // Templates for objects with hidden prototypes and possibly security check.
 
16856
  Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
 
16857
  hidden_proto_template->SetHiddenPrototype(true);
 
16858
 
 
16859
  Local<FunctionTemplate> protected_hidden_proto_template =
 
16860
      v8::FunctionTemplate::New();
 
16861
  protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
 
16862
      BlockProtoNamedSecurityTestCallback,
 
16863
      IndexedSecurityTestCallback);
 
16864
  protected_hidden_proto_template->SetHiddenPrototype(true);
 
16865
 
 
16866
  // Context for "foreign" objects used in test.
 
16867
  Persistent<Context> context = v8::Context::New();
 
16868
  context->Enter();
 
16869
 
 
16870
  // Plain object, no security check.
 
16871
  Local<Object> simple_object = Object::New();
 
16872
 
 
16873
  // Object with explicit security check.
 
16874
  Local<Object> protected_object =
 
16875
      no_proto_template->NewInstance();
 
16876
 
 
16877
  // JSGlobalProxy object, always have security check.
 
16878
  Local<Object> proxy_object =
 
16879
      context->Global();
 
16880
 
 
16881
  // Global object, the  prototype of proxy_object. No security checks.
 
16882
  Local<Object> global_object =
 
16883
      proxy_object->GetPrototype()->ToObject();
 
16884
 
 
16885
  // Hidden prototype without security check.
 
16886
  Local<Object> hidden_prototype =
 
16887
      hidden_proto_template->GetFunction()->NewInstance();
 
16888
  Local<Object> object_with_hidden =
 
16889
    Object::New();
 
16890
  object_with_hidden->SetPrototype(hidden_prototype);
 
16891
 
 
16892
  // Hidden prototype with security check on the hidden prototype.
 
16893
  Local<Object> protected_hidden_prototype =
 
16894
      protected_hidden_proto_template->GetFunction()->NewInstance();
 
16895
  Local<Object> object_with_protected_hidden =
 
16896
    Object::New();
 
16897
  object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
 
16898
 
 
16899
  context->Exit();
 
16900
 
 
16901
  // Template for object for second context. Values to test are put on it as
 
16902
  // properties.
 
16903
  Local<ObjectTemplate> global_template = ObjectTemplate::New();
 
16904
  global_template->Set(v8_str("simple"), simple_object);
 
16905
  global_template->Set(v8_str("protected"), protected_object);
 
16906
  global_template->Set(v8_str("global"), global_object);
 
16907
  global_template->Set(v8_str("proxy"), proxy_object);
 
16908
  global_template->Set(v8_str("hidden"), object_with_hidden);
 
16909
  global_template->Set(v8_str("phidden"), object_with_protected_hidden);
 
16910
 
 
16911
  LocalContext context2(NULL, global_template);
 
16912
 
 
16913
  Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
 
16914
  CHECK(result1->Equals(simple_object->GetPrototype()));
 
16915
 
 
16916
  Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
 
16917
  CHECK(result2->Equals(Undefined()));
 
16918
 
 
16919
  Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
 
16920
  CHECK(result3->Equals(global_object->GetPrototype()));
 
16921
 
 
16922
  Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
 
16923
  CHECK(result4->Equals(Undefined()));
 
16924
 
 
16925
  Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
 
16926
  CHECK(result5->Equals(
 
16927
      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
 
16928
 
 
16929
  Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
 
16930
  CHECK(result6->Equals(Undefined()));
 
16931
 
 
16932
  context.Dispose();
 
16933
}
 
16934
 
 
16935
 
 
16936
THREADED_TEST(Regress125988) {
 
16937
  v8::HandleScope scope;
 
16938
  Handle<FunctionTemplate> intercept = FunctionTemplate::New();
 
16939
  AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
16940
  LocalContext env;
 
16941
  env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
 
16942
  CompileRun("var a = new Object();"
 
16943
             "var b = new Intercept();"
 
16944
             "var c = new Object();"
 
16945
             "c.__proto__ = b;"
 
16946
             "b.__proto__ = a;"
 
16947
             "a.x = 23;"
 
16948
             "for (var i = 0; i < 3; i++) c.x;");
 
16949
  ExpectBoolean("c.hasOwnProperty('x')", false);
 
16950
  ExpectInt32("c.x", 23);
 
16951
  CompileRun("a.y = 42;"
 
16952
             "for (var i = 0; i < 3; i++) c.x;");
 
16953
  ExpectBoolean("c.hasOwnProperty('x')", false);
 
16954
  ExpectInt32("c.x", 23);
 
16955
  ExpectBoolean("c.hasOwnProperty('y')", false);
 
16956
  ExpectInt32("c.y", 42);
 
16957
}
 
16958
 
 
16959
 
 
16960
static void TestReceiver(Local<Value> expected_result,
 
16961
                         Local<Value> expected_receiver,
 
16962
                         const char* code) {
 
16963
  Local<Value> result = CompileRun(code);
 
16964
  CHECK(result->IsObject());
 
16965
  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
 
16966
  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
 
16967
}
 
16968
 
 
16969
 
 
16970
THREADED_TEST(ForeignFunctionReceiver) {
 
16971
  HandleScope scope;
 
16972
 
 
16973
  // Create two contexts with different "id" properties ('i' and 'o').
 
16974
  // Call a function both from its own context and from a the foreign
 
16975
  // context, and see what "this" is bound to (returning both "this"
 
16976
  // and "this.id" for comparison).
 
16977
 
 
16978
  Persistent<Context> foreign_context = v8::Context::New();
 
16979
  foreign_context->Enter();
 
16980
  Local<Value> foreign_function =
 
16981
    CompileRun("function func() { return { 0: this.id, "
 
16982
               "                           1: this, "
 
16983
               "                           toString: function() { "
 
16984
               "                               return this[0];"
 
16985
               "                           }"
 
16986
               "                         };"
 
16987
               "}"
 
16988
               "var id = 'i';"
 
16989
               "func;");
 
16990
  CHECK(foreign_function->IsFunction());
 
16991
  foreign_context->Exit();
 
16992
 
 
16993
  LocalContext context;
 
16994
 
 
16995
  Local<String> password = v8_str("Password");
 
16996
  // Don't get hit by security checks when accessing foreign_context's
 
16997
  // global receiver (aka. global proxy).
 
16998
  context->SetSecurityToken(password);
 
16999
  foreign_context->SetSecurityToken(password);
 
17000
 
 
17001
  Local<String> i = v8_str("i");
 
17002
  Local<String> o = v8_str("o");
 
17003
  Local<String> id = v8_str("id");
 
17004
 
 
17005
  CompileRun("function ownfunc() { return { 0: this.id, "
 
17006
             "                              1: this, "
 
17007
             "                              toString: function() { "
 
17008
             "                                  return this[0];"
 
17009
             "                              }"
 
17010
             "                             };"
 
17011
             "}"
 
17012
             "var id = 'o';"
 
17013
             "ownfunc");
 
17014
  context->Global()->Set(v8_str("func"), foreign_function);
 
17015
 
 
17016
  // Sanity check the contexts.
 
17017
  CHECK(i->Equals(foreign_context->Global()->Get(id)));
 
17018
  CHECK(o->Equals(context->Global()->Get(id)));
 
17019
 
 
17020
  // Checking local function's receiver.
 
17021
  // Calling function using its call/apply methods.
 
17022
  TestReceiver(o, context->Global(), "ownfunc.call()");
 
17023
  TestReceiver(o, context->Global(), "ownfunc.apply()");
 
17024
  // Making calls through built-in functions.
 
17025
  TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
 
17026
  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
 
17027
  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
 
17028
  CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
 
17029
  // Calling with environment record as base.
 
17030
  TestReceiver(o, context->Global(), "ownfunc()");
 
17031
  // Calling with no base.
 
17032
  TestReceiver(o, context->Global(), "(1,ownfunc)()");
 
17033
 
 
17034
  // Checking foreign function return value.
 
17035
  // Calling function using its call/apply methods.
 
17036
  TestReceiver(i, foreign_context->Global(), "func.call()");
 
17037
  TestReceiver(i, foreign_context->Global(), "func.apply()");
 
17038
  // Calling function using another context's call/apply methods.
 
17039
  TestReceiver(i, foreign_context->Global(),
 
17040
               "Function.prototype.call.call(func)");
 
17041
  TestReceiver(i, foreign_context->Global(),
 
17042
               "Function.prototype.call.apply(func)");
 
17043
  TestReceiver(i, foreign_context->Global(),
 
17044
               "Function.prototype.apply.call(func)");
 
17045
  TestReceiver(i, foreign_context->Global(),
 
17046
               "Function.prototype.apply.apply(func)");
 
17047
  // Making calls through built-in functions.
 
17048
  TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
 
17049
  // ToString(func()) is func()[0], i.e., the returned this.id.
 
17050
  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
 
17051
  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
 
17052
  CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
 
17053
 
 
17054
  // TODO(1547): Make the following also return "i".
 
17055
  // Calling with environment record as base.
 
17056
  TestReceiver(o, context->Global(), "func()");
 
17057
  // Calling with no base.
 
17058
  TestReceiver(o, context->Global(), "(1,func)()");
 
17059
 
 
17060
  foreign_context.Dispose();
 
17061
}
 
17062
 
 
17063
 
 
17064
uint8_t callback_fired = 0;
 
17065
 
 
17066
 
 
17067
void CallCompletedCallback1() {
 
17068
  i::OS::Print("Firing callback 1.\n");
 
17069
  callback_fired ^= 1;  // Toggle first bit.
 
17070
}
 
17071
 
 
17072
 
 
17073
void CallCompletedCallback2() {
 
17074
  i::OS::Print("Firing callback 2.\n");
 
17075
  callback_fired ^= 2;  // Toggle second bit.
 
17076
}
 
17077
 
 
17078
 
 
17079
Handle<Value> RecursiveCall(const Arguments& args) {
 
17080
  int32_t level = args[0]->Int32Value();
 
17081
  if (level < 3) {
 
17082
    level++;
 
17083
    i::OS::Print("Entering recursion level %d.\n", level);
 
17084
    char script[64];
 
17085
    i::Vector<char> script_vector(script, sizeof(script));
 
17086
    i::OS::SNPrintF(script_vector, "recursion(%d)", level);
 
17087
    CompileRun(script_vector.start());
 
17088
    i::OS::Print("Leaving recursion level %d.\n", level);
 
17089
    CHECK_EQ(0, callback_fired);
 
17090
  } else {
 
17091
    i::OS::Print("Recursion ends.\n");
 
17092
    CHECK_EQ(0, callback_fired);
 
17093
  }
 
17094
  return Undefined();
 
17095
}
 
17096
 
 
17097
 
 
17098
TEST(CallCompletedCallback) {
 
17099
  v8::HandleScope scope;
 
17100
  LocalContext env;
 
17101
  v8::Handle<v8::FunctionTemplate> recursive_runtime =
 
17102
      v8::FunctionTemplate::New(RecursiveCall);
 
17103
  env->Global()->Set(v8_str("recursion"),
 
17104
                     recursive_runtime->GetFunction());
 
17105
  // Adding the same callback a second time has no effect.
 
17106
  v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
 
17107
  v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
 
17108
  v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
 
17109
  i::OS::Print("--- Script (1) ---\n");
 
17110
  Local<Script> script =
 
17111
      v8::Script::Compile(v8::String::New("recursion(0)"));
 
17112
  script->Run();
 
17113
  CHECK_EQ(3, callback_fired);
 
17114
 
 
17115
  i::OS::Print("\n--- Script (2) ---\n");
 
17116
  callback_fired = 0;
 
17117
  v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
 
17118
  script->Run();
 
17119
  CHECK_EQ(2, callback_fired);
 
17120
 
 
17121
  i::OS::Print("\n--- Function ---\n");
 
17122
  callback_fired = 0;
 
17123
  Local<Function> recursive_function =
 
17124
      Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
 
17125
  v8::Handle<Value> args[] = { v8_num(0) };
 
17126
  recursive_function->Call(env->Global(), 1, args);
 
17127
  CHECK_EQ(2, callback_fired);
 
17128
}
 
17129
 
 
17130
 
 
17131
void CallCompletedCallbackNoException() {
 
17132
  v8::HandleScope scope;
 
17133
  CompileRun("1+1;");
 
17134
}
 
17135
 
 
17136
 
 
17137
void CallCompletedCallbackException() {
 
17138
  v8::HandleScope scope;
 
17139
  CompileRun("throw 'second exception';");
 
17140
}
 
17141
 
 
17142
 
 
17143
TEST(CallCompletedCallbackOneException) {
 
17144
  v8::HandleScope scope;
 
17145
  LocalContext env;
 
17146
  v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
 
17147
  CompileRun("throw 'exception';");
 
17148
}
 
17149
 
 
17150
 
 
17151
TEST(CallCompletedCallbackTwoExceptions) {
 
17152
  v8::HandleScope scope;
 
17153
  LocalContext env;
 
17154
  v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
 
17155
  CompileRun("throw 'first exception';");
 
17156
}
 
17157
 
 
17158
 
 
17159
static int probes_counter = 0;
 
17160
static int misses_counter = 0;
 
17161
static int updates_counter = 0;
 
17162
 
 
17163
 
 
17164
static int* LookupCounter(const char* name) {
 
17165
  if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
 
17166
    return &probes_counter;
 
17167
  } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
 
17168
    return &misses_counter;
 
17169
  } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
 
17170
    return &updates_counter;
 
17171
  }
 
17172
  return NULL;
 
17173
}
 
17174
 
 
17175
 
 
17176
static const char* kMegamorphicTestProgram =
 
17177
    "function ClassA() { };"
 
17178
    "function ClassB() { };"
 
17179
    "ClassA.prototype.foo = function() { };"
 
17180
    "ClassB.prototype.foo = function() { };"
 
17181
    "function fooify(obj) { obj.foo(); };"
 
17182
    "var a = new ClassA();"
 
17183
    "var b = new ClassB();"
 
17184
    "for (var i = 0; i < 10000; i++) {"
 
17185
    "  fooify(a);"
 
17186
    "  fooify(b);"
 
17187
    "}";
 
17188
 
 
17189
 
 
17190
static void StubCacheHelper(bool primary) {
 
17191
  V8::SetCounterFunction(LookupCounter);
 
17192
  USE(kMegamorphicTestProgram);
 
17193
#ifdef DEBUG
 
17194
  i::FLAG_native_code_counters = true;
 
17195
  if (primary) {
 
17196
    i::FLAG_test_primary_stub_cache = true;
 
17197
  } else {
 
17198
    i::FLAG_test_secondary_stub_cache = true;
 
17199
  }
 
17200
  i::FLAG_crankshaft = false;
 
17201
  v8::HandleScope scope;
 
17202
  LocalContext env;
 
17203
  int initial_probes = probes_counter;
 
17204
  int initial_misses = misses_counter;
 
17205
  int initial_updates = updates_counter;
 
17206
  CompileRun(kMegamorphicTestProgram);
 
17207
  int probes = probes_counter - initial_probes;
 
17208
  int misses = misses_counter - initial_misses;
 
17209
  int updates = updates_counter - initial_updates;
 
17210
  CHECK_LT(updates, 10);
 
17211
  CHECK_LT(misses, 10);
 
17212
  CHECK_GE(probes, 10000);
 
17213
#endif
 
17214
}
 
17215
 
 
17216
 
 
17217
TEST(SecondaryStubCache) {
 
17218
  StubCacheHelper(true);
 
17219
}
 
17220
 
 
17221
 
 
17222
TEST(PrimaryStubCache) {
 
17223
  StubCacheHelper(false);
 
17224
}
 
17225
 
 
17226
 
 
17227
static int fatal_error_callback_counter = 0;
 
17228
static void CountingErrorCallback(const char* location, const char* message) {
 
17229
  printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
 
17230
  fatal_error_callback_counter++;
 
17231
}
 
17232
 
 
17233
 
 
17234
TEST(StaticGetters) {
 
17235
  v8::HandleScope scope;
 
17236
  LocalContext context;
 
17237
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
17238
  i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
 
17239
  CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
 
17240
  CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
 
17241
  i::Handle<i::Object> null_value = FACTORY->null_value();
 
17242
  CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
 
17243
  CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
 
17244
  i::Handle<i::Object> true_value = FACTORY->true_value();
 
17245
  CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
 
17246
  CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
 
17247
  i::Handle<i::Object> false_value = FACTORY->false_value();
 
17248
  CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
 
17249
  CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
 
17250
 
 
17251
  // Test after-death behavior.
 
17252
  CHECK(i::Internals::IsInitialized(isolate));
 
17253
  CHECK_EQ(0, fatal_error_callback_counter);
 
17254
  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
 
17255
  v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
 
17256
  i::Isolate::Current()->TearDown();
 
17257
  CHECK(!i::Internals::IsInitialized(isolate));
 
17258
  CHECK_EQ(1, fatal_error_callback_counter);
 
17259
  CHECK(v8::Undefined().IsEmpty());
 
17260
  CHECK_EQ(2, fatal_error_callback_counter);
 
17261
  CHECK(v8::Undefined(isolate).IsEmpty());
 
17262
  CHECK_EQ(3, fatal_error_callback_counter);
 
17263
  CHECK(v8::Null().IsEmpty());
 
17264
  CHECK_EQ(4, fatal_error_callback_counter);
 
17265
  CHECK(v8::Null(isolate).IsEmpty());
 
17266
  CHECK_EQ(5, fatal_error_callback_counter);
 
17267
  CHECK(v8::True().IsEmpty());
 
17268
  CHECK_EQ(6, fatal_error_callback_counter);
 
17269
  CHECK(v8::True(isolate).IsEmpty());
 
17270
  CHECK_EQ(7, fatal_error_callback_counter);
 
17271
  CHECK(v8::False().IsEmpty());
 
17272
  CHECK_EQ(8, fatal_error_callback_counter);
 
17273
  CHECK(v8::False(isolate).IsEmpty());
 
17274
  CHECK_EQ(9, fatal_error_callback_counter);
 
17275
}
 
17276
 
 
17277
 
 
17278
TEST(IsolateEmbedderData) {
 
17279
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
17280
  CHECK_EQ(NULL, isolate->GetData());
 
17281
  CHECK_EQ(NULL, ISOLATE->GetData());
 
17282
  static void* data1 = reinterpret_cast<void*>(0xacce55ed);
 
17283
  isolate->SetData(data1);
 
17284
  CHECK_EQ(data1, isolate->GetData());
 
17285
  CHECK_EQ(data1, ISOLATE->GetData());
 
17286
  static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
 
17287
  ISOLATE->SetData(data2);
 
17288
  CHECK_EQ(data2, isolate->GetData());
 
17289
  CHECK_EQ(data2, ISOLATE->GetData());
 
17290
  ISOLATE->TearDown();
 
17291
  CHECK_EQ(data2, isolate->GetData());
 
17292
  CHECK_EQ(data2, ISOLATE->GetData());
 
17293
}
 
17294
 
 
17295
 
 
17296
TEST(StringEmpty) {
 
17297
  v8::HandleScope scope;
 
17298
  LocalContext context;
 
17299
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
 
17300
  i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
 
17301
  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
 
17302
  CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
 
17303
 
 
17304
  // Test after-death behavior.
 
17305
  CHECK(i::Internals::IsInitialized(isolate));
 
17306
  CHECK_EQ(0, fatal_error_callback_counter);
 
17307
  v8::V8::SetFatalErrorHandler(CountingErrorCallback);
 
17308
  v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
 
17309
  i::Isolate::Current()->TearDown();
 
17310
  CHECK(!i::Internals::IsInitialized(isolate));
 
17311
  CHECK_EQ(1, fatal_error_callback_counter);
 
17312
  CHECK(v8::String::Empty().IsEmpty());
 
17313
  CHECK_EQ(2, fatal_error_callback_counter);
 
17314
  CHECK(v8::String::Empty(isolate).IsEmpty());
 
17315
  CHECK_EQ(3, fatal_error_callback_counter);
 
17316
}
 
17317
 
 
17318
 
 
17319
static int instance_checked_getter_count = 0;
 
17320
static Handle<Value> InstanceCheckedGetter(Local<String> name,
 
17321
                                           const AccessorInfo& info) {
 
17322
  CHECK_EQ(name, v8_str("foo"));
 
17323
  instance_checked_getter_count++;
 
17324
  return v8_num(11);
 
17325
}
 
17326
 
 
17327
 
 
17328
static int instance_checked_setter_count = 0;
 
17329
static void InstanceCheckedSetter(Local<String> name,
 
17330
                      Local<Value> value,
 
17331
                      const AccessorInfo& info) {
 
17332
  CHECK_EQ(name, v8_str("foo"));
 
17333
  CHECK_EQ(value, v8_num(23));
 
17334
  instance_checked_setter_count++;
 
17335
}
 
17336
 
 
17337
 
 
17338
static void CheckInstanceCheckedResult(int getters,
 
17339
                                       int setters,
 
17340
                                       bool expects_callbacks,
 
17341
                                       TryCatch* try_catch) {
 
17342
  if (expects_callbacks) {
 
17343
    CHECK(!try_catch->HasCaught());
 
17344
    CHECK_EQ(getters, instance_checked_getter_count);
 
17345
    CHECK_EQ(setters, instance_checked_setter_count);
 
17346
  } else {
 
17347
    CHECK(try_catch->HasCaught());
 
17348
    CHECK_EQ(0, instance_checked_getter_count);
 
17349
    CHECK_EQ(0, instance_checked_setter_count);
 
17350
  }
 
17351
  try_catch->Reset();
 
17352
}
 
17353
 
 
17354
 
 
17355
static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
 
17356
  instance_checked_getter_count = 0;
 
17357
  instance_checked_setter_count = 0;
 
17358
  TryCatch try_catch;
 
17359
 
 
17360
  // Test path through generic runtime code.
 
17361
  CompileRun("obj.foo");
 
17362
  CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
 
17363
  CompileRun("obj.foo = 23");
 
17364
  CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
 
17365
 
 
17366
  // Test path through generated LoadIC and StoredIC.
 
17367
  CompileRun("function test_get(o) { o.foo; }"
 
17368
             "test_get(obj);");
 
17369
  CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
 
17370
  CompileRun("test_get(obj);");
 
17371
  CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
 
17372
  CompileRun("test_get(obj);");
 
17373
  CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
 
17374
  CompileRun("function test_set(o) { o.foo = 23; }"
 
17375
             "test_set(obj);");
 
17376
  CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
 
17377
  CompileRun("test_set(obj);");
 
17378
  CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
 
17379
  CompileRun("test_set(obj);");
 
17380
  CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
 
17381
 
 
17382
  // Test path through optimized code.
 
17383
  CompileRun("%OptimizeFunctionOnNextCall(test_get);"
 
17384
             "test_get(obj);");
 
17385
  CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
 
17386
  CompileRun("%OptimizeFunctionOnNextCall(test_set);"
 
17387
             "test_set(obj);");
 
17388
  CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
 
17389
 
 
17390
  // Cleanup so that closures start out fresh in next check.
 
17391
  CompileRun("%DeoptimizeFunction(test_get);"
 
17392
             "%ClearFunctionTypeFeedback(test_get);"
 
17393
             "%DeoptimizeFunction(test_set);"
 
17394
             "%ClearFunctionTypeFeedback(test_set);");
 
17395
}
 
17396
 
 
17397
 
 
17398
THREADED_TEST(InstanceCheckOnInstanceAccessor) {
 
17399
  v8::internal::FLAG_allow_natives_syntax = true;
 
17400
  v8::HandleScope scope;
 
17401
  LocalContext context;
 
17402
 
 
17403
  Local<FunctionTemplate> templ = FunctionTemplate::New();
 
17404
  Local<ObjectTemplate> inst = templ->InstanceTemplate();
 
17405
  inst->SetAccessor(v8_str("foo"),
 
17406
                    InstanceCheckedGetter, InstanceCheckedSetter,
 
17407
                    Handle<Value>(),
 
17408
                    v8::DEFAULT,
 
17409
                    v8::None,
 
17410
                    v8::AccessorSignature::New(templ));
 
17411
  context->Global()->Set(v8_str("f"), templ->GetFunction());
 
17412
 
 
17413
  printf("Testing positive ...\n");
 
17414
  CompileRun("var obj = new f();");
 
17415
  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17416
  CheckInstanceCheckedAccessors(true);
 
17417
 
 
17418
  printf("Testing negative ...\n");
 
17419
  CompileRun("var obj = {};"
 
17420
             "obj.__proto__ = new f();");
 
17421
  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17422
  CheckInstanceCheckedAccessors(false);
 
17423
}
 
17424
 
 
17425
 
 
17426
THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
 
17427
  v8::internal::FLAG_allow_natives_syntax = true;
 
17428
  v8::HandleScope scope;
 
17429
  LocalContext context;
 
17430
 
 
17431
  Local<FunctionTemplate> templ = FunctionTemplate::New();
 
17432
  Local<ObjectTemplate> inst = templ->InstanceTemplate();
 
17433
  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
17434
  inst->SetAccessor(v8_str("foo"),
 
17435
                    InstanceCheckedGetter, InstanceCheckedSetter,
 
17436
                    Handle<Value>(),
 
17437
                    v8::DEFAULT,
 
17438
                    v8::None,
 
17439
                    v8::AccessorSignature::New(templ));
 
17440
  context->Global()->Set(v8_str("f"), templ->GetFunction());
 
17441
 
 
17442
  printf("Testing positive ...\n");
 
17443
  CompileRun("var obj = new f();");
 
17444
  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17445
  CheckInstanceCheckedAccessors(true);
 
17446
 
 
17447
  printf("Testing negative ...\n");
 
17448
  CompileRun("var obj = {};"
 
17449
             "obj.__proto__ = new f();");
 
17450
  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17451
  CheckInstanceCheckedAccessors(false);
 
17452
}
 
17453
 
 
17454
 
 
17455
THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
 
17456
  v8::internal::FLAG_allow_natives_syntax = true;
 
17457
  v8::HandleScope scope;
 
17458
  LocalContext context;
 
17459
 
 
17460
  Local<FunctionTemplate> templ = FunctionTemplate::New();
 
17461
  Local<ObjectTemplate> proto = templ->PrototypeTemplate();
 
17462
  proto->SetAccessor(v8_str("foo"),
 
17463
                     InstanceCheckedGetter, InstanceCheckedSetter,
 
17464
                     Handle<Value>(),
 
17465
                     v8::DEFAULT,
 
17466
                     v8::None,
 
17467
                     v8::AccessorSignature::New(templ));
 
17468
  context->Global()->Set(v8_str("f"), templ->GetFunction());
 
17469
 
 
17470
  printf("Testing positive ...\n");
 
17471
  CompileRun("var obj = new f();");
 
17472
  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17473
  CheckInstanceCheckedAccessors(true);
 
17474
 
 
17475
  printf("Testing negative ...\n");
 
17476
  CompileRun("var obj = {};"
 
17477
             "obj.__proto__ = new f();");
 
17478
  CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17479
  CheckInstanceCheckedAccessors(false);
 
17480
 
 
17481
  printf("Testing positive with modified prototype chain ...\n");
 
17482
  CompileRun("var obj = new f();"
 
17483
             "var pro = {};"
 
17484
             "pro.__proto__ = obj.__proto__;"
 
17485
             "obj.__proto__ = pro;");
 
17486
  CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
 
17487
  CheckInstanceCheckedAccessors(true);
 
17488
}
 
17489
 
 
17490
 
 
17491
TEST(TryFinallyMessage) {
 
17492
  v8::HandleScope scope;
 
17493
  LocalContext context;
 
17494
  {
 
17495
    // Test that the original error message is not lost if there is a
 
17496
    // recursive call into Javascript is done in the finally block, e.g. to
 
17497
    // initialize an IC. (crbug.com/129171)
 
17498
    TryCatch try_catch;
 
17499
    const char* trigger_ic =
 
17500
        "try {                      \n"
 
17501
        "  throw new Error('test'); \n"
 
17502
        "} finally {                \n"
 
17503
        "  var x = 0;               \n"
 
17504
        "  x++;                     \n"  // Trigger an IC initialization here.
 
17505
        "}                          \n";
 
17506
    CompileRun(trigger_ic);
 
17507
    CHECK(try_catch.HasCaught());
 
17508
    Local<Message> message = try_catch.Message();
 
17509
    CHECK(!message.IsEmpty());
 
17510
    CHECK_EQ(2, message->GetLineNumber());
 
17511
  }
 
17512
 
 
17513
  {
 
17514
    // Test that the original exception message is indeed overwritten if
 
17515
    // a new error is thrown in the finally block.
 
17516
    TryCatch try_catch;
 
17517
    const char* throw_again =
 
17518
        "try {                       \n"
 
17519
        "  throw new Error('test');  \n"
 
17520
        "} finally {                 \n"
 
17521
        "  var x = 0;                \n"
 
17522
        "  x++;                      \n"
 
17523
        "  throw new Error('again'); \n"  // This is the new uncaught error.
 
17524
        "}                           \n";
 
17525
    CompileRun(throw_again);
 
17526
    CHECK(try_catch.HasCaught());
 
17527
    Local<Message> message = try_catch.Message();
 
17528
    CHECK(!message.IsEmpty());
 
17529
    CHECK_EQ(6, message->GetLineNumber());
 
17530
  }
 
17531
}
 
17532
 
 
17533
 
 
17534
static void Helper137002(bool do_store,
 
17535
                         bool polymorphic,
 
17536
                         bool remove_accessor,
 
17537
                         bool interceptor) {
 
17538
  LocalContext context;
 
17539
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
17540
  if (interceptor) {
 
17541
    templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
 
17542
  } else {
 
17543
    templ->SetAccessor(v8_str("foo"),
 
17544
                       GetterWhichReturns42,
 
17545
                       SetterWhichSetsYOnThisTo23);
 
17546
  }
 
17547
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
17548
 
 
17549
  // Turn monomorphic on slow object with native accessor, then turn
 
17550
  // polymorphic, finally optimize to create negative lookup and fail.
 
17551
  CompileRun(do_store ?
 
17552
             "function f(x) { x.foo = void 0; }" :
 
17553
             "function f(x) { return x.foo; }");
 
17554
  CompileRun("obj.y = void 0;");
 
17555
  if (!interceptor) {
 
17556
    CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
 
17557
  }
 
17558
  CompileRun("obj.__proto__ = null;"
 
17559
             "f(obj); f(obj); f(obj);");
 
17560
  if (polymorphic) {
 
17561
    CompileRun("f({});");
 
17562
  }
 
17563
  CompileRun("obj.y = void 0;"
 
17564
             "%OptimizeFunctionOnNextCall(f);");
 
17565
  if (remove_accessor) {
 
17566
    CompileRun("delete obj.foo;");
 
17567
  }
 
17568
  CompileRun("var result = f(obj);");
 
17569
  if (do_store) {
 
17570
    CompileRun("result = obj.y;");
 
17571
  }
 
17572
  if (remove_accessor && !interceptor) {
 
17573
    CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
 
17574
  } else {
 
17575
    CHECK_EQ(do_store ? 23 : 42,
 
17576
             context->Global()->Get(v8_str("result"))->Int32Value());
 
17577
  }
 
17578
}
 
17579
 
 
17580
 
 
17581
THREADED_TEST(Regress137002a) {
 
17582
  i::FLAG_allow_natives_syntax = true;
 
17583
  i::FLAG_compilation_cache = false;
 
17584
  v8::HandleScope scope;
 
17585
  for (int i = 0; i < 16; i++) {
 
17586
    Helper137002(i & 8, i & 4, i & 2, i & 1);
 
17587
  }
 
17588
}
 
17589
 
 
17590
 
 
17591
THREADED_TEST(Regress137002b) {
 
17592
  i::FLAG_allow_natives_syntax = true;
 
17593
  v8::HandleScope scope;
 
17594
  LocalContext context;
 
17595
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
17596
  templ->SetAccessor(v8_str("foo"),
 
17597
                     GetterWhichReturns42,
 
17598
                     SetterWhichSetsYOnThisTo23);
 
17599
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
17600
 
 
17601
  // Turn monomorphic on slow object with native accessor, then just
 
17602
  // delete the property and fail.
 
17603
  CompileRun("function load(x) { return x.foo; }"
 
17604
             "function store(x) { x.foo = void 0; }"
 
17605
             "function keyed_load(x, key) { return x[key]; }"
 
17606
             // Second version of function has a different source (add void 0)
 
17607
             // so that it does not share code with the first version.  This
 
17608
             // ensures that the ICs are monomorphic.
 
17609
             "function load2(x) { void 0; return x.foo; }"
 
17610
             "function store2(x) { void 0; x.foo = void 0; }"
 
17611
             "function keyed_load2(x, key) { void 0; return x[key]; }"
 
17612
 
 
17613
             "obj.y = void 0;"
 
17614
             "obj.__proto__ = null;"
 
17615
             "var subobj = {};"
 
17616
             "subobj.y = void 0;"
 
17617
             "subobj.__proto__ = obj;"
 
17618
             "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
 
17619
 
 
17620
             // Make the ICs monomorphic.
 
17621
             "load(obj); load(obj);"
 
17622
             "load2(subobj); load2(subobj);"
 
17623
             "store(obj); store(obj);"
 
17624
             "store2(subobj); store2(subobj);"
 
17625
             "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
 
17626
             "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
 
17627
 
 
17628
             // Actually test the shiny new ICs and better not crash. This
 
17629
             // serves as a regression test for issue 142088 as well.
 
17630
             "load(obj);"
 
17631
             "load2(subobj);"
 
17632
             "store(obj);"
 
17633
             "store2(subobj);"
 
17634
             "keyed_load(obj, 'foo');"
 
17635
             "keyed_load2(subobj, 'foo');"
 
17636
 
 
17637
             // Delete the accessor.  It better not be called any more now.
 
17638
             "delete obj.foo;"
 
17639
             "obj.y = void 0;"
 
17640
             "subobj.y = void 0;"
 
17641
 
 
17642
             "var load_result = load(obj);"
 
17643
             "var load_result2 = load2(subobj);"
 
17644
             "var keyed_load_result = keyed_load(obj, 'foo');"
 
17645
             "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
 
17646
             "store(obj);"
 
17647
             "store2(subobj);"
 
17648
             "var y_from_obj = obj.y;"
 
17649
             "var y_from_subobj = subobj.y;");
 
17650
  CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
 
17651
  CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
 
17652
  CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
 
17653
  CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
 
17654
  CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
 
17655
  CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
 
17656
}
 
17657
 
 
17658
 
 
17659
THREADED_TEST(Regress142088) {
 
17660
  i::FLAG_allow_natives_syntax = true;
 
17661
  v8::HandleScope scope;
 
17662
  LocalContext context;
 
17663
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
17664
  templ->SetAccessor(v8_str("foo"),
 
17665
                     GetterWhichReturns42,
 
17666
                     SetterWhichSetsYOnThisTo23);
 
17667
  context->Global()->Set(v8_str("obj"), templ->NewInstance());
 
17668
 
 
17669
  CompileRun("function load(x) { return x.foo; }"
 
17670
             "var o = Object.create(obj);"
 
17671
             "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
 
17672
             "load(o); load(o); load(o); load(o);");
 
17673
}
 
17674
 
 
17675
 
 
17676
THREADED_TEST(Regress137496) {
 
17677
  i::FLAG_expose_gc = true;
 
17678
  v8::HandleScope scope;
 
17679
  LocalContext context;
 
17680
 
 
17681
  // Compile a try-finally clause where the finally block causes a GC
 
17682
  // while there still is a message pending for external reporting.
 
17683
  TryCatch try_catch;
 
17684
  try_catch.SetVerbose(true);
 
17685
  CompileRun("try { throw new Error(); } finally { gc(); }");
 
17686
  CHECK(try_catch.HasCaught());
 
17687
}
 
17688
 
 
17689
 
 
17690
THREADED_TEST(Regress149912) {
 
17691
  v8::HandleScope scope;
 
17692
  LocalContext context;
 
17693
  Handle<FunctionTemplate> templ = FunctionTemplate::New();
 
17694
  AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
 
17695
  context->Global()->Set(v8_str("Bug"), templ->GetFunction());
 
17696
  CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
 
17697
}
 
17698
 
 
17699
 
 
17700
THREADED_TEST(Regress157124) {
 
17701
  v8::HandleScope scope;
 
17702
  LocalContext context;
 
17703
  Local<ObjectTemplate> templ = ObjectTemplate::New();
 
17704
  Local<Object> obj = templ->NewInstance();
 
17705
  obj->GetIdentityHash();
 
17706
  obj->DeleteHiddenValue(v8_str("Bug"));
 
17707
}
 
17708
 
 
17709
 
 
17710
#ifndef WIN32
 
17711
class ThreadInterruptTest {
 
17712
 public:
 
17713
  ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
 
17714
  ~ThreadInterruptTest() { delete sem_; }
 
17715
 
 
17716
  void RunTest() {
 
17717
    sem_ = i::OS::CreateSemaphore(0);
 
17718
 
 
17719
    InterruptThread i_thread(this);
 
17720
    i_thread.Start();
 
17721
 
 
17722
    sem_->Wait();
 
17723
    CHECK_EQ(kExpectedValue, sem_value_);
 
17724
  }
 
17725
 
 
17726
 private:
 
17727
  static const int kExpectedValue = 1;
 
17728
 
 
17729
  class InterruptThread : public i::Thread {
 
17730
   public:
 
17731
    explicit InterruptThread(ThreadInterruptTest* test)
 
17732
        : Thread("InterruptThread"), test_(test) {}
 
17733
 
 
17734
    virtual void Run() {
 
17735
      struct sigaction action;
 
17736
 
 
17737
      // Ensure that we'll enter waiting condition
 
17738
      i::OS::Sleep(100);
 
17739
 
 
17740
      // Setup signal handler
 
17741
      memset(&action, 0, sizeof(action));
 
17742
      action.sa_handler = SignalHandler;
 
17743
      sigaction(SIGCHLD, &action, NULL);
 
17744
 
 
17745
      // Send signal
 
17746
      kill(getpid(), SIGCHLD);
 
17747
 
 
17748
      // Ensure that if wait has returned because of error
 
17749
      i::OS::Sleep(100);
 
17750
 
 
17751
      // Set value and signal semaphore
 
17752
      test_->sem_value_ = 1;
 
17753
      test_->sem_->Signal();
 
17754
    }
 
17755
 
 
17756
    static void SignalHandler(int signal) {
 
17757
    }
 
17758
 
 
17759
   private:
 
17760
     ThreadInterruptTest* test_;
 
17761
     struct sigaction sa_;
 
17762
  };
 
17763
 
 
17764
  i::Semaphore* sem_;
 
17765
  volatile int sem_value_;
 
17766
};
 
17767
 
 
17768
 
 
17769
THREADED_TEST(SemaphoreInterruption) {
 
17770
  ThreadInterruptTest().RunTest();
 
17771
}
 
17772
#endif  // WIN32