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
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.
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.
31
#include <signal.h> // kill
32
#include <unistd.h> // getpid
39
#include "compilation-cache.h"
40
#include "execution.h"
47
#include "unicode-inl.h"
49
static const bool kLogThreading = false;
51
static bool IsNaN(double x) {
59
using ::v8::AccessorInfo;
60
using ::v8::Arguments;
62
using ::v8::Extension;
64
using ::v8::FunctionTemplate;
66
using ::v8::HandleScope;
69
using ::v8::MessageCallback;
71
using ::v8::ObjectTemplate;
72
using ::v8::Persistent;
74
using ::v8::StackTrace;
77
using ::v8::Undefined;
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);
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());
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());
102
static void ExpectTrue(const char* code) {
103
ExpectBoolean(code, true);
107
static void ExpectFalse(const char* code) {
108
ExpectBoolean(code, false);
112
static void ExpectObject(const char* code, Local<Value> expected) {
113
Local<Value> result = CompileRun(code);
114
CHECK(result->Equals(expected));
118
static void ExpectUndefined(const char* code) {
119
Local<Value> result = CompileRun(code);
120
CHECK(result->IsUndefined());
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]);
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]);
146
THREADED_TEST(Handles) {
147
v8::HandleScope scope;
148
Local<Context> local_env;
151
local_env = env.local();
154
// Local context should still be live.
155
CHECK(!local_env.IsEmpty());
158
v8::Handle<v8::Primitive> undef = v8::Undefined();
159
CHECK(!undef.IsEmpty());
160
CHECK(undef->IsUndefined());
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());
171
THREADED_TEST(ReceiverSignature) {
172
v8::HandleScope scope;
174
v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
175
v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
176
fun->PrototypeTemplate()->Set(
178
v8::FunctionTemplate::New(IncrementingSignatureCallback,
181
env->Global()->Set(v8_str("Fun"), fun->GetFunction());
182
signature_callback_count = 0;
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());
191
"var o = new SubFun();"
193
CHECK_EQ(2, signature_callback_count);
195
v8::TryCatch try_catch;
198
"o.m = Fun.prototype.m;"
200
CHECK_EQ(2, signature_callback_count);
201
CHECK(try_catch.HasCaught());
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());
207
"var o = new UnrelFun();"
208
"o.m = Fun.prototype.m;"
210
CHECK_EQ(2, signature_callback_count);
211
CHECK(try_catch.HasCaught());
215
THREADED_TEST(ArgumentSignature) {
216
v8::HandleScope scope;
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());
227
v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
228
CHECK(value1->IsTrue());
230
v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
231
CHECK(value2->IsTrue());
233
v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
234
CHECK(value3->IsTrue());
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"));
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);
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());
258
v8::Handle<Value> value5 = CompileRun(
259
"Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
260
CHECK(value5->IsTrue());
262
v8::Handle<Value> value6 = CompileRun(
263
"Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
264
CHECK(value6->IsTrue());
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());
271
v8::Handle<Value> value8 = CompileRun(
272
"Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
273
CHECK(value8->IsTrue());
277
THREADED_TEST(HulIgennem) {
278
v8::HandleScope scope;
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);
289
THREADED_TEST(Access) {
290
v8::HandleScope scope;
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);
304
THREADED_TEST(AccessElement) {
305
v8::HandleScope scope;
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);
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));
323
THREADED_TEST(Script) {
324
v8::HandleScope scope;
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());
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];
341
class TestResource: public String::ExternalStringResource {
343
explicit TestResource(uint16_t* data, int* counter = NULL)
344
: data_(data), length_(0), counter_(counter) {
345
while (data[length_]) ++length_;
349
i::DeleteArray(data_);
350
if (counter_ != NULL) ++*counter_;
353
const uint16_t* data() const {
357
size_t length() const {
367
class TestAsciiResource: public String::ExternalAsciiStringResource {
369
explicit TestAsciiResource(const char* data, int* counter = NULL)
370
: data_(data), length_(strlen(data)), counter_(counter) { }
372
~TestAsciiResource() {
373
i::DeleteArray(data_);
374
if (counter_ != NULL) ++*counter_;
377
const char* data() const {
381
size_t length() const {
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);
396
v8::HandleScope scope;
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());
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);
414
v8::internal::Isolate::Current()->compilation_cache()->Clear();
415
HEAP->CollectAllAvailableGarbage();
416
CHECK_EQ(1, dispose_count);
420
THREADED_TEST(ScriptUsingAsciiStringResource) {
421
int dispose_count = 0;
422
const char* c_source = "1 + 2 * 3";
424
v8::HandleScope scope;
426
TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
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);
443
i::Isolate::Current()->compilation_cache()->Clear();
444
HEAP->CollectAllAvailableGarbage();
445
CHECK_EQ(1, dispose_count);
449
THREADED_TEST(ScriptMakingExternalString) {
450
int dispose_count = 0;
451
uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
453
v8::HandleScope scope;
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,
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);
474
i::Isolate::Current()->compilation_cache()->Clear();
475
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
476
CHECK_EQ(1, dispose_count);
480
THREADED_TEST(ScriptMakingExternalAsciiString) {
481
int dispose_count = 0;
482
const char* c_source = "1 + 2 * 3";
484
v8::HandleScope scope;
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));
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);
500
i::Isolate::Current()->compilation_cache()->Clear();
501
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
502
CHECK_EQ(1, dispose_count);
506
TEST(MakingExternalStringConditions) {
507
v8::HandleScope scope;
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);
514
uint16_t* two_byte_string = AsciiToTwoByteString("s1");
515
Local<String> small_string = String::New(two_byte_string);
516
i::DeleteArray(two_byte_string);
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());
526
two_byte_string = AsciiToTwoByteString("small string 2");
527
small_string = String::New(two_byte_string);
528
i::DeleteArray(two_byte_string);
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);
535
// Frequently used strings should be accepted.
536
CHECK(small_string->CanMakeExternal());
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';
543
two_byte_string = AsciiToTwoByteString(buf);
544
Local<String> large_string = String::New(two_byte_string);
546
i::DeleteArray(two_byte_string);
547
// Large strings should be immediately accepted.
548
CHECK(large_string->CanMakeExternal());
552
TEST(MakingExternalAsciiStringConditions) {
553
v8::HandleScope scope;
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);
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());
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);
575
// Frequently used strings should be accepted.
576
CHECK(small_string->CanMakeExternal());
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);
584
// Large strings should be immediately accepted.
585
CHECK(large_string->CanMakeExternal());
589
THREADED_TEST(UsingExternalString) {
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());
602
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
603
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
607
THREADED_TEST(UsingExternalAsciiString) {
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());
620
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
621
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
625
THREADED_TEST(ScavengeExternalString) {
626
int dispose_count = 0;
627
bool in_new_space = false;
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,
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);
640
HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
641
CHECK_EQ(1, dispose_count);
645
THREADED_TEST(ScavengeExternalAsciiString) {
646
int dispose_count = 0;
647
bool in_new_space = false;
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);
659
HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
660
CHECK_EQ(1, dispose_count);
664
class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
666
// Only used by non-threaded tests, so it can use static fields.
667
static int dispose_calls;
668
static int dispose_count;
670
TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
671
: TestAsciiResource(data, &dispose_count),
672
dispose_(dispose) { }
676
if (dispose_) delete this;
683
int TestAsciiResourceWithDisposeControl::dispose_count = 0;
684
int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
687
TEST(ExternalStringWithDisposeHandling) {
688
const char* c_source = "1 + 2 * 3";
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);
695
v8::HandleScope scope;
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);
705
i::Isolate::Current()->compilation_cache()->Clear();
706
HEAP->CollectAllAvailableGarbage();
707
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
708
CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
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);
716
v8::HandleScope scope;
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);
726
i::Isolate::Current()->compilation_cache()->Clear();
727
HEAP->CollectAllAvailableGarbage();
728
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
729
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
733
THREADED_TEST(StringConcat) {
735
v8::HandleScope scope;
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);
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);
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);
760
two_byte_source = AsciiToTwoByteString(two_byte_string_2);
761
right = String::New(two_byte_source);
762
i::DeleteArray(two_byte_source);
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());
773
i::Isolate::Current()->compilation_cache()->Clear();
774
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
775
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
779
THREADED_TEST(GlobalProperties) {
780
v8::HandleScope scope;
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());
789
static v8::Handle<Value> handle_call(const v8::Arguments& args) {
790
ApiTestFuzzer::Fuzz();
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));
802
static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
803
ApiTestFuzzer::Fuzz();
808
THREADED_TEST(FunctionTemplate) {
809
v8::HandleScope scope;
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());
819
// Use SetCallHandler to initialize a function template, should work like the
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());
829
// Test constructor calls.
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());
840
Local<Value> result = v8_compile("(new obj()).toString()")->Run();
841
CHECK_EQ(v8_str("[object funky]"), result);
843
result = v8_compile("(new obj()).m")->Run();
844
CHECK_EQ(239, result->Int32Value());
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);
857
static void TestExternalPointerWrapping() {
858
v8::HandleScope scope;
861
v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
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);
870
" for (var i = 0; i < 13; i++) obj.func();\n"
872
"foo(), true")->BooleanValue());
876
THREADED_TEST(ExternalWrap) {
877
// Check heap allocated object.
880
TestExternalPointerWrapping();
883
// Check stack allocated object.
886
TestExternalPointerWrapping();
888
// Check not aligned addresses.
890
char* s = new char[n];
891
for (int i = 0; i < n; i++) {
892
expected_ptr = s + i;
893
TestExternalPointerWrapping();
898
// Check several invalid addresses.
899
expected_ptr = reinterpret_cast<void*>(1);
900
TestExternalPointerWrapping();
902
expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
903
TestExternalPointerWrapping();
905
expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
906
TestExternalPointerWrapping();
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();
913
expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
914
TestExternalPointerWrapping();
916
expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
917
TestExternalPointerWrapping();
922
THREADED_TEST(FindInstanceInPrototypeChain) {
923
v8::HandleScope scope;
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);
931
Local<v8::Function> base_function = base->GetFunction();
932
Local<v8::Function> derived_function = derived->GetFunction();
933
Local<v8::Function> other_function = other->GetFunction();
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);
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());
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());
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
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));
969
THREADED_TEST(TinyInteger) {
970
v8::HandleScope scope;
972
v8::Isolate* isolate = v8::Isolate::GetCurrent();
975
Local<v8::Integer> value_obj = v8::Integer::New(value);
976
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
978
value_obj = v8::Integer::New(value, isolate);
979
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983
THREADED_TEST(BigSmiInteger) {
984
v8::HandleScope scope;
986
v8::Isolate* isolate = v8::Isolate::GetCurrent();
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));
994
Local<v8::Integer> value_obj = v8::Integer::New(value);
995
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
997
value_obj = v8::Integer::New(value, isolate);
998
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1003
THREADED_TEST(BigInteger) {
1004
v8::HandleScope scope;
1006
v8::Isolate* isolate = v8::Isolate::GetCurrent();
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.
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));
1017
Local<v8::Integer> value_obj = v8::Integer::New(value);
1018
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1020
value_obj = v8::Integer::New(value, isolate);
1021
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026
THREADED_TEST(TinyUnsignedInteger) {
1027
v8::HandleScope scope;
1029
v8::Isolate* isolate = v8::Isolate::GetCurrent();
1031
uint32_t value = 239;
1033
Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1034
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1036
value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1037
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1041
THREADED_TEST(BigUnsignedSmiInteger) {
1042
v8::HandleScope scope;
1044
v8::Isolate* isolate = v8::Isolate::GetCurrent();
1046
uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1047
CHECK(i::Smi::IsValid(value));
1048
CHECK(!i::Smi::IsValid(value + 1));
1050
Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1051
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1053
value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1054
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1058
THREADED_TEST(BigUnsignedInteger) {
1059
v8::HandleScope scope;
1061
v8::Isolate* isolate = v8::Isolate::GetCurrent();
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));
1067
Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1068
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1070
value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1071
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1075
THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1076
v8::HandleScope scope;
1078
v8::Isolate* isolate = v8::Isolate::GetCurrent();
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.
1084
Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1085
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1087
value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1088
CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1092
THREADED_TEST(IsNativeError) {
1093
v8::HandleScope scope;
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());
1105
THREADED_TEST(StringObject) {
1106
v8::HandleScope scope;
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);
1130
THREADED_TEST(NumberObject) {
1131
v8::HandleScope scope;
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);
1151
THREADED_TEST(BooleanObject) {
1152
v8::HandleScope scope;
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());
1176
THREADED_TEST(Number) {
1177
v8::HandleScope scope;
1179
double PI = 3.1415926;
1180
Local<v8::Number> pi_obj = v8::Number::New(PI);
1181
CHECK_EQ(PI, pi_obj->NumberValue());
1185
THREADED_TEST(ToNumber) {
1186
v8::HandleScope scope;
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());
1197
THREADED_TEST(Date) {
1198
v8::HandleScope scope;
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());
1208
THREADED_TEST(Boolean) {
1209
v8::HandleScope scope;
1211
v8::Handle<v8::Boolean> t = v8::True();
1213
v8::Handle<v8::Boolean> f = v8::False();
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());
1231
static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1232
ApiTestFuzzer::Fuzz();
1233
return v8_num(13.4);
1237
static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1238
ApiTestFuzzer::Fuzz();
1243
THREADED_TEST(GlobalPrototype) {
1244
v8::HandleScope scope;
1245
v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1246
func_templ->PrototypeTemplate()->Set(
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());
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));
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());
1285
static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1286
ApiTestFuzzer::Fuzz();
1287
return v8_num(17.2);
1291
static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1292
ApiTestFuzzer::Fuzz();
1293
return v8_num(15.2);
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));
1304
super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1306
v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1307
base1->Inherit(super);
1308
base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1310
v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1311
base2->Inherit(super);
1312
base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
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());
1320
// Checks right __proto__ chain.
1321
CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1322
CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1324
CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
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());
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());
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());
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());
1353
int echo_named_call_count;
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++;
1364
// Helper functions for Interceptor/Accessor interaction tests
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));
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);
1378
Handle<Value> EmptyInterceptorGetter(Local<String> name,
1379
const AccessorInfo& info) {
1380
return Handle<Value>();
1383
Handle<Value> EmptyInterceptorSetter(Local<String> name,
1385
const AccessorInfo& info) {
1386
return Handle<Value>();
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_";
1396
for (i = 0; name_str[i] && prefix[i]; ++i) {
1397
if (name_str[i] != prefix[i]) return Handle<Value>();
1399
Handle<Object> self = info.This();
1400
return self->GetHiddenValue(v8_str(name_str + i));
1403
Handle<Value> InterceptorSetter(Local<String> name,
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);
1412
return Handle<Value>();
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);
1422
void AddInterceptor(Handle<FunctionTemplate> templ,
1423
v8::NamedPropertyGetter getter,
1424
v8::NamedPropertySetter setter) {
1425
templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
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);
1437
env->Global()->Set(v8_str("Child"), child->GetFunction());
1438
CompileRun("var child = new Child;"
1440
ExpectBoolean("child.hasOwnProperty('age')", false);
1441
ExpectInt32("child.age", 10);
1442
ExpectInt32("child.accessor_age", 10);
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);
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});"
1460
ExpectBoolean("child.hasOwnProperty('age')", false);
1461
ExpectInt32("child.age", 10);
1462
ExpectInt32("child.accessor_age", 10);
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);
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");
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);
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);
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);
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);
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);
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);
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);
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);
1556
THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1557
v8::HandleScope scope;
1558
Handle<FunctionTemplate> templ = FunctionTemplate::New();
1559
AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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");
1580
THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1581
v8::HandleScope scope;
1582
Handle<FunctionTemplate> templ = FunctionTemplate::New();
1583
AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
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");
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);
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);
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);
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);
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,
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());
1662
int echo_indexed_call_count = 0;
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);
1674
THREADED_TEST(IndexedPropertyHandlerGetter) {
1675
v8::HandleScope scope;
1676
v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1677
templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
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);
1688
v8::Handle<v8::Object> bottom;
1690
static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1692
const AccessorInfo& info) {
1693
ApiTestFuzzer::Fuzz();
1694
CHECK(info.This()->Equals(bottom));
1695
return v8::Handle<Value>();
1698
static v8::Handle<Value> CheckThisNamedPropertyHandler(
1700
const AccessorInfo& info) {
1701
ApiTestFuzzer::Fuzz();
1702
CHECK(info.This()->Equals(bottom));
1703
return v8::Handle<Value>();
1707
v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1709
const AccessorInfo& info) {
1710
ApiTestFuzzer::Fuzz();
1711
CHECK(info.This()->Equals(bottom));
1712
return v8::Handle<Value>();
1716
v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1718
const AccessorInfo& info) {
1719
ApiTestFuzzer::Fuzz();
1720
CHECK(info.This()->Equals(bottom));
1721
return v8::Handle<Value>();
1724
v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1726
const AccessorInfo& info) {
1727
ApiTestFuzzer::Fuzz();
1728
CHECK(info.This()->Equals(bottom));
1729
return v8::Handle<v8::Integer>();
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>();
1741
v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1743
const AccessorInfo& info) {
1744
ApiTestFuzzer::Fuzz();
1745
CHECK(info.This()->Equals(bottom));
1746
return v8::Handle<v8::Boolean>();
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>();
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>();
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>();
1775
THREADED_TEST(PropertyHandlerInPrototype) {
1776
v8::HandleScope scope;
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);
1788
templ->InstanceTemplate()->SetNamedPropertyHandler(
1789
CheckThisNamedPropertyHandler,
1790
CheckThisNamedPropertySetter,
1791
CheckThisNamedPropertyQuery,
1792
CheckThisNamedPropertyDeleter,
1793
CheckThisNamedPropertyEnumerator);
1795
bottom = templ->GetFunction()->NewInstance();
1796
Local<v8::Object> top = templ->GetFunction()->NewInstance();
1797
Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1799
bottom->Set(v8_str("__proto__"), middle);
1800
middle->Set(v8_str("__proto__"), top);
1801
env->Global()->Set(v8_str("obj"), bottom);
1803
// Indexed and named get.
1804
Script::Compile(v8_str("obj[0]"))->Run();
1805
Script::Compile(v8_str("obj.x"))->Run();
1807
// Indexed and named set.
1808
Script::Compile(v8_str("obj[1] = 42"))->Run();
1809
Script::Compile(v8_str("obj.y = 42"))->Run();
1811
// Indexed and named query.
1812
Script::Compile(v8_str("0 in obj"))->Run();
1813
Script::Compile(v8_str("'x' in obj"))->Run();
1815
// Indexed and named deleter.
1816
Script::Compile(v8_str("delete obj[0]"))->Run();
1817
Script::Compile(v8_str("delete obj.x"))->Run();
1820
Script::Compile(v8_str("for (var p in obj) ;"))->Run();
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");
1830
return v8::Handle<String>();
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);
1840
return v8::Handle<v8::Integer>(); // do not intercept the call
1844
THREADED_TEST(PrePropertyHandler) {
1845
v8::HandleScope scope;
1846
v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1847
desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
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());
1862
THREADED_TEST(UndefinedIsNotEnumerable) {
1863
v8::HandleScope scope;
1865
v8::Handle<Value> result = Script::Compile(v8_str(
1866
"this.propertyIsEnumerable(undefined)"))->Run();
1867
CHECK(result->IsFalse());
1871
v8::Handle<Script> call_recursively_script;
1872
static const int kTargetRecursionDepth = 200; // near maximum
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();
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();
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);
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);
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>();
1913
env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1914
Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1918
static v8::Handle<Value>
1919
ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1920
ApiTestFuzzer::Fuzz();
1921
return v8::ThrowException(key);
1925
static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1927
const AccessorInfo&) {
1928
v8::ThrowException(key);
1929
return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1933
THREADED_TEST(CallbackExceptionRegression) {
1934
v8::HandleScope scope;
1935
v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1936
obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1937
ThrowingPropertyHandlerSet);
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);
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));
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);
1960
THREADED_TEST(InternalFields) {
1961
v8::HandleScope scope;
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());
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());
1989
THREADED_TEST(InternalFieldsNativePointers) {
1990
v8::HandleScope scope;
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);
2000
char* data = new char[100];
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));
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));
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));
2021
THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2022
v8::HandleScope scope;
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);
2032
char* data = new char[100];
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));
2039
obj->SetPointerInInternalField(0, aligned);
2040
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2041
CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2043
obj->SetPointerInInternalField(0, unaligned);
2044
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2045
CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2047
obj->SetInternalField(0, v8::External::Wrap(aligned));
2048
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2049
CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2051
obj->SetInternalField(0, v8::External::Wrap(unaligned));
2052
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2053
CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2059
THREADED_TEST(IdentityHash) {
2060
v8::HandleScope scope;
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);
2084
// Check identity hashes behaviour in the presence of JS accessors.
2085
// Put a getter for 'v8::IdentityHash' on the Object's prototype:
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());
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());
2103
THREADED_TEST(HiddenProperties) {
2104
v8::HandleScope scope;
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");
2112
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2114
// Make sure delete of a non-existent hidden value works
2115
CHECK(obj->DeleteHiddenValue(key));
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());
2122
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
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());
2133
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2135
// Add another property and delete it afterwards to force the object in
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());
2144
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2146
CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2147
CHECK(obj->GetHiddenValue(key).IsEmpty());
2149
CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2150
CHECK(obj->DeleteHiddenValue(key));
2151
CHECK(obj->GetHiddenValue(key).IsEmpty());
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;
2162
v8::Local<v8::Object> obj = v8::Object::New();
2163
v8::Local<v8::String> key = v8_str("hidden");
2166
"set_called = false;"
2167
"Object.defineProperty("
2168
" Object.prototype,"
2170
" {get: function() { return 45; },"
2171
" set: function() { set_called = true; }})");
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
2177
CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2178
ExpectFalse("set_called");
2179
CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
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>();
2191
THREADED_TEST(HiddenPropertiesWithInterceptors) {
2192
v8::HandleScope scope;
2193
LocalContext context;
2195
interceptor_for_hidden_properties_called = false;
2197
v8::Local<v8::String> key = v8_str("api-test::hidden-key");
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);
2211
THREADED_TEST(External) {
2212
v8::HandleScope scope;
2214
Local<v8::External> ext = v8::External::New(&x);
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());
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]);
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);
2243
THREADED_TEST(GlobalHandle) {
2244
v8::Persistent<String> global;
2246
v8::HandleScope scope;
2247
Local<String> str = v8_str("str");
2248
global = v8::Persistent<String>::New(str);
2250
CHECK_EQ(global->Length(), 3);
2255
class WeakCallCounter {
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_; }
2263
int number_of_weak_calls_;
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();
2275
THREADED_TEST(ApiObjectGroups) {
2279
Persistent<Object> g1s1;
2280
Persistent<Object> g1s2;
2281
Persistent<Object> g1c1;
2282
Persistent<Object> g2s1;
2283
Persistent<Object> g2s2;
2284
Persistent<Object> g2c1;
2286
WeakCallCounter counter(1234);
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);
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);
2305
Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2307
// Connect group 1 and 2, make a cycle.
2308
CHECK(g1s2->Set(0, g2s2));
2309
CHECK(g2s1->Set(0, g1s1));
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);
2321
// Do a single full GC, ensure incremental marking is stopped.
2322
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2324
// All object should be alive.
2325
CHECK_EQ(0, counter.NumberOfWeakCalls());
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.
2334
// Groups are deleted, rebuild groups.
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);
2346
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2348
// All objects should be gone. 5 global handles in total.
2349
CHECK_EQ(5, counter.NumberOfWeakCalls());
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);
2355
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2356
CHECK_EQ(7, counter.NumberOfWeakCalls());
2360
THREADED_TEST(ApiObjectGroupsCycle) {
2364
WeakCallCounter counter(1234);
2366
Persistent<Object> g1s1;
2367
Persistent<Object> g1s2;
2368
Persistent<Object> g2s1;
2369
Persistent<Object> g2s2;
2370
Persistent<Object> g3s1;
2371
Persistent<Object> g3s2;
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);
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);
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);
2391
Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2393
// Connect groups. We're building the following cycle:
2394
// G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
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);
2410
// Do a single full GC
2411
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2413
// All object should be alive.
2414
CHECK_EQ(0, counter.NumberOfWeakCalls());
2417
root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2419
// Groups are deleted, rebuild groups.
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);
2435
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2437
// All objects should be gone. 7 global handles in total.
2438
CHECK_EQ(7, counter.NumberOfWeakCalls());
2442
THREADED_TEST(ScriptException) {
2443
v8::HandleScope scope;
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!");
2455
bool message_received;
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;
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'"),
2477
script->SetData(v8_str("7.56"));
2479
CHECK(message_received);
2480
// clear out the message listener
2481
v8::V8::RemoveMessageListeners(check_message_0);
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;
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);
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;
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);
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());
2561
THREADED_TEST(PropertyAttributes) {
2562
v8::HandleScope scope;
2563
LocalContext context;
2565
Local<String> prop = v8_str("none");
2566
context->Global()->Set(prop, v8_num(7));
2567
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
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());
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));
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));
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));
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);
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());
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);
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);
2649
const char* fun = "f()";
2650
Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2651
CHECK_EQ(0, a0->Length());
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());
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());
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());
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());
2681
THREADED_TEST(FunctionCall) {
2682
v8::HandleScope scope;
2683
LocalContext context;
2687
" for (var i = 0; i < arguments.length; i++) {"
2688
" result.push(arguments[i]);"
2692
Local<Function> Foo =
2693
Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
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());
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());
2704
v8::Handle<Value> args2[] = { v8_num(2.2),
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());
2711
v8::Handle<Value> args3[] = { v8_num(4.4),
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());
2720
v8::Handle<Value> args4[] = { v8_num(7.7),
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());
2733
static const char* js_code_causing_out_of_memory =
2734
"var a = new Array(); while(true) a.push(a);";
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.
2740
// It's not possible to read a snapshot into a heap with different dimensions.
2741
if (i::Snapshot::IsEnabled()) return;
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);
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();
2757
// Check for out of memory state.
2758
CHECK(result.IsEmpty());
2759
CHECK(context->HasOutOfMemoryException());
2763
v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2764
ApiTestFuzzer::Fuzz();
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();
2772
// Check for out of memory state.
2773
CHECK(result.IsEmpty());
2774
CHECK(context->HasOutOfMemoryException());
2780
TEST(OutOfMemoryNested) {
2781
// It's not possible to read a snapshot into a heap with different dimensions.
2782
if (i::Snapshot::IsEnabled()) return;
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);
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;"
2799
" ProvokeOutOfMemory();"
2803
// Check for out of memory state.
2804
CHECK(result.IsEmpty());
2805
CHECK(context->HasOutOfMemoryException());
2809
TEST(HugeConsStringOutOfMemory) {
2810
// It's not possible to read a snapshot into a heap with different dimensions.
2811
if (i::Snapshot::IsEnabled()) return;
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);
2819
// Execute a script that causes out of memory.
2820
v8::V8::IgnoreOutOfMemoryException();
2822
v8::HandleScope scope;
2823
LocalContext context;
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; }");
2830
// Check for out of memory state.
2831
CHECK(result.IsEmpty());
2832
CHECK(context->HasOutOfMemoryException());
2836
THREADED_TEST(ConstructCall) {
2837
v8::HandleScope scope;
2838
LocalContext context;
2842
" for (var i = 0; i < arguments.length; i++) {"
2843
" result.push(arguments[i]);"
2847
Local<Function> Foo =
2848
Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
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());
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());
2859
v8::Handle<Value> args2[] = { v8_num(2.2),
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());
2866
v8::Handle<Value> args3[] = { v8_num(4.4),
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());
2875
v8::Handle<Value> args4[] = { v8_num(7.7),
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());
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?");
2896
THREADED_TEST(ConversionNumber) {
2897
v8::HandleScope scope;
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.
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
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
2944
THREADED_TEST(isNumberType) {
2945
v8::HandleScope scope;
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());
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());
2983
CompileRun("var obj = 0.0;");
2984
obj = env->Global()->Get(v8_str("obj"));
2985
CHECK(obj->IsInt32());
2986
CHECK(obj->IsUint32());
2988
CompileRun("var obj = -0.0;");
2989
obj = env->Global()->Get(v8_str("obj"));
2990
CHECK(!obj->IsInt32());
2991
CHECK(!obj->IsUint32());
2995
THREADED_TEST(ConversionException) {
2996
v8::HandleScope scope;
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"));
3004
v8::TryCatch try_catch;
3006
Local<Value> to_string_result = obj->ToString();
3007
CHECK(to_string_result.IsEmpty());
3008
CheckUncle(&try_catch);
3010
Local<Value> to_number_result = obj->ToNumber();
3011
CHECK(to_number_result.IsEmpty());
3012
CheckUncle(&try_catch);
3014
Local<Value> to_integer_result = obj->ToInteger();
3015
CHECK(to_integer_result.IsEmpty());
3016
CheckUncle(&try_catch);
3018
Local<Value> to_uint32_result = obj->ToUint32();
3019
CHECK(to_uint32_result.IsEmpty());
3020
CheckUncle(&try_catch);
3022
Local<Value> to_int32_result = obj->ToInt32();
3023
CHECK(to_int32_result.IsEmpty());
3024
CheckUncle(&try_catch);
3026
Local<Value> to_object_result = v8::Undefined()->ToObject();
3027
CHECK(to_object_result.IsEmpty());
3028
CHECK(try_catch.HasCaught());
3031
int32_t int32_value = obj->Int32Value();
3032
CHECK_EQ(0, int32_value);
3033
CheckUncle(&try_catch);
3035
uint32_t uint32_value = obj->Uint32Value();
3036
CHECK_EQ(0, uint32_value);
3037
CheckUncle(&try_catch);
3039
double number_value = obj->NumberValue();
3040
CHECK_NE(0, IsNaN(number_value));
3041
CheckUncle(&try_catch);
3043
int64_t integer_value = obj->IntegerValue();
3044
CHECK_EQ(0.0, static_cast<double>(integer_value));
3045
CheckUncle(&try_catch);
3049
v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3050
ApiTestFuzzer::Fuzz();
3051
return v8::ThrowException(v8_str("konto"));
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());
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);
3072
"var thrown = false;"
3078
Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3079
CHECK(thrown->BooleanValue());
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());
3095
// Test that a try-finally block doesn't shadow a try-catch block
3096
// when setting up an external handler.
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 {"
3110
" CCatcher('throw 7;');"
3115
CHECK(result->IsTrue());
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)));
3127
static v8::Handle<Value> Fail(const v8::Arguments& args) {
3128
ApiTestFuzzer::Fuzz();
3130
return v8::Undefined();
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;");
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);
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)));
3183
TEST(CustomErrorToString) {
3184
v8::HandleScope scope;
3185
v8::V8::AddMessageListener(check_custom_error_message);
3186
LocalContext context;
3188
"function MyError(name, message) { "
3189
" this.name = name; "
3190
" this.message = message; "
3192
"MyError.prototype = Object.create(Error.prototype); "
3193
"MyError.prototype.toString = function() { "
3194
" return 'MyError toString'; "
3196
"throw new MyError('my name', 'my message'); ");
3197
v8::V8::RemoveMessageListeners(check_custom_error_message);
3201
static void receive_message(v8::Handle<v8::Message> message,
3202
v8::Handle<v8::Value> data) {
3204
message_received = true;
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);
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);
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);
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);
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);
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();
3280
return v8::ThrowException(v8_str("FromC"));
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),
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());
3297
CHECK_NE(expected, count);
3301
return fun.As<Function>()->Call(global, 4, argv);
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();
3314
CHECK_EQ(count, expected);
3316
CHECK_NE(count, expected);
3318
return v8::Undefined();
3322
THREADED_TEST(EvalInTryFinally) {
3323
v8::HandleScope scope;
3324
LocalContext context;
3325
v8::TryCatch try_catch;
3326
CompileRun("(function() {"
3328
" eval('asldkf (*&^&*^');"
3333
CHECK(!try_catch.HasCaught());
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.
3345
// The notation used to describe a test case looks like this:
3347
// *JS[4] *C[3] @JS[2] C[1] JS[0]
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.
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);
3365
"function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3366
" if (count == 0) throw 'FromJS';"
3367
" if (count % jsInterval == 0) {"
3369
" var value = CThrowCountDown(count - 1,"
3373
" check(false, count, expected);"
3376
" check(true, count, expected);"
3379
" return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3382
Local<Function> fun =
3383
Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3386
// count jsInterval cInterval expected
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);
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);
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);
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);
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);
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);
3414
v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3415
ApiTestFuzzer::Fuzz();
3416
CHECK_EQ(1, args.Length());
3417
return v8::ThrowException(args[0]);
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) {"
3433
" return 'no exception';"
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());
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());
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());
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());
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());
3484
v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3485
v8::TryCatch try_catch;
3486
return v8::Undefined();
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());
3500
" throw new Error('a');\n"
3502
" native_with_try_catch();\n"
3504
CHECK(try_catch.HasCaught());
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")));
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));
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()));
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));
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++)
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"));
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"));
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());
3578
// Uses getOwnPropertyDescriptor to check the configurable status
3579
Local<Script> script_desc
3580
= Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3582
"prop.configurable;"));
3583
Local<Value> result = script_desc->Run();
3584
CHECK_EQ(result->BooleanValue(), true);
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);"
3592
result = script_define->Run();
3593
CHECK_EQ(result, v8_num(42));
3595
// Check that the accessor is still configurable
3596
result = script_desc->Run();
3597
CHECK_EQ(result->BooleanValue(), true);
3599
// Redefine to a non-configurable
3601
= Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3602
" configurable: false };"
3603
"Object.defineProperty(obj, 'x', desc);"
3605
result = script_define->Run();
3606
CHECK_EQ(result, v8_num(43));
3607
result = script_desc->Run();
3608
CHECK_EQ(result->BooleanValue(), false);
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");
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());
3625
Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3626
"Object.getOwnPropertyDescriptor( "
3628
"prop.configurable;"));
3629
Local<Value> result = script_desc->Run();
3630
CHECK_EQ(result->BooleanValue(), true);
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);"
3637
result = script_define->Run();
3638
CHECK_EQ(result, v8_num(42));
3641
result = script_desc->Run();
3642
CHECK_EQ(result->BooleanValue(), true);
3646
Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3647
" configurable: false };"
3648
"Object.defineProperty(obj, 'x', desc);"
3650
result = script_define->Run();
3651
CHECK_EQ(result, v8_num(43));
3652
result = script_desc->Run();
3654
CHECK_EQ(result->BooleanValue(), false);
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");
3664
static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3666
return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3670
THREADED_TEST(DefineAPIAccessorOnObject) {
3671
v8::HandleScope scope;
3672
Local<ObjectTemplate> templ = ObjectTemplate::New();
3673
LocalContext context;
3675
context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3676
CompileRun("var obj2 = {};");
3678
CHECK(CompileRun("obj1.x")->IsUndefined());
3679
CHECK(CompileRun("obj2.x")->IsUndefined());
3681
CHECK(GetGlobalProperty(&context, "obj1")->
3682
SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3684
ExpectString("obj1.x", "x");
3685
CHECK(CompileRun("obj2.x")->IsUndefined());
3687
CHECK(GetGlobalProperty(&context, "obj2")->
3688
SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3690
ExpectString("obj1.x", "x");
3691
ExpectString("obj2.x", "x");
3693
ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3694
ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3696
CompileRun("Object.defineProperty(obj1, 'x',"
3697
"{ get: function() { return 'y'; }, configurable: true })");
3699
ExpectString("obj1.x", "y");
3700
ExpectString("obj2.x", "x");
3702
CompileRun("Object.defineProperty(obj2, 'x',"
3703
"{ get: function() { return 'y'; }, configurable: true })");
3705
ExpectString("obj1.x", "y");
3706
ExpectString("obj2.x", "y");
3708
ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3709
ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
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")));
3716
ExpectString("obj1.x", "x");
3717
ExpectString("obj2.x", "x");
3719
ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3720
ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
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 })");
3728
ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3729
ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3731
ExpectString("obj1.x", "z");
3732
ExpectString("obj2.x", "z");
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")));
3739
ExpectString("obj1.x", "z");
3740
ExpectString("obj2.x", "z");
3744
THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3745
v8::HandleScope scope;
3746
Local<ObjectTemplate> templ = ObjectTemplate::New();
3747
LocalContext context;
3749
context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3750
CompileRun("var obj2 = {};");
3752
CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3755
v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3756
CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3759
v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3761
ExpectString("obj1.x", "x");
3762
ExpectString("obj2.x", "x");
3764
ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3765
ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
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")));
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");
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");
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"));
3800
THREADED_TEST(ElementAPIAccessor) {
3801
v8::HandleScope scope;
3802
Local<ObjectTemplate> templ = ObjectTemplate::New();
3803
LocalContext context;
3805
context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3806
CompileRun("var obj2 = {};");
3808
CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3812
CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3817
ExpectString("obj1[239]", "239");
3818
ExpectString("obj2[239]", "239");
3819
ExpectString("obj1['239']", "239");
3820
ExpectString("obj2['239']", "239");
3824
v8::Persistent<Value> xValue;
3827
static void SetXValue(Local<String> name,
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);
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());
3848
CHECK_EQ(v8_num(4), xValue);
3850
xValue = v8::Persistent<Value>();
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());
3865
CHECK_EQ(v8_num(4), xValue);
3867
xValue = v8::Persistent<Value>();
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++) {
3885
static v8::Handle<Value> XPropertyGetter(Local<String> property,
3886
const AccessorInfo& info) {
3887
ApiTestFuzzer::Fuzz();
3888
CHECK(info.Data()->IsUndefined());
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"));
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"));
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 };"
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"));
3937
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3938
v8::HandleScope scope;
3940
v8::Persistent<Context> context1 = Context::New();
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);
3949
// Force the object into the slow case.
3950
CompileRun("interceptor_obj.y = 0;"
3951
"delete interceptor_obj.y;");
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);"
3965
"get_x(interceptor_obj)");
3966
// Check that the interceptor was actually invoked.
3967
CHECK_EQ(result, v8_str("x"));
3970
// Return to the original context and force some object to the slow case
3971
// to cause the NormalizedMapCache to verify.
3973
CompileRun("var obj = { x : 0 }; delete obj.x;");
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>();
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);
4007
static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4008
const AccessorInfo& info) {
4009
ApiTestFuzzer::Fuzz();
4011
return v8::Handle<Value>(v8_num(625));
4013
return v8::Handle<Value>();
4017
static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4019
const AccessorInfo& info) {
4020
ApiTestFuzzer::Fuzz();
4024
return v8::Handle<Value>();
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;});"
4041
Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4042
"obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4044
"obj.foo;")); // This setter should not run, due to the interceptor.
4045
Local<Script> interceptor_getter_script = Script::Compile(v8_str(
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);
4058
static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4060
const AccessorInfo& info) {
4061
ApiTestFuzzer::Fuzz();
4063
return v8::Handle<Value>(v8_num(index));
4065
return v8::Handle<Value>();
4069
static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4072
const AccessorInfo& info) {
4073
ApiTestFuzzer::Fuzz();
4075
return v8::Handle<Value>(v8_num(index));
4077
return v8::Handle<Value>();
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));
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,
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; } "
4109
"for (x in obj) {key_count++;};"
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(
4115
result = key_count_check->Run();
4116
CHECK_EQ(v8_num(40013), result);
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(
4125
" return arguments;"
4127
"keys = f(0, 1, 2, 3);"
4129
Local<Value> result = indexed_property_names_script->Run();
4130
return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4134
static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4136
const AccessorInfo& info) {
4137
ApiTestFuzzer::Fuzz();
4139
return v8::Handle<Value>(v8_num(index));
4141
return v8::Handle<Value>();
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,
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);
4166
static v8::Handle<Value> IdentityIndexedPropertyGetter(
4168
const AccessorInfo& info) {
4169
return v8::Integer::NewFromUnsigned(index);
4173
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4174
v8::HandleScope scope;
4175
Local<ObjectTemplate> templ = ObjectTemplate::New();
4176
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4178
LocalContext context;
4179
context->Global()->Set(v8_str("obj"), templ->NewInstance());
4181
// Check fast object case.
4182
const char* fast_case_code =
4183
"Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4184
ExpectString(fast_case_code, "0");
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");
4194
THREADED_TEST(IndexedInterceptorWithNoSetter) {
4195
v8::HandleScope scope;
4196
Local<ObjectTemplate> templ = ObjectTemplate::New();
4197
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4199
LocalContext context;
4200
context->Global()->Set(v8_str("obj"), templ->NewInstance());
4205
" for (var i = 0; i < 100; i++) {"
4207
" if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4213
ExpectString(code, "PASSED");
4217
THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4218
v8::HandleScope scope;
4219
Local<ObjectTemplate> templ = ObjectTemplate::New();
4220
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4222
LocalContext context;
4223
Local<v8::Object> obj = templ->NewInstance();
4224
obj->TurnOnAccessCheck();
4225
context->Global()->Set(v8_str("obj"), obj);
4229
" for (var i = 0; i < 100; i++) {"
4231
" if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4237
ExpectString(code, "PASSED");
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);
4247
LocalContext context;
4248
Local<v8::Object> obj = templ->NewInstance();
4249
context->Global()->Set(v8_str("obj"), obj);
4253
" for (var i = 0; i < 100; i++) {"
4254
" var expected = i;"
4256
" %EnableAccessChecks(obj);"
4257
" expected = undefined;"
4260
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4261
" if (i == 5) %DisableAccessChecks(obj);"
4267
ExpectString(code, "PASSED");
4271
THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4272
v8::HandleScope scope;
4273
Local<ObjectTemplate> templ = ObjectTemplate::New();
4274
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4276
LocalContext context;
4277
Local<v8::Object> obj = templ->NewInstance();
4278
context->Global()->Set(v8_str("obj"), obj);
4282
" for (var i = 0; i < 100; i++) {"
4284
" if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4290
ExpectString(code, "PASSED");
4294
THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4295
v8::HandleScope scope;
4296
Local<ObjectTemplate> templ = ObjectTemplate::New();
4297
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4299
LocalContext context;
4300
Local<v8::Object> obj = templ->NewInstance();
4301
context->Global()->Set(v8_str("obj"), obj);
4305
" for (var i = 0; i < 100; i++) {"
4306
" var expected = i;"
4310
" expected = undefined;"
4313
" /* probe minimal Smi number on 32-bit platforms */"
4314
" key = -(1 << 30);"
4315
" expected = undefined;"
4318
" /* probe minimal Smi number on 64-bit platforms */"
4320
" expected = undefined;"
4322
" var v = obj[key];"
4323
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4329
ExpectString(code, "PASSED");
4333
THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4334
v8::HandleScope scope;
4335
Local<ObjectTemplate> templ = ObjectTemplate::New();
4336
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4338
LocalContext context;
4339
Local<v8::Object> obj = templ->NewInstance();
4340
context->Global()->Set(v8_str("obj"), obj);
4344
" for (var i = 0; i < 100; i++) {"
4345
" var expected = i;"
4349
" expected = undefined;"
4351
" var v = obj[key];"
4352
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4358
ExpectString(code, "PASSED");
4362
THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4363
v8::HandleScope scope;
4364
Local<ObjectTemplate> templ = ObjectTemplate::New();
4365
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4367
LocalContext context;
4368
Local<v8::Object> obj = templ->NewInstance();
4369
context->Global()->Set(v8_str("obj"), obj);
4372
"var original = obj;"
4374
" for (var i = 0; i < 100; i++) {"
4375
" var expected = i;"
4377
" obj = {50: 'foobar'};"
4378
" expected = 'foobar';"
4381
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4382
" if (i == 50) obj = original;"
4388
ExpectString(code, "PASSED");
4392
THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4393
v8::HandleScope scope;
4394
Local<ObjectTemplate> templ = ObjectTemplate::New();
4395
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4397
LocalContext context;
4398
Local<v8::Object> obj = templ->NewInstance();
4399
context->Global()->Set(v8_str("obj"), obj);
4402
"var original = obj;"
4404
" for (var i = 0; i < 100; i++) {"
4405
" var expected = i;"
4408
" expected = undefined;"
4411
" if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4412
" if (i == 5) obj = original;"
4418
ExpectString(code, "PASSED");
4422
THREADED_TEST(IndexedInterceptorOnProto) {
4423
v8::HandleScope scope;
4424
Local<ObjectTemplate> templ = ObjectTemplate::New();
4425
templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4427
LocalContext context;
4428
Local<v8::Object> obj = templ->NewInstance();
4429
context->Global()->Set(v8_str("obj"), obj);
4432
"var o = {__proto__: obj};"
4434
" for (var i = 0; i < 100; i++) {"
4436
" if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4442
ExpectString(code, "PASSED");
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));
4451
Local<String> password = v8_str("Password");
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());
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());
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());
4479
THREADED_TEST(FunctionPrototypeAcrossContexts) {
4480
// Make sure that functions created by cloning boilerplates cannot
4481
// communicate through their __proto__ field.
4483
v8::HandleScope scope;
4486
v8::Handle<v8::Object> global0 =
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));
4497
v8::Handle<v8::Object> global1 =
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")));
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.
4516
v8::HandleScope scope;
4518
Local<String> source = v8_str("Object.prototype.obj = 1234;"
4519
"Array.prototype.arr = 4567;"
4523
Local<Script> script0 = Script::Compile(source);
4524
CHECK_EQ(8901.0, script0->Run()->NumberValue());
4527
Local<Script> script1 = Script::Compile(source);
4528
CHECK_EQ(8901.0, script1->Run()->NumberValue());
4532
THREADED_TEST(UndetectableObject) {
4533
v8::HandleScope scope;
4536
Local<v8::FunctionTemplate> desc =
4537
v8::FunctionTemplate::New(0, v8::Handle<Value>());
4538
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4540
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4541
env->Global()->Set(v8_str("undetectable"), obj);
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);
4551
ExpectObject("true&&undetectable", obj);
4552
ExpectBoolean("false&&undetectable", false);
4553
ExpectBoolean("true||undetectable", true);
4554
ExpectObject("false||undetectable", obj);
4556
ExpectObject("undetectable&&true", obj);
4557
ExpectObject("undetectable&&false", obj);
4558
ExpectBoolean("undetectable||true", true);
4559
ExpectBoolean("undetectable||false", false);
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);
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);
4576
THREADED_TEST(VoidLiteral) {
4577
v8::HandleScope scope;
4580
Local<v8::FunctionTemplate> desc =
4581
v8::FunctionTemplate::New(0, v8::Handle<Value>());
4582
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4584
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4585
env->Global()->Set(v8_str("undetectable"), obj);
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);
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);
4601
ExpectString("(function() {"
4603
" return x === void 0;"
4605
" return e.toString();"
4608
"ReferenceError: x is not defined");
4609
ExpectString("(function() {"
4611
" return void 0 === x;"
4613
" return e.toString();"
4616
"ReferenceError: x is not defined");
4620
THREADED_TEST(ExtensibleOnUndetectable) {
4621
v8::HandleScope scope;
4624
Local<v8::FunctionTemplate> desc =
4625
v8::FunctionTemplate::New(0, v8::Handle<Value>());
4626
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4628
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4629
env->Global()->Set(v8_str("undetectable"), obj);
4631
Local<String> source = v8_str("undetectable.x = 42;"
4634
Local<Script> script = Script::Compile(source);
4636
CHECK_EQ(v8::Integer::New(42), script->Run());
4638
ExpectBoolean("Object.isExtensible(undetectable)", true);
4640
source = v8_str("Object.preventExtensions(undetectable);");
4641
script = Script::Compile(source);
4643
ExpectBoolean("Object.isExtensible(undetectable)", false);
4645
source = v8_str("undetectable.y = 2000;");
4646
script = Script::Compile(source);
4648
ExpectBoolean("undetectable.y == undefined", true);
4653
THREADED_TEST(UndetectableString) {
4654
v8::HandleScope scope;
4657
Local<String> obj = String::NewUndetectable("foo");
4658
env->Global()->Set(v8_str("undetectable"), obj);
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);
4668
ExpectObject("true&&undetectable", obj);
4669
ExpectBoolean("false&&undetectable", false);
4670
ExpectBoolean("true||undetectable", true);
4671
ExpectObject("false||undetectable", obj);
4673
ExpectObject("undetectable&&true", obj);
4674
ExpectObject("undetectable&&false", obj);
4675
ExpectBoolean("undetectable||true", true);
4676
ExpectBoolean("undetectable||false", false);
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);
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);
4693
TEST(UndetectableOptimized) {
4694
i::FLAG_allow_natives_syntax = true;
4695
v8::HandleScope scope;
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"));
4703
"function testBranch() {"
4704
" if (!%_IsUndetectableObject(undetectable)) throw 1;"
4705
" if (%_IsUndetectableObject(detectable)) throw 2;"
4707
"function testBool() {"
4708
" var b1 = !%_IsUndetectableObject(undetectable);"
4709
" var b2 = %_IsUndetectableObject(detectable);"
4714
"%OptimizeFunctionOnNextCall(testBranch);"
4715
"%OptimizeFunctionOnNextCall(testBool);"
4716
"for (var i = 0; i < 10; i++) {"
4725
template <typename T> static void USE(T) { }
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);
4734
Local<Script> scr = Script::Compile(v8_str(""));
4735
v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4737
Local<ObjectTemplate> templ = ObjectTemplate::New();
4738
v8::Persistent<ObjectTemplate> p_templ =
4739
v8::Persistent<ObjectTemplate>::New(templ);
4744
static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4745
ApiTestFuzzer::Fuzz();
4746
return v8::Undefined();
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();
4762
static const char* kSimpleExtensionSource =
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));
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));
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;
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);
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,
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);
4826
// Anything but exactly the right length should fail to compile.
4827
CHECK_EQ(0, *context);
4833
static const char* kEvalExtensionSource1 =
4834
"function UseEval1() {"
4836
" return eval('x');"
4840
static const char* kEvalExtensionSource2 =
4844
" return eval('x');"
4846
" this.UseEval2 = e;"
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));
4865
static const char* kWithExtensionSource1 =
4866
"function UseWith1() {"
4868
" with({x:87}) { return x; }"
4873
static const char* kWithExtensionSource2 =
4877
" with ({x:87}) { return x; }"
4879
" this.UseWith2 = e;"
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));
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));
4910
static const char* kSyntaxErrorInExtensionSource =
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());
4927
static const char* kExceptionInExtensionSource =
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());
4944
static const char* kNativeCallInExtensionSource =
4945
"function call_runtime_last_index_of(x) {"
4946
" return %StringLastIndexOf(x, 'bob', 10);"
4950
static const char* kNativeCallTest =
4951
"call_runtime_last_index_of('bobbobboellebobboellebobbob');";
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));
4967
class NativeFunctionExtension : public Extension {
4969
NativeFunctionExtension(const char* name,
4971
v8::InvocationCallback fun = &Echo)
4972
: Extension(name, source),
4975
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4976
v8::Handle<v8::String> name) {
4977
return v8::FunctionTemplate::New(function_);
4980
static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4981
if (args.Length() >= 1) return (args[0]);
4982
return v8::Undefined();
4985
v8::InvocationCallback function_;
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));
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());
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(
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());
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")));
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")));
5068
static const char* kExtensionTestScript =
5069
"native function A();"
5070
"native function B();"
5071
"native function C();"
5073
" if (i == 0) return A();"
5074
" if (i == 1) return B();"
5075
" if (i == 2) return C();"
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());
5089
class FunctionExtension : public Extension {
5091
FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5092
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5093
v8::Handle<String> name);
5097
static int lookup_count = 0;
5098
v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5099
v8::Handle<String> name) {
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));
5108
return v8::Handle<v8::FunctionTemplate>();
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());
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());
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;
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);
5172
static const char* js_code_causing_huge_string_flattening =
5174
"for (var i = 0; i < 30; i++) {"
5180
void OOMCallback(const char* location, const char* message) {
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;
5195
CHECK(false); // Should not return.
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();
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);
5217
int global_index = 0;
5221
Snorkel() { index_ = global_index++; }
5233
v8::Handle<Script> getScript() {
5234
if (script_.IsEmpty())
5235
script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5236
return Local<Script>(*script_);
5240
static const int kObjectCount = 256;
5242
v8::Persistent<v8::Object> objects_[kObjectCount];
5243
v8::Persistent<Script> script_;
5246
static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5247
Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5252
v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5253
const AccessorInfo& info) {
5255
static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5257
v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
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();
5266
whammy->objects_[whammy->cursor_] = global;
5267
whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5268
return whammy->getScript()->Run();
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,
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);
5283
v8::Handle<v8::Object> interceptor = templ->NewInstance();
5284
context->Global()->Set(v8_str("whammy"), interceptor);
5287
"for (var i = 0; i < 10000; i++) {"
5288
" var obj = whammy.length;"
5289
" if (last) last.next = obj;"
5294
v8::Handle<Value> result = CompileRun(code);
5295
CHECK_EQ(4.0, result->NumberValue());
5301
static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5304
*(reinterpret_cast<bool*>(data)) = true;
5308
THREADED_TEST(IndependentWeakHandle) {
5309
v8::Persistent<Context> context = Context::New();
5310
Context::Scope context_scope(context);
5312
v8::Persistent<v8::Object> object_a;
5315
v8::HandleScope handle_scope;
5316
object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
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);
5329
static void InvokeScavenge() {
5330
HEAP->PerformScavenge();
5334
static void InvokeMarkSweep() {
5335
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5339
static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5342
*(reinterpret_cast<bool*>(data)) = true;
5347
static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5350
*(reinterpret_cast<bool*>(data)) = true;
5355
THREADED_TEST(GCFromWeakCallbacks) {
5356
v8::Persistent<Context> context = Context::New();
5357
Context::Scope context_scope(context);
5359
static const int kNumberOfGCTypes = 2;
5360
v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5361
{&ForceScavenge, &ForceMarkSweep};
5363
typedef void (*GCInvoker)();
5364
GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
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;
5370
v8::HandleScope handle_scope;
5371
object = v8::Persistent<v8::Object>::New(v8::Object::New());
5373
bool disposed = false;
5374
object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5375
object.MarkIndependent();
5376
invoke_gc[outer_gc]();
5383
static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5385
*(reinterpret_cast<bool*>(data)) = true;
5389
THREADED_TEST(IndependentHandleRevival) {
5390
v8::Persistent<Context> context = Context::New();
5391
Context::Scope context_scope(context);
5393
v8::Persistent<v8::Object> object;
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);
5401
bool revived = false;
5402
object.MakeWeak(&revived, &RevivingCallback);
5403
object.MarkIndependent();
5404
HEAP->PerformScavenge();
5406
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
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));
5416
v8::Handle<Function> args_fun;
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();
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();
5443
static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5444
const AccessorInfo&) {
5445
return v8::Handle<Value>();
5449
static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5450
const AccessorInfo&) {
5451
return v8::Handle<Value>();
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
5461
return v8::False(); // intercepted, and don't delete the property
5465
static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5467
return v8::Handle<v8::Boolean>(); // not intercepted
5470
return v8::False(); // intercepted, and don't delete the property
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());
5486
CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5487
CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5489
CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5490
CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5492
CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5493
CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5495
CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5496
CHECK(v8_compile("k[4]")->Run()->IsUndefined());
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();
5507
return v8::Handle<Value>();
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>();
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"));
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"));
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(
5549
"k[4294967295] = 0;"
5551
"k[4294967296] = 0;"
5555
"k[30000000000] = 0;"
5558
"for (var prop in k) {"
5559
" result.push(prop);"
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)));
5595
int p_getter_count2;
5598
static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5599
ApiTestFuzzer::Fuzz();
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")));
5612
return v8::Undefined();
5616
static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5617
ApiTestFuzzer::Fuzz();
5618
LocalContext context;
5619
context->Global()->Set(v8_str("o1"), obj->NewInstance());
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;");
5632
static v8::Handle<Value> PGetter2(Local<String> name,
5633
const AccessorInfo& info) {
5634
ApiTestFuzzer::Fuzz();
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")));
5647
return v8::Undefined();
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);
5660
CHECK_EQ(40, p_getter_count);
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;
5670
CHECK_EQ(40, p_getter_count2);
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);
5693
static int StrCmp16(uint16_t* a, uint16_t* b) {
5695
if (*a == 0 && *b == 0) return 0;
5696
if (*a != *b) return 0 + *a - *b;
5703
static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5705
if (n-- == 0) return 0;
5706
if (*a == 0 && *b == 0) return 0;
5707
if (*a != *b) return 0 + *a - *b;
5714
int GetUtf8Length(Handle<String> str) {
5715
int len = str->Utf8Length();
5717
i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5718
i::FlattenString(istr);
5719
len = str->Utf8Length();
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.
5735
"for (var i = 0; i < 0xd800; i += 4) {"
5736
" left = left + String.fromCharCode(i);"
5740
"for (var i = 0; i < 0xd800; i += 4) {"
5741
" right = String.fromCharCode(i) + right;"
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>();
5747
CHECK_EQ(5, str2->Length());
5748
CHECK_EQ(0xd800 / kStride, left_tree->Length());
5749
CHECK_EQ(0xd800 / kStride, right_tree->Length());
5752
char utf8buf[0xd800 * 3];
5757
memset(utf8buf, 0x1, 1000);
5758
len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5760
CHECK_EQ(5, charlen);
5761
CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5763
memset(utf8buf, 0x1, 1000);
5764
len = str2->WriteUtf8(utf8buf, 8, &charlen);
5766
CHECK_EQ(5, charlen);
5767
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5769
memset(utf8buf, 0x1, 1000);
5770
len = str2->WriteUtf8(utf8buf, 7, &charlen);
5772
CHECK_EQ(4, charlen);
5773
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5775
memset(utf8buf, 0x1, 1000);
5776
len = str2->WriteUtf8(utf8buf, 6, &charlen);
5778
CHECK_EQ(4, charlen);
5779
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5781
memset(utf8buf, 0x1, 1000);
5782
len = str2->WriteUtf8(utf8buf, 5, &charlen);
5784
CHECK_EQ(4, charlen);
5785
CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5787
memset(utf8buf, 0x1, 1000);
5788
len = str2->WriteUtf8(utf8buf, 4, &charlen);
5790
CHECK_EQ(3, charlen);
5791
CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5793
memset(utf8buf, 0x1, 1000);
5794
len = str2->WriteUtf8(utf8buf, 3, &charlen);
5796
CHECK_EQ(3, charlen);
5797
CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5799
memset(utf8buf, 0x1, 1000);
5800
len = str2->WriteUtf8(utf8buf, 2, &charlen);
5802
CHECK_EQ(2, charlen);
5803
CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5805
memset(utf8buf, 0x1, sizeof(utf8buf));
5806
len = GetUtf8Length(left_tree);
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]);
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]);
5830
memset(buf, 0x1, sizeof(buf));
5831
memset(wbuf, 0x1, sizeof(wbuf));
5832
len = str->WriteAscii(buf);
5834
len = str->Write(wbuf);
5836
CHECK_EQ(0, strcmp("abcde", buf));
5837
uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5838
CHECK_EQ(0, StrCmp16(answer1, wbuf));
5840
memset(buf, 0x1, sizeof(buf));
5841
memset(wbuf, 0x1, sizeof(wbuf));
5842
len = str->WriteAscii(buf, 0, 4);
5844
len = str->Write(wbuf, 0, 4);
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));
5850
memset(buf, 0x1, sizeof(buf));
5851
memset(wbuf, 0x1, sizeof(wbuf));
5852
len = str->WriteAscii(buf, 0, 5);
5854
len = str->Write(wbuf, 0, 5);
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));
5860
memset(buf, 0x1, sizeof(buf));
5861
memset(wbuf, 0x1, sizeof(wbuf));
5862
len = str->WriteAscii(buf, 0, 6);
5864
len = str->Write(wbuf, 0, 6);
5866
CHECK_EQ(0, strcmp("abcde", buf));
5867
uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5868
CHECK_EQ(0, StrCmp16(answer4, wbuf));
5870
memset(buf, 0x1, sizeof(buf));
5871
memset(wbuf, 0x1, sizeof(wbuf));
5872
len = str->WriteAscii(buf, 4, -1);
5874
len = str->Write(wbuf, 4, -1);
5876
CHECK_EQ(0, strcmp("e", buf));
5877
uint16_t answer5[] = {'e', '\0'};
5878
CHECK_EQ(0, StrCmp16(answer5, wbuf));
5880
memset(buf, 0x1, sizeof(buf));
5881
memset(wbuf, 0x1, sizeof(wbuf));
5882
len = str->WriteAscii(buf, 4, 6);
5884
len = str->Write(wbuf, 4, 6);
5886
CHECK_EQ(0, strcmp("e", buf));
5887
CHECK_EQ(0, StrCmp16(answer5, wbuf));
5889
memset(buf, 0x1, sizeof(buf));
5890
memset(wbuf, 0x1, sizeof(wbuf));
5891
len = str->WriteAscii(buf, 4, 1);
5893
len = str->Write(wbuf, 4, 1);
5895
CHECK_EQ(0, strncmp("e\1", buf, 2));
5896
uint16_t answer6[] = {'e', 0x101};
5897
CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5899
memset(buf, 0x1, sizeof(buf));
5900
memset(wbuf, 0x1, sizeof(wbuf));
5901
len = str->WriteAscii(buf, 3, 1);
5903
len = str->Write(wbuf, 3, 1);
5905
CHECK_EQ(0, strncmp("d\1", buf, 2));
5906
uint16_t answer7[] = {'d', 0x101};
5907
CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5909
memset(wbuf, 0x1, sizeof(wbuf));
5911
len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
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));
5919
CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5921
memset(buf, 0x1, sizeof(buf));
5923
len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5925
CHECK_EQ('X', buf[5]);
5926
CHECK_EQ(0, strncmp("abcde", buf, 5));
5927
CHECK_NE(0, strcmp("abcde", buf));
5929
CHECK_EQ(0, strcmp("abcde", buf));
5931
memset(utf8buf, 0x1, sizeof(utf8buf));
5933
len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5934
String::NO_NULL_TERMINATION);
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"));
5941
CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5943
memset(utf8buf, 0x1, sizeof(utf8buf));
5945
len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5946
String::NO_NULL_TERMINATION);
5948
CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
5949
CHECK_EQ(5, charlen);
5951
CHECK_EQ(0, strcmp(utf8buf, "abcde"));
5953
memset(buf, 0x1, sizeof(buf));
5954
len = str3->WriteAscii(buf);
5956
CHECK_EQ(0, strcmp("abc def", buf));
5958
memset(buf, 0x1, sizeof(buf));
5959
len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
5961
CHECK_EQ(0, strcmp("abc", buf));
5962
CHECK_EQ(0, buf[3]);
5963
CHECK_EQ(0, strcmp("def", buf + 4));
5967
static void Utf16Helper(
5968
LocalContext& context,
5970
const char* lengths_name,
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);
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);
5996
static void WriteUtf8Helper(
5997
LocalContext& context,
5999
const char* lengths_name,
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)));
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));
6018
string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
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]);
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);
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));
6039
if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6041
if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
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);
6067
THREADED_TEST(Utf16) {
6068
LocalContext context;
6069
v8::HandleScope scope;
6071
"var pad = '01234567890123456789';"
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));"
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]);"
6093
"alens[5] -= 2;" // Here the surrogate pairs match up.
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);"
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);
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;
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));
6133
THREADED_TEST(Utf16Symbol) {
6134
LocalContext context;
6135
v8::HandleScope scope;
6137
Handle<String> symbol1 = v8::String::NewSymbol("abc");
6138
Handle<String> symbol2 = v8::String::NewSymbol("abc");
6139
CHECK(SameSymbol(symbol1, symbol2));
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.
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))));
6186
THREADED_TEST(ToArrayIndex) {
6187
v8::HandleScope scope;
6188
LocalContext context;
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());
6217
THREADED_TEST(ErrorConstruction) {
6218
v8::HandleScope scope;
6219
LocalContext context;
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));
6241
static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6242
ApiTestFuzzer::Fuzz();
6247
static void YSetter(Local<String> name,
6249
const AccessorInfo& info) {
6250
if (info.This()->Has(name)) {
6251
info.This()->Delete(name);
6253
info.This()->Set(name, value);
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());
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));
6295
// For use within the TestSecurityHandler() test.
6296
static bool g_security_callback_result = false;
6297
static bool NamedSecurityTestCallback(Local<v8::Object> global,
6299
v8::AccessType type,
6300
Local<Value> data) {
6301
// Always allow read access.
6302
if (type == v8::ACCESS_GET)
6305
// Sometimes allow other access.
6306
return g_security_callback_result;
6310
static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6312
v8::AccessType type,
6313
Local<Value> data) {
6314
// Always allow read access.
6315
if (type == v8::ACCESS_GET)
6318
// Sometimes allow other access.
6319
return g_security_callback_result;
6323
static int trouble_nesting = 0;
6324
static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6325
ApiTestFuzzer::Fuzz();
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);
6338
static int report_count = 0;
6339
static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6340
v8::Handle<Value>) {
6345
// Counts uncaught exceptions, but other tests running in parallel
6346
// also have uncaught exceptions.
6347
TEST(ApiUncaughtException) {
6349
v8::HandleScope scope;
6351
v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
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());
6357
Script::Compile(v8_str("function trouble_callee() {"
6361
"function trouble_caller() {"
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);
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);
6387
TEST(ExceptionInNativeScript) {
6388
v8::HandleScope scope;
6390
v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
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());
6396
Script::Compile(v8_str("function trouble() {\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);
6407
TEST(CompilationErrorUsingTryCatchHandler) {
6408
v8::HandleScope scope;
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());
6417
TEST(TryCatchFinallyUsingTryCatchHandler) {
6418
v8::HandleScope scope;
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());
6426
Script::Compile(v8_str("(function() {"
6427
"try { throw ''; } finally { return; }"
6429
CHECK(!try_catch.HasCaught());
6430
Script::Compile(v8_str("(function()"
6431
" { try { throw ''; } finally { throw 0; }"
6433
CHECK(try_catch.HasCaught());
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);
6448
v8::Handle<v8::Object> global0 = context0->Global();
6449
v8::Handle<Script> script0 = v8_compile("foo = 111");
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());
6457
// Create another environment, should fail security checks.
6458
v8::HandleScope scope1;
6460
v8::Persistent<Context> context1 =
6461
Context::New(NULL, global_template);
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;");
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());
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;");
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());
6500
THREADED_TEST(SecurityChecks) {
6501
v8::HandleScope handle_scope;
6503
v8::Persistent<Context> env2 = Context::New();
6505
Local<Value> foo = v8_str("foo");
6506
Local<Value> bar = v8_str("bar");
6508
// Set to the same domain.
6509
env1->SetSecurityToken(foo);
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());
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());
6521
// Switch to env2 in the same domain and invoke spy on env2.
6523
env2->SetSecurityToken(foo);
6525
Context::Scope scope_env2(env2);
6526
Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6527
CHECK(result->IsFunction());
6531
env2->SetSecurityToken(bar);
6532
Context::Scope scope_env2(env2);
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());
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();
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));
6558
current->Global()->Set(v8_str("other"), other->Global());
6559
CHECK(v8_compile("other")->Run()->Equals(other->Global()));
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());
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());
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());
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());
6613
THREADED_TEST(CrossDomainDelete) {
6614
v8::HandleScope handle_scope;
6616
v8::Persistent<Context> env2 = Context::New();
6618
Local<Value> foo = v8_str("foo");
6619
Local<Value> bar = v8_str("bar");
6621
// Set to the same domain.
6622
env1->SetSecurityToken(foo);
6623
env2->SetSecurityToken(foo);
6625
env1->Global()->Set(v8_str("prop"), v8_num(3));
6626
env2->Global()->Set(v8_str("env1"), env1->Global());
6628
// Change env2 to a different domain and delete env1.prop.
6629
env2->SetSecurityToken(bar);
6631
Context::Scope scope_env2(env2);
6632
Local<Value> result =
6633
Script::Compile(v8_str("delete env1.prop"))->Run();
6634
CHECK(result->IsFalse());
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());
6646
THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6647
v8::HandleScope handle_scope;
6649
v8::Persistent<Context> env2 = Context::New();
6651
Local<Value> foo = v8_str("foo");
6652
Local<Value> bar = v8_str("bar");
6654
// Set to the same domain.
6655
env1->SetSecurityToken(foo);
6656
env2->SetSecurityToken(foo);
6658
env1->Global()->Set(v8_str("prop"), v8_num(3));
6659
env2->Global()->Set(v8_str("env1"), env1->Global());
6661
// env1.prop is enumerable in env2.
6662
Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6664
Context::Scope scope_env2(env2);
6665
Local<Value> result = Script::Compile(test)->Run();
6666
CHECK(result->IsTrue());
6669
// Change env2 to a different domain and test again.
6670
env2->SetSecurityToken(bar);
6672
Context::Scope scope_env2(env2);
6673
Local<Value> result = Script::Compile(test)->Run();
6674
CHECK(result->IsFalse());
6681
THREADED_TEST(CrossDomainForIn) {
6682
v8::HandleScope handle_scope;
6684
v8::Persistent<Context> env2 = Context::New();
6686
Local<Value> foo = v8_str("foo");
6687
Local<Value> bar = v8_str("bar");
6689
// Set to the same domain.
6690
env1->SetSecurityToken(foo);
6691
env2->SetSecurityToken(foo);
6693
env1->Global()->Set(v8_str("prop"), v8_num(3));
6694
env2->Global()->Set(v8_str("env1"), env1->Global());
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
6700
env2->SetSecurityToken(bar);
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());
6714
TEST(ContextDetachGlobal) {
6715
v8::HandleScope handle_scope;
6717
v8::Persistent<Context> env2 = Context::New();
6719
Local<v8::Object> global1 = env1->Global();
6721
Local<Value> foo = v8_str("foo");
6723
// Set to the same domain.
6724
env1->SetSecurityToken(foo);
6725
env2->SetSecurityToken(foo);
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;}");
6735
env1->Global()->Set(v8_str("getProp"),
6736
global2->Get(v8_str("getProp")));
6738
// Detach env2's global, and reuse the global object of env2
6740
env2->DetachGlobal();
6741
// env2 has a new global object.
6742
CHECK(!env2->Global()->Equals(global2));
6744
v8::Persistent<Context> env3 =
6745
Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6746
env3->SetSecurityToken(v8_str("bar"));
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));
6757
// Call getProp in env1, and it should return the value 1
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());
6767
// Check that env3 is not accessible from env1
6769
Local<Value> r = global3->Get(v8_str("prop2"));
6770
CHECK(r->IsUndefined());
6778
TEST(DetachAndReattachGlobal) {
6779
v8::HandleScope scope;
6782
// Create second environment.
6783
v8::Persistent<Context> env2 = Context::New();
6785
Local<Value> foo = v8_str("foo");
6787
// Set same security token for env1 and env2.
6788
env1->SetSecurityToken(foo);
6789
env2->SetSecurityToken(foo);
6791
// Create a property on the global object in env2.
6793
v8::Context::Scope scope(env2);
6794
env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6797
// Create a reference to env2 global from env1 global.
6798
env1->Global()->Set(v8_str("other"), env2->Global());
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());
6805
// Hold on to global from env2 and detach global from env2.
6806
Local<v8::Object> global2 = env2->Global();
6807
env2->DetachGlobal();
6809
// Check that the global has been detached. No other.p property can
6811
result = CompileRun("other.p");
6812
CHECK(result->IsUndefined());
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());
6819
// Start by using the same security token for env3 as for env1 and env2.
6820
env3->SetSecurityToken(foo);
6822
// Create a property on the global object in env3.
6824
v8::Context::Scope scope(env3);
6825
env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
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());
6833
// Change security token for env3 to something different from env1 and env2.
6834
env3->SetSecurityToken(v8_str("bar"));
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());
6842
// Detach the global for env3 and reattach it to env2.
6843
env3->DetachGlobal();
6844
env2->ReattachGlobal(global2);
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());
6857
static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6858
static bool NamedAccessBlocker(Local<v8::Object> global,
6860
v8::AccessType type,
6861
Local<Value> data) {
6862
return Context::GetCurrent()->Global()->Equals(global) ||
6863
allowed_access_type[type];
6867
static bool IndexedAccessBlocker(Local<v8::Object> global,
6869
v8::AccessType type,
6870
Local<Value> data) {
6871
return Context::GetCurrent()->Global()->Equals(global) ||
6872
allowed_access_type[type];
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);
6883
static void EchoSetter(Local<String> name,
6885
const AccessorInfo&) {
6886
if (value->IsNumber())
6887
g_echo_value = value->Int32Value();
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();
6898
static void UnreachableSetter(Local<String>, Local<Value>,
6899
const AccessorInfo&) {
6900
CHECK(false); // This function should nto be called.
6904
TEST(AccessControl) {
6905
v8::HandleScope handle_scope;
6906
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6908
global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6909
IndexedAccessBlocker);
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));
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>(),
6924
// Create an environment
6925
v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6928
v8::Handle<v8::Object> global0 = context0->Global();
6930
// Define a property with JS getter and setter.
6932
"function getter() { return 'getter'; };\n"
6933
"function setter() { return 'setter'; }\n"
6934
"Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6936
Local<Value> getter = global0->Get(v8_str("getter"));
6937
Local<Value> setter = global0->Get(v8_str("setter"));
6939
// And define normal element.
6940
global0->Set(239, v8_str("239"));
6942
// Define an element with JS getter and setter.
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});");
6948
Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6949
Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6951
v8::HandleScope scope1;
6953
v8::Persistent<Context> context1 = Context::New();
6956
v8::Handle<v8::Object> global1 = context1->Global();
6957
global1->Set(v8_str("other"), global0);
6959
// Access blocked property.
6960
CompileRun("other.blocked_prop = 1");
6962
ExpectUndefined("other.blocked_prop");
6964
"Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6965
ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
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...
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;
6977
// Access blocked element.
6978
CompileRun("other[239] = 1");
6980
ExpectUndefined("other[239]");
6981
ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6982
ExpectFalse("propertyIsEnumerable.call(other, '239')");
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;
6993
// Access a property with JS accessor.
6994
CompileRun("other.js_accessor_p = 2");
6996
ExpectUndefined("other.js_accessor_p");
6998
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7000
// Enable ACCESS_HAS.
7001
allowed_access_type[v8::ACCESS_HAS] = true;
7002
ExpectUndefined("other.js_accessor_p");
7004
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7006
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7008
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7009
allowed_access_type[v8::ACCESS_HAS] = false;
7011
// Enable both ACCESS_HAS and ACCESS_GET.
7012
allowed_access_type[v8::ACCESS_HAS] = true;
7013
allowed_access_type[v8::ACCESS_GET] = true;
7015
ExpectString("other.js_accessor_p", "getter");
7017
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7019
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7021
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7023
allowed_access_type[v8::ACCESS_GET] = false;
7024
allowed_access_type[v8::ACCESS_HAS] = false;
7026
// Enable both ACCESS_HAS and ACCESS_SET.
7027
allowed_access_type[v8::ACCESS_HAS] = true;
7028
allowed_access_type[v8::ACCESS_SET] = true;
7030
ExpectUndefined("other.js_accessor_p");
7032
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7034
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7036
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7038
allowed_access_type[v8::ACCESS_SET] = false;
7039
allowed_access_type[v8::ACCESS_HAS] = false;
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;
7046
ExpectString("other.js_accessor_p", "getter");
7048
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7050
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7052
"Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7054
allowed_access_type[v8::ACCESS_SET] = false;
7055
allowed_access_type[v8::ACCESS_GET] = false;
7056
allowed_access_type[v8::ACCESS_HAS] = false;
7058
// Access an element with JS accessor.
7059
CompileRun("other[42] = 2");
7061
ExpectUndefined("other[42]");
7062
ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
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;
7072
// Enable both ACCESS_HAS and ACCESS_GET.
7073
allowed_access_type[v8::ACCESS_HAS] = true;
7074
allowed_access_type[v8::ACCESS_GET] = true;
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");
7081
allowed_access_type[v8::ACCESS_GET] = false;
7082
allowed_access_type[v8::ACCESS_HAS] = false;
7084
// Enable both ACCESS_HAS and ACCESS_SET.
7085
allowed_access_type[v8::ACCESS_HAS] = true;
7086
allowed_access_type[v8::ACCESS_SET] = true;
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");
7093
allowed_access_type[v8::ACCESS_SET] = false;
7094
allowed_access_type[v8::ACCESS_HAS] = false;
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;
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");
7106
allowed_access_type[v8::ACCESS_SET] = false;
7107
allowed_access_type[v8::ACCESS_GET] = false;
7108
allowed_access_type[v8::ACCESS_HAS] = false;
7110
v8::Handle<Value> value;
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);
7118
value = CompileRun("other.accessible_prop");
7119
CHECK(value->IsNumber());
7120
CHECK_EQ(3, value->Int32Value());
7123
"Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7124
CHECK(value->IsNumber());
7125
CHECK_EQ(3, value->Int32Value());
7127
value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
7128
CHECK(value->IsTrue());
7130
// Enumeration doesn't enumerate accessors from inaccessible objects in
7131
// the prototype chain even if the accessors are in themselves accessible.
7133
CompileRun("(function(){var obj = {'__proto__':other};"
7134
"for (var p in obj)"
7135
" if (p == 'accessible_prop' || p == 'blocked_prop') {"
7138
"return true;})()");
7139
CHECK(value->IsTrue());
7148
TEST(AccessControlES5) {
7149
v8::HandleScope handle_scope;
7150
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7152
global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7153
IndexedAccessBlocker);
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));
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>(),
7169
// Create an environment
7170
v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7173
v8::Handle<v8::Object> global0 = context0->Global();
7175
v8::Persistent<Context> context1 = Context::New();
7177
v8::Handle<v8::Object> global1 = context1->Global();
7178
global1->Set(v8_str("other"), global0);
7180
// Regression test for issue 1154.
7181
ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
7183
ExpectUndefined("other.blocked_prop");
7185
// Regression test for issue 1027.
7186
CompileRun("Object.defineProperty(\n"
7187
" other, 'blocked_prop', {configurable: false})");
7188
ExpectUndefined("other.blocked_prop");
7190
"Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7192
// Regression test for issue 1171.
7193
ExpectTrue("Object.isExtensible(other)");
7194
CompileRun("Object.preventExtensions(other)");
7195
ExpectTrue("Object.isExtensible(other)");
7197
// Object.seal and Object.freeze.
7198
CompileRun("Object.freeze(other)");
7199
ExpectTrue("Object.isExtensible(other)");
7201
CompileRun("Object.seal(other)");
7202
ExpectTrue("Object.isExtensible(other)");
7204
// Regression test for issue 1250.
7205
// Make sure that we can set the accessible accessors value using normal
7207
CompileRun("other.accessible_prop = 42");
7208
CHECK_EQ(42, g_echo_value);
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());
7218
static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7220
v8::AccessType type,
7221
Local<Value> data) {
7226
static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7228
v8::AccessType type,
7229
Local<Value> data) {
7234
THREADED_TEST(AccessControlGetOwnPropertyNames) {
7235
v8::HandleScope handle_scope;
7236
v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7238
obj_template->Set(v8_str("x"), v8::Integer::New(42));
7239
obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7240
GetOwnPropertyNamesIndexedBlocker);
7242
// Create an environment
7243
v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7246
v8::Handle<v8::Object> global0 = context0->Global();
7248
v8::HandleScope scope1;
7250
v8::Persistent<Context> context1 = Context::New();
7253
v8::Handle<v8::Object> global1 = context1->Global();
7254
global1->Set(v8_str("other"), global0);
7255
global1->Set(v8_str("object"), obj_template->NewInstance());
7257
v8::Handle<Value> value;
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());
7267
value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7268
CHECK(value->IsTrue());
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"));
7284
THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7285
v8::HandleScope handle_scope;
7286
v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7288
obj_template->Set(v8_str("x"), v8::Integer::New(42));
7289
obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7290
NamedPropertyEnumerator);
7292
LocalContext context;
7293
v8::Handle<v8::Object> global = context->Global();
7294
global->Set(v8_str("object"), obj_template->NewInstance());
7296
v8::Handle<Value> value =
7297
CompileRun("Object.getOwnPropertyNames(object).join(',')");
7298
CHECK_EQ(v8_str("x"), value);
7302
static v8::Handle<Value> ConstTenGetter(Local<String> name,
7303
const AccessorInfo& info) {
7308
THREADED_TEST(CrossDomainAccessors) {
7309
v8::HandleScope handle_scope;
7311
v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7313
v8::Handle<v8::ObjectTemplate> global_template =
7314
func_template->InstanceTemplate();
7316
v8::Handle<v8::ObjectTemplate> proto_template =
7317
func_template->PrototypeTemplate();
7319
// Add an accessor to proto that's accessible by cross-domain JS code.
7320
proto_template->SetAccessor(v8_str("accessible"),
7322
v8::Handle<Value>(),
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>(),
7331
v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7334
Local<v8::Object> global = context0->Global();
7335
// Add a normal property that shadows 'accessible'
7336
global->Set(v8_str("accessible"), v8_num(11));
7338
// Enter a new context.
7339
v8::HandleScope scope1;
7340
v8::Persistent<Context> context1 = Context::New();
7343
v8::Handle<v8::Object> global1 = context1->Global();
7344
global1->Set(v8_str("other"), global);
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());
7351
value = v8_compile("other.unreachable")->Run();
7352
CHECK(value->IsUndefined());
7361
static int named_access_count = 0;
7362
static int indexed_access_count = 0;
7364
static bool NamedAccessCounter(Local<v8::Object> global,
7366
v8::AccessType type,
7367
Local<Value> data) {
7368
named_access_count++;
7373
static bool IndexedAccessCounter(Local<v8::Object> global,
7375
v8::AccessType type,
7376
Local<Value> data) {
7377
indexed_access_count++;
7382
// This one is too easily disturbed by other tests.
7383
TEST(AccessControlIC) {
7384
named_access_count = 0;
7385
indexed_access_count = 0;
7387
v8::HandleScope handle_scope;
7389
// Create an environment.
7390
v8::Persistent<Context> context0 = Context::New();
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();
7400
v8::HandleScope scope1;
7402
// Create another environment.
7403
v8::Persistent<Context> context1 = Context::New();
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);
7410
v8::Handle<Value> value;
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;"
7418
value = CompileRun("testProp(obj)");
7419
CHECK(value->IsNumber());
7420
CHECK_EQ(1, value->Int32Value());
7421
CHECK_EQ(21, named_access_count);
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];"
7430
// Use obj which requires access checks. No inline caching is used
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);
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];"
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);
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();"
7468
CompileRun("testCallNormal(obj)");
7469
CHECK_EQ(74, named_access_count);
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);
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);
7496
static bool NamedAccessFlatten(Local<v8::Object> global,
7498
v8::AccessType type,
7499
Local<Value> data) {
7503
CHECK(name->IsString());
7505
memset(buf, 0x1, sizeof(buf));
7506
len = name.As<String>()->WriteAscii(buf);
7511
memset(buf, 0x1, sizeof(buf));
7512
len = name.As<String>()->Write(buf2);
7519
static bool IndexedAccessFlatten(Local<v8::Object> global,
7521
v8::AccessType type,
7522
Local<Value> data) {
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
7532
THREADED_TEST(AccessControlFlatten) {
7533
named_access_count = 0;
7534
indexed_access_count = 0;
7536
v8::HandleScope handle_scope;
7538
// Create an environment.
7539
v8::Persistent<Context> context0 = Context::New();
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();
7549
v8::HandleScope scope1;
7551
// Create another environment.
7552
v8::Persistent<Context> context1 = Context::New();
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);
7559
v8::Handle<Value> value;
7561
value = v8_compile("var p = 'as' + 'df';")->Run();
7562
value = v8_compile("obj[p];")->Run();
7571
static v8::Handle<Value> AccessControlNamedGetter(
7572
Local<String>, const AccessorInfo&) {
7573
return v8::Integer::New(42);
7577
static v8::Handle<Value> AccessControlNamedSetter(
7578
Local<String>, Local<Value> value, const AccessorInfo&) {
7583
static v8::Handle<Value> AccessControlIndexedGetter(
7585
const AccessorInfo& info) {
7590
static v8::Handle<Value> AccessControlIndexedSetter(
7591
uint32_t, Local<Value> value, const AccessorInfo&) {
7596
THREADED_TEST(AccessControlInterceptorIC) {
7597
named_access_count = 0;
7598
indexed_access_count = 0;
7600
v8::HandleScope handle_scope;
7602
// Create an environment.
7603
v8::Persistent<Context> context0 = Context::New();
7606
// Create an object that requires access-check functions to be
7607
// called for cross-domain access. The object also has interceptors
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();
7618
v8::HandleScope scope1;
7620
// Create another environment.
7621
v8::Persistent<Context> context1 = Context::New();
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);
7628
v8::Handle<Value> value;
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;"
7635
CHECK(value->IsNumber());
7636
CHECK_EQ(42, value->Int32Value());
7637
CHECK_EQ(21, named_access_count);
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];"
7643
CHECK(value->IsNumber());
7644
CHECK_EQ(42, value->Int32Value());
7645
CHECK_EQ(42, named_access_count);
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];"
7652
CHECK(value->IsNumber());
7653
CHECK_EQ(42, value->Int32Value());
7654
CHECK_EQ(21, indexed_access_count);
7663
THREADED_TEST(Version) {
7664
v8::V8::GetVersion();
7668
static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7669
ApiTestFuzzer::Fuzz();
7674
THREADED_TEST(InstanceProperties) {
7675
v8::HandleScope handle_scope;
7676
LocalContext context;
7678
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7679
Local<ObjectTemplate> instance = t->InstanceTemplate();
7681
instance->Set(v8_str("x"), v8_num(42));
7682
instance->Set(v8_str("f"),
7683
v8::FunctionTemplate::New(InstanceFunctionCallback));
7685
Local<Value> o = t->GetFunction()->NewInstance();
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());
7691
value = Script::Compile(v8_str("i.f()"))->Run();
7692
CHECK_EQ(12, value->Int32Value());
7696
static v8::Handle<Value>
7697
GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7698
ApiTestFuzzer::Fuzz();
7699
return v8::Handle<Value>();
7703
THREADED_TEST(GlobalObjectInstanceProperties) {
7704
v8::HandleScope handle_scope;
7706
Local<Value> global_object;
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));
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++) {"
7727
"for (var i = 0; i < 17; i++) wrapper(false);"
7729
"try { wrapper(true); } catch (e) { thrown = 1; };"
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();
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());
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());
7759
THREADED_TEST(CallKnownGlobalReceiver) {
7760
v8::HandleScope handle_scope;
7762
Local<Value> global_object;
7764
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7765
Local<ObjectTemplate> instance_template = t->InstanceTemplate();
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);"
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();
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();
7799
static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7800
ApiTestFuzzer::Fuzz();
7805
static int shadow_y;
7806
static int shadow_y_setter_call_count;
7807
static int shadow_y_getter_call_count;
7810
static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7811
shadow_y_setter_call_count++;
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);
7824
static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7825
const AccessorInfo& info) {
7826
return v8::Handle<Value>();
7830
static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7831
const AccessorInfo&) {
7832
return v8::Handle<Value>();
7836
THREADED_TEST(ShadowObject) {
7837
shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7838
v8::HandleScope handle_scope;
7840
Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7841
LocalContext context(NULL, global_template);
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();
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,
7855
proto->Set(v8_str("x"), v8_num(12));
7857
instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7859
Local<Value> o = t->GetFunction()->NewInstance();
7860
context->Global()->Set(v8_str("__proto__"), o);
7862
Local<Value> value =
7863
Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7864
CHECK(value->IsBoolean());
7865
CHECK(!value->BooleanValue());
7867
value = Script::Compile(v8_str("x"))->Run();
7868
CHECK_EQ(12, value->Int32Value());
7870
value = Script::Compile(v8_str("f()"))->Run();
7871
CHECK_EQ(42, value->Int32Value());
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());
7881
THREADED_TEST(HiddenPrototype) {
7882
v8::HandleScope handle_scope;
7883
LocalContext context;
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));
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();
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());
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
7919
Local<Value> proto = o0->Get(v8_str("__proto__"));
7920
CHECK(proto->IsObject());
7921
CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7925
THREADED_TEST(SetPrototype) {
7926
v8::HandleScope handle_scope;
7927
LocalContext context;
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));
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();
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());
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
7963
Local<Value> proto = o0->Get(v8_str("__proto__"));
7964
CHECK(proto->IsObject());
7965
CHECK_EQ(proto.As<v8::Object>(), o3);
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);
7972
Local<Value> proto1 = o1->GetPrototype();
7973
CHECK(proto1->IsObject());
7974
CHECK_EQ(proto1.As<v8::Object>(), o2);
7976
Local<Value> proto2 = o2->GetPrototype();
7977
CHECK(proto2->IsObject());
7978
CHECK_EQ(proto2.As<v8::Object>(), o3);
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;
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));
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));
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();
8016
// Create prototype chain of hidden prototypes.
8017
CHECK(o4->SetPrototype(o3));
8018
CHECK(o3->SetPrototype(o2));
8019
CHECK(o2->SetPrototype(o1));
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);");
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");
8036
THREADED_TEST(FunctionReadOnlyPrototype) {
8037
v8::HandleScope handle_scope;
8038
LocalContext context;
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.
8047
" descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
8048
" return (descriptor['writable'] == false);"
8049
"})()")->BooleanValue());
8050
CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8052
CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
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.
8060
" descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
8061
" return (descriptor['writable'] == true);"
8062
"})()")->BooleanValue());
8063
CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
8067
THREADED_TEST(SetPrototypeThrows) {
8068
v8::HandleScope handle_scope;
8069
LocalContext context;
8071
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8073
Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8074
Local<v8::Object> o1 = t->GetFunction()->NewInstance();
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());
8084
CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8088
THREADED_TEST(GetterSetterExceptions) {
8089
v8::HandleScope handle_scope;
8090
LocalContext context;
8092
"function Foo() { };"
8093
"function Throw() { throw 5; };"
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"));
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());
8126
static Handle<Value> ConstructorCallback(const Arguments& args) {
8127
ApiTestFuzzer::Fuzz();
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);
8141
This->Set(v8_str("a"), args[0]);
8146
static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8147
ApiTestFuzzer::Fuzz();
8152
THREADED_TEST(ConstructorForObject) {
8153
v8::HandleScope handle_scope;
8154
LocalContext context;
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;
8162
CHECK(!try_catch.HasCaught());
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());
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());
8179
// Call the Object's constructor with a String.
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);
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);
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());
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());
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());
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());
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;
8237
CHECK(!try_catch.HasCaught());
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);
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);
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;
8260
CHECK(!try_catch.HasCaught());
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);
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);
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;
8284
CHECK(!try_catch.HasCaught());
8286
CHECK(instance1->IsObject());
8287
CHECK(instance1->IsFunction());
8289
value = CompileRun("new obj4(28)");
8290
CHECK(!try_catch.HasCaught());
8291
CHECK(value->IsObject());
8293
Local<Value> args1[] = { v8_num(28) };
8294
value = instance1->CallAsConstructor(1, args1);
8295
CHECK(!try_catch.HasCaught());
8296
CHECK(value->IsObject());
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());
8304
CHECK(instance2->IsObject());
8305
CHECK(!instance2->IsFunction());
8307
value = CompileRun("new obj5(28)");
8308
CHECK(!try_catch.HasCaught());
8309
CHECK(!value->IsObject());
8311
Local<Value> args2[] = { v8_num(28) };
8312
value = instance2->CallAsConstructor(1, args2);
8313
CHECK(!try_catch.HasCaught());
8314
CHECK(!value->IsObject());
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(
8329
" (new Fun()).blah()"
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;"
8340
CHECK_EQ(0, value->Int32Value());
8344
THREADED_TEST(EvalAliasedDynamic) {
8345
v8::HandleScope scope;
8346
LocalContext current;
8348
// Tests where aliased eval can only be resolved dynamically.
8349
Local<Script> script =
8350
Script::Compile(v8_str("function f(x) { "
8352
" with (x) { return eval('foo'); }"
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);"));
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());
8365
v8::TryCatch try_catch;
8367
Script::Compile(v8_str("function f(x) { "
8369
" with (x) { return eval('bar'); }"
8371
"result4 = f(this)"));
8373
CHECK(!try_catch.HasCaught());
8374
CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8380
THREADED_TEST(CrossEval) {
8381
v8::HandleScope scope;
8383
LocalContext current;
8385
Local<String> token = v8_str("<security token>");
8386
other->SetSecurityToken(token);
8387
current->SetSecurityToken(token);
8389
// Set up reference from current to other.
8390
current->Global()->Set(v8_str("other"), other->Global());
8392
// Check that new variables are introduced in other context.
8393
Local<Script> script =
8394
Script::Compile(v8_str("other.eval('var foo = 1234')"));
8396
Local<Value> foo = other->Global()->Get(v8_str("foo"));
8397
CHECK_EQ(1234, foo->Int32Value());
8398
CHECK(!current->Global()->Has(v8_str("foo")));
8400
// Check that writing to non-existing properties introduces them in
8401
// the other context.
8403
Script::Compile(v8_str("other.eval('na = 1234')"));
8405
CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8406
CHECK(!current->Global()->Has(v8_str("na")));
8408
// Check that global variables in current context are not visible in other
8410
v8::TryCatch try_catch;
8412
Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
8413
Local<Value> result = script->Run();
8414
CHECK(try_catch.HasCaught());
8417
// Check that local variables in current context are not visible in other
8420
Script::Compile(v8_str("(function() { "
8422
" return other.eval('baz');"
8424
result = script->Run();
8425
CHECK(try_catch.HasCaught());
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());
8435
// Check that the 'this' pointer points to the global object evaluating
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());
8443
// Check that variables introduced in with-statement are not visible in
8446
Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8447
result = script->Run();
8448
CHECK(try_catch.HasCaught());
8451
// Check that you cannot use 'eval.call' with another object than the
8452
// current global object.
8454
Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8455
result = script->Run();
8456
CHECK(try_catch.HasCaught());
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;
8466
v8::Persistent<Context> context0 = Context::New();
8467
v8::Persistent<Context> context1 = Context::New();
8469
// Set up function in context0 that uses eval from context0.
8471
v8::Handle<v8::Value> fun =
8472
CompileRun("var x = 42;"
8475
" return function(s) { return e(s); }"
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.
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());
8498
THREADED_TEST(CrossLazyLoad) {
8499
v8::HandleScope scope;
8501
LocalContext current;
8503
Local<String> token = v8_str("<security token>");
8504
other->SetSecurityToken(token);
8505
current->SetSecurityToken(token);
8507
// Set up reference from current to other.
8508
current->Global()->Set(v8_str("other"), other->Global());
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());
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());
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
8533
THREADED_TEST(CallAsFunction) {
8534
v8::HandleScope scope;
8535
LocalContext context;
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;
8544
CHECK(!try_catch.HasCaught());
8546
value = CompileRun("obj(42)");
8547
CHECK(!try_catch.HasCaught());
8548
CHECK_EQ(42, value->Int32Value());
8550
value = CompileRun("(function(o){return o(49)})(obj)");
8551
CHECK(!try_catch.HasCaught());
8552
CHECK_EQ(49, value->Int32Value());
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());
8559
value = CompileRun("obj.call = Function.prototype.call;"
8560
"obj.call(null, 87)");
8561
CHECK(!try_catch.HasCaught());
8562
CHECK_EQ(87, value->Int32Value());
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());
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());
8576
// Check that the call-as-function handler can be called through
8578
value = CompileRun("new obj(43)");
8579
CHECK(!try_catch.HasCaught());
8580
CHECK_EQ(-43, value->Int32Value());
8582
// Check that the call-as-function handler can be called through
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());
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;
8597
CHECK(!try_catch.HasCaught());
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",
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);
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;
8626
CHECK(!try_catch.HasCaught());
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);
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);
8645
// Check whether a non-function object is callable.
8646
THREADED_TEST(CallableObject) {
8647
v8::HandleScope scope;
8648
LocalContext context;
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;
8655
CHECK(instance->IsCallable());
8656
CHECK(!try_catch.HasCaught());
8659
{ Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8660
Local<Object> instance = instance_template->NewInstance();
8661
v8::TryCatch try_catch;
8663
CHECK(!instance->IsCallable());
8664
CHECK(!try_catch.HasCaught());
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;
8673
CHECK(instance->IsCallable());
8674
CHECK(!try_catch.HasCaught());
8677
{ Local<FunctionTemplate> function_template = FunctionTemplate::New();
8678
Local<Function> function = function_template->GetFunction();
8679
Local<Object> instance = function;
8680
v8::TryCatch try_catch;
8682
CHECK(instance->IsCallable());
8683
CHECK(!try_catch.HasCaught());
8688
static int CountHandles() {
8689
return v8::HandleScope::NumberOfHandles();
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));
8699
return Recurse(depth - 1, iterations);
8703
THREADED_TEST(HandleIteration) {
8704
static const int kIterations = 500;
8705
static const int kNesting = 200;
8706
CHECK_EQ(0, CountHandles());
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());
8715
CHECK_EQ(kIterations, CountHandles());
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());
8723
CHECK_EQ(kIterations, CountHandles());
8725
CHECK_EQ(0, CountHandles());
8726
CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8730
static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8732
const AccessorInfo& info) {
8733
ApiTestFuzzer::Fuzz();
8734
return v8::Handle<Value>();
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());
8752
"o.hasOwnProperty('ostehaps');");
8753
CHECK_EQ(true, value->BooleanValue());
8755
"var p = new constructor();"
8756
"p.hasOwnProperty('ostehaps');");
8757
CHECK_EQ(false, value->BooleanValue());
8761
static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8763
const AccessorInfo& info) {
8764
ApiTestFuzzer::Fuzz();
8765
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8766
return v8::Handle<Value>();
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.
8780
"function makestr(size) {"
8782
" case 1: return 'f';"
8783
" case 2: return 'fo';"
8784
" case 3: return 'foo';"
8786
" return makestr(size >> 1) + makestr((size + 1) >> 1);"
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());
8799
typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8800
const AccessorInfo& info);
8803
static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
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());
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);
8827
// This test should hit the load IC for the interceptor case.
8828
THREADED_TEST(InterceptorLoadIC) {
8829
CheckInterceptorLoadIC(InterceptorLoadICGetter,
8831
"for (var i = 0; i < 1000; i++) {"
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).
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>();
8850
THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8851
CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8854
"for (var i = 0; i < 1000; i++) {"
8861
THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8862
CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8864
"o.__proto__ = { 'y': 239 };"
8865
"for (var i = 0; i < 1000; i++) {"
8866
" result = o.y + o.x;"
8872
THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8873
CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8875
"o.__proto__.y = 239;"
8876
"for (var i = 0; i < 1000; i++) {"
8877
" result = o.y + o.x;"
8883
THREADED_TEST(InterceptorLoadICUndefined) {
8884
CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8886
"for (var i = 0; i < 1000; i++) {"
8887
" result = (o.y == undefined) ? 239 : 42;"
8893
THREADED_TEST(InterceptorLoadICWithOverride) {
8894
CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8895
"fst = new Object(); fst.__proto__ = o;"
8896
"snd = new Object(); snd.__proto__ = fst;"
8898
"for (var i = 0; i < 1000; i++) {"
8903
"for (var i = 0; i < 1000; i++) {"
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;"
8918
"for (var i = 0; i < 1000; i++) {"
8920
// Now it should be ICed and keep a reference to x defined on proto
8923
"for (var i = 0; i < 1000; i++) {"
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;"
8940
"for (var i = 0; i < 1000; i++) {"
8942
// Now it should be ICed and keep a reference to y defined on proto2
8946
"for (var i = 0; i < 1000; i++) {"
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>();
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] = [];"
8975
"o.__proto__ = proto;"
8977
"for (var i = 0; i < 1000; i++) {"
8978
" result += receiver.x;"
8982
CHECK_EQ(1000, interceptor_load_not_handled_calls);
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.
8997
"this.y = 42;" // Assign on a global.
8999
"for (var i = 0; i < 10; i++) {"
9007
static void SetOnThis(Local<String> name,
9009
const AccessorInfo& info) {
9010
info.This()->ForceSet(name, value);
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());
9022
// Check the case when receiver and interceptor's holder
9023
// are the same objects.
9024
v8::Handle<Value> value = CompileRun(
9026
"for (var i = 0; i < 7; i++) {"
9029
CHECK_EQ(239, value->Int32Value());
9031
// Check the case when interceptor's holder is in proto chain
9034
"r = { __proto__: o };"
9036
"for (var i = 0; i < 7; i++) {"
9039
CHECK_EQ(239, value->Int32Value());
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);
9050
LocalContext context;
9051
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9052
context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9054
// Check the case when receiver and interceptor's holder
9055
// are the same objects.
9056
v8::Handle<Value> value = CompileRun(
9059
"for (var i = 0; i < 7; i++) {"
9060
" result = o.x + o.y;"
9062
CHECK_EQ(239 + 42, value->Int32Value());
9064
// Check the case when interceptor's holder is in proto chain
9067
"r = { __proto__: o };"
9069
"for (var i = 0; i < 7; i++) {"
9070
" result = r.x + r.y;"
9072
CHECK_EQ(239 + 42, value->Int32Value());
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);
9082
LocalContext context;
9083
context->Global()->Set(v8_str("o"), templ->NewInstance());
9085
v8::Handle<Value> value = CompileRun(
9086
"fst = new Object(); fst.__proto__ = o;"
9087
"snd = new Object(); snd.__proto__ = fst;"
9089
"for (var i = 0; i < 7; i++) {"
9094
"for (var i = 0; i < 7; i++) {"
9097
"result + result1");
9098
CHECK_EQ(239 + 42, value->Int32Value());
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);
9111
LocalContext context;
9112
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9113
context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9115
v8::Handle<Value> value = CompileRun(
9117
"for (var i = 0; i < 7; i++) {"
9119
// Now it should be ICed and keep a reference to x defined on p
9122
"for (var i = 0; i < 7; i++) {"
9126
CHECK_EQ(42 * 7, value->Int32Value());
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);
9139
LocalContext context;
9140
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9141
context->Global()->Set(v8_str("p"), templ_p->NewInstance());
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++) {"
9149
// Now it should be ICed and keep a reference to y defined on p
9153
"for (var i = 0; i < 10; i++) {"
9157
CHECK_EQ(42 * 10, value->Int32Value());
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);
9171
LocalContext context;
9172
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9173
context->Global()->Set(v8_str("p"), templ_p->NewInstance());
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
9184
"for (var i = 0; i < 10; i++) {"
9188
CHECK_EQ(42 * 10, value->Int32Value());
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);
9200
THREADED_TEST(InterceptorReturningZero) {
9201
CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9202
"o.x == undefined ? 1 : 0",
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());
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());
9225
"for (var i = 0; i < 1000; i++) {"
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++) {"
9242
CHECK_EQ(239 + 42, value->Int32Value());
9248
v8::Handle<Value> call_ic_function;
9249
v8::Handle<Value> call_ic_function2;
9250
v8::Handle<Value> call_ic_function3;
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;
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());
9268
v8_compile("function f(x) { return x + 1; }; f")->Run();
9269
v8::Handle<Value> value = CompileRun(
9271
"for (var i = 0; i < 1000; i++) {"
9272
" result = o.x(41);"
9274
CHECK_EQ(42, value->Int32Value());
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; };"
9289
"for (var i = 0; i < 7; i++) {"
9290
" result = o.x(41);"
9292
CHECK_EQ(42, value->Int32Value());
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;
9305
// This test checks that if interceptor provides a function,
9306
// even if we cached shadowed variant, interceptor's function
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());
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; };"
9319
"for (var i = 0; i < 1000; i++) {"
9320
" result = o.x(42);"
9322
CHECK_EQ(41, value->Int32Value());
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++) {"
9344
"proto1.y = function(x) { return x - 1; };"
9346
"for (var i = 0; i < 7; i++) {"
9347
" result += o.y(42);"
9349
CHECK_EQ(41 * 7, value->Int32Value());
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; };"
9366
"for (var i = 0; i < 1000; i++) {"
9367
" result = o.x(42);"
9369
CHECK_EQ(43, value->Int32Value());
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;
9380
return Local<Value>();
9384
// This test checks that if interceptor provides a function,
9385
// even if we cached constant function, interceptor's function
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());
9394
v8_compile("function f(x) { return x - 1; }; f")->Run();
9395
v8::Handle<Value> value = CompileRun(
9396
"function inc(x) { return x + 1; };"
9400
"for (var i = 0; i < 1000; i++) {"
9401
" result = o.x(42);"
9403
CHECK_EQ(41, value->Int32Value());
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;
9414
return Local<Value>();
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());
9428
v8_compile("function f(x) { return x - 1; }; f")->Run();
9429
v8::Handle<Value> value = CompileRun(
9430
"function inc(x) { return x + 1; };"
9435
" for (var i = 0; i < 1000; i++) {"
9436
" result = o.x(42);"
9443
"%OptimizeFunctionOnNextCall(test);"
9445
CHECK_EQ(41, value->Int32Value());
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; };"
9460
"proto1 = new Object();"
9461
"proto2 = new Object();"
9462
"o.__proto__ = proto1;"
9463
"proto1.__proto__ = proto2;"
9465
// Invoke it many times to compile a stub
9466
"for (var i = 0; i < 7; i++) {"
9469
"proto1.y = function(x) { return x - 1; };"
9471
"for (var i = 0; i < 7; i++) {"
9472
" result += o.y(42);"
9474
CHECK_EQ(41 * 7, value->Int32Value());
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; };"
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);"
9496
"this.y = function(x) { return x - 1; };"
9498
"for (var i = 0; i < 7; i++) {"
9499
" result += o.y(42);"
9501
CHECK_EQ(41 * 7, value->Int32Value());
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);
9511
LocalContext context;
9512
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9514
v8::Handle<Value> value = CompileRun(
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.
9523
" for (var i = 0; i < 10; i++) {"
9524
" result += o.parseFloat('239');"
9530
CHECK_EQ(239 * 10, value->Int32Value());
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()));
9538
if ((*call_count) % 20 == 0) {
9539
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
9541
return v8::Handle<Value>();
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);
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);
9567
// Helper to maximize the odds of object moving.
9568
static void GenerateSomeGarbage() {
9571
"for (var i = 0; i < 1000; i++) {"
9572
" garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9574
"garbage = undefined;");
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
9585
return v8::Handle<v8::Value>();
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.
9600
" for (var i = 1; i <= 30; i++) {"
9601
" nativeobject.callback();"
9608
v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9609
return v8::ThrowException(v8_str("g"));
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(
9625
" for (var i = 1; i <= 5; i++) {"
9626
" try { nativeobject.callback(); } catch (e) { result += e; }"
9630
CHECK_EQ(v8_str("ggggg"), result);
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();
9640
return v8::Handle<v8::Value>();
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());
9653
" for (var i = 0; i < 30; i++) o1.p1;"
9656
CHECK_EQ(30, p_getter_count);
9660
v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9661
Local<String> name, const v8::AccessorInfo& info) {
9662
return v8::ThrowException(v8_str("g"));
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(
9674
"for (var i = 0; i < 5; i++) {"
9675
" try { o1.p1; } catch (e) { result += e; }"
9678
CHECK_EQ(v8_str("ggggg"), result);
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());
9702
"for (var i = 0; i < 100; i++) {"
9703
" result = o.method(41);"
9705
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9706
CHECK_EQ(100, interceptor_call_count);
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());
9729
"var receiver = {};"
9730
"receiver.__proto__ = o;"
9732
"for (var i = 0; i < 100; i++) {"
9733
" result = receiver.method(41);"
9735
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9736
CHECK_EQ(100, interceptor_call_count);
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());
9759
"var receiver = {};"
9760
"receiver.__proto__ = o;"
9762
"var saved_result = 0;"
9763
"for (var i = 0; i < 100; i++) {"
9764
" result = receiver.method(41);"
9766
" saved_result = result;"
9767
" receiver = {method: function(x) { return x - 1 }};"
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);
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());
9795
"var receiver = {};"
9796
"receiver.__proto__ = o;"
9798
"var saved_result = 0;"
9799
"for (var i = 0; i < 100; i++) {"
9800
" result = receiver.method(41);"
9802
" saved_result = result;"
9803
" o.method = function(x) { return x - 1 };"
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);
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;
9832
"var receiver = {};"
9833
"receiver.__proto__ = o;"
9835
"var saved_result = 0;"
9836
"for (var i = 0; i < 100; i++) {"
9837
" result = receiver.method(41);"
9839
" saved_result = result;"
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);
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;
9871
"var receiver = {};"
9872
"receiver.__proto__ = o;"
9874
"var saved_result = 0;"
9875
"for (var i = 0; i < 100; i++) {"
9876
" result = receiver.method(41);"
9878
" saved_result = result;"
9879
" receiver = {method: receiver.method};"
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);
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());
9900
LocalContext context;
9901
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9902
GenerateSomeGarbage();
9903
context->Global()->Set(v8_str("o"), fun->NewInstance());
9906
"for (var i = 0; i < 100; i++) {"
9907
" result = o.method(41);"
9910
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
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());
9930
"var receiver = {};"
9931
"receiver.__proto__ = o;"
9933
"for (var i = 0; i < 100; i++) {"
9934
" result = receiver.method(41);"
9937
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
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());
9957
"var receiver = {};"
9958
"receiver.__proto__ = o;"
9960
"var saved_result = 0;"
9961
"for (var i = 0; i < 100; i++) {"
9962
" result = receiver.method(41);"
9964
" saved_result = result;"
9965
" receiver = {method: function(x) { return x - 1 }};"
9968
CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9969
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
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;
9990
"var receiver = {};"
9991
"receiver.__proto__ = o;"
9993
"var saved_result = 0;"
9994
"for (var i = 0; i < 100; i++) {"
9995
" result = receiver.method(41);"
9997
" saved_result = result;"
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());
10008
v8::Handle<Value> keyed_call_ic_function;
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;
10016
return v8::Handle<Value>();
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());
10029
"proto = new Object();"
10030
"proto.y = function(x) { return x + 1; };"
10031
"proto.z = function(x) { return x - 1; };"
10032
"o.__proto__ = proto;"
10034
"var method = 'y';"
10035
"for (var i = 0; i < 10; i++) {"
10036
" if (i == 5) { method = 'z'; };"
10037
" result += o[method](41);"
10039
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
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();
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;"
10062
"var method = 'x';"
10063
"for (var i = 0; i < 10; i++) {"
10064
" if (i == 5) { method = 'y'; };"
10065
" result += o[method](41);"
10067
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
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());
10080
"function inc(x) { return x + 1; };"
10082
"function dec(x) { return x - 1; };"
10084
"o.__proto__ = this;"
10085
"this.__proto__.x = inc;"
10086
"this.__proto__.y = dec;"
10088
"var method = 'x';"
10089
"for (var i = 0; i < 10; i++) {"
10090
" if (i == 5) { method = 'y'; };"
10091
" result += o[method](41);"
10093
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
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());
10106
"function len(x) { return x.length; };"
10107
"o.__proto__ = this;"
10108
"var m = 'parseFloat';"
10110
"for (var i = 0; i < 10; i++) {"
10113
" saved_result = result;"
10115
" result = o[m]('239');"
10117
CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10118
CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
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());
10130
"var o = new Object();"
10131
"o.__proto__ = proto;"
10132
"o.method = function(x) { return x + 1; };"
10133
"var m = 'method';"
10135
"for (var i = 0; i < 10; i++) {"
10136
" if (i == 5) { o.method = function(x) { return x - 1; }; };"
10137
" result += o[m](41);"
10139
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
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());
10152
"var proto = new Object();"
10153
"o.__proto__ = proto;"
10154
"proto.method = function(x) { return x + 1; };"
10155
"var m = 'method';"
10157
"for (var i = 0; i < 10; i++) {"
10158
" if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10159
" result += o[m](41);"
10161
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10165
static int interceptor_call_count = 0;
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;
10173
return v8::Handle<Value>();
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(
10188
" for (var i = 0; i < 1000; i++) {"
10189
" try { x; } catch(e) { return true; }"
10194
CHECK_EQ(true, value->BooleanValue());
10195
interceptor_call_count = 0;
10196
value = CompileRun(
10198
" for (var i = 0; i < 1000; i++) {"
10199
" try { x(42); } catch(e) { return true; }"
10204
CHECK_EQ(true, value->BooleanValue());
10208
static int interceptor_ic_exception_get_count = 0;
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;
10217
if (interceptor_ic_exception_get_count == 20) {
10218
return v8::ThrowException(v8_num(42));
10220
// Do not handle get for properties other than x.
10221
return v8::Handle<Value>();
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(
10235
" for (var i = 0; i < 100; i++) {"
10236
" try { x; } catch(e) { return true; }"
10241
CHECK_EQ(true, value->BooleanValue());
10242
interceptor_ic_exception_get_count = 0;
10243
value = CompileRun(
10245
" for (var i = 0; i < 100; i++) {"
10246
" try { x(42); } catch(e) { return true; }"
10251
CHECK_EQ(true, value->BooleanValue());
10255
static int interceptor_ic_exception_set_count = 0;
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));
10263
// Do not actually handle setting.
10264
return v8::Handle<Value>();
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(
10277
" for (var i = 0; i < 100; i++) {"
10278
" try { x = 42; } catch(e) { return true; }"
10283
CHECK_EQ(true, value->BooleanValue());
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());
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());
10317
THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10318
v8::HandleScope scope;
10319
v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10320
templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10322
env->Global()->Set(v8_str("obj"),
10323
templ->GetFunction()->NewInstance());
10324
ExpectTrue("obj.x === 42");
10325
ExpectTrue("!obj.propertyIsEnumerable('x')");
10329
static Handle<Value> ThrowingGetter(Local<String> name,
10330
const AccessorInfo& info) {
10331
ApiTestFuzzer::Fuzz();
10332
ThrowException(Handle<Value>());
10333
return Undefined();
10337
THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10339
LocalContext context;
10341
Local<FunctionTemplate> templ = FunctionTemplate::New();
10342
Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10343
instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10345
Local<Object> instance = templ->GetFunction()->NewInstance();
10347
Local<Object> another = Object::New();
10348
another->SetPrototype(instance);
10350
Local<Object> with_js_getter = CompileRun(
10352
"o.__defineGetter__('f', function() { throw undefined; });\n"
10353
"o\n").As<Object>();
10354
CHECK(!with_js_getter.IsEmpty());
10356
TryCatch try_catch;
10358
Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10359
CHECK(try_catch.HasCaught());
10361
CHECK(result.IsEmpty());
10363
result = another->GetRealNamedProperty(v8_str("f"));
10364
CHECK(try_catch.HasCaught());
10366
CHECK(result.IsEmpty());
10368
result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10369
CHECK(try_catch.HasCaught());
10371
CHECK(result.IsEmpty());
10373
result = another->Get(v8_str("f"));
10374
CHECK(try_catch.HasCaught());
10376
CHECK(result.IsEmpty());
10378
result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10379
CHECK(try_catch.HasCaught());
10381
CHECK(result.IsEmpty());
10383
result = with_js_getter->Get(v8_str("f"));
10384
CHECK(try_catch.HasCaught());
10386
CHECK(result.IsEmpty());
10390
static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10391
TryCatch try_catch;
10392
// Verboseness is important: it triggers message delivery which can call into
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();
10403
static int call_depth;
10406
static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10407
TryCatch try_catch;
10411
static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10412
if (--call_depth) CompileRun("throw 'ThrowInJS';");
10416
static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10417
if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
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();
10428
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10430
LocalContext context;
10432
Local<Function> func =
10433
FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10434
context->Global()->Set(v8_str("func"), func);
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);
10443
// Some small number to control number of times message handler should
10444
// throw an exception.
10447
"var thrown = false;\n"
10448
"try { func(); } catch(e) { thrown = true; }\n"
10450
if (callback != NULL) {
10451
V8::RemoveMessageListeners(callback);
10457
static v8::Handle<Value> ParentGetter(Local<String> name,
10458
const AccessorInfo& info) {
10459
ApiTestFuzzer::Fuzz();
10464
static v8::Handle<Value> ChildGetter(Local<String> name,
10465
const AccessorInfo& info) {
10466
ApiTestFuzzer::Fuzz();
10471
THREADED_TEST(Overriding) {
10472
i::FLAG_es5_readonly = true;
10473
v8::HandleScope scope;
10474
LocalContext context;
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);
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
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);
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);
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
10503
child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10504
v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10508
// Instantiate the child template.
10509
Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
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());
10519
// Check that 'h' cannot be shadowed.
10520
value = v8_compile("o.h = 3; o.h")->Run();
10521
CHECK_EQ(1, value->Int32Value());
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());
10529
static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10530
ApiTestFuzzer::Fuzz();
10531
return v8::Boolean::New(args.IsConstructCall());
10535
THREADED_TEST(IsConstructCall) {
10536
v8::HandleScope scope;
10538
// Function template with call handler.
10539
Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10540
templ->SetCallHandler(IsConstructHandler);
10542
LocalContext context;
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());
10552
THREADED_TEST(ObjectProtoToString) {
10553
v8::HandleScope scope;
10554
Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10555
templ->SetClassName(v8_str("MyClass"));
10557
LocalContext context;
10559
Local<String> customized_tostring = v8_str("customized toString");
10561
// Replace Object.prototype.toString
10562
v8_compile("Object.prototype.toString = function() {"
10563
" return 'customized toString';"
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));
10571
// ObjectProtoToString should not call replace toString function.
10572
value = instance->ObjectProtoToString();
10573
CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10576
value = context->Global()->ObjectProtoToString();
10577
CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
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]")));
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();
10597
Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10598
CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10599
v8_str("Parent")));
10601
Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10602
CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10605
Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10606
CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10607
v8_str("outer.inner")));
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_;
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();
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_) {
10635
printf("Stay with %s\n", test_name);
10638
if (kLogThreading) {
10639
printf("Switch from %s to %s\n",
10641
RegisterThreadedTest::nth(test_position)->name());
10643
current_ = test_position;
10644
RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10649
void ApiTestFuzzer::Run() {
10650
// When it is our turn...
10653
// ... get the V8 lock and start running the test.
10657
// This test finished.
10660
// If it was the last then signal that fact.
10661
if (active_tests_ == 0) {
10662
all_tests_done_->Signal();
10664
// Otherwise select a new test and start that.
10670
static unsigned linear_congruential_generator;
10673
void ApiTestFuzzer::SetUp(PartOfTest part) {
10674
linear_congruential_generator = i::FLAG_testing_prng_seed;
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);
10683
for (int i = 0; i < active_tests_; i++) {
10684
RegisterThreadedTest::nth(i)->fuzzer_->Start();
10689
static void CallTestNumber(int test_number) {
10690
(RegisterThreadedTest::nth(test_number)->callback())();
10694
void ApiTestFuzzer::RunAllTests() {
10695
// Set off the first test.
10698
// Wait till they are all done.
10699
all_tests_done_->Wait();
10703
int ApiTestFuzzer::GetNextTestNumber() {
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_);
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.
10726
void ApiTestFuzzer::TearDown() {
10728
for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10729
ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10730
if (fuzzer != NULL) fuzzer->Join();
10735
// Lets not be needlessly self-referential.
10737
ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
10738
ApiTestFuzzer::RunAllTests();
10739
ApiTestFuzzer::TearDown();
10743
ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
10744
ApiTestFuzzer::RunAllTests();
10745
ApiTestFuzzer::TearDown();
10749
ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
10750
ApiTestFuzzer::RunAllTests();
10751
ApiTestFuzzer::TearDown();
10755
ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
10756
ApiTestFuzzer::RunAllTests();
10757
ApiTestFuzzer::TearDown();
10760
void ApiTestFuzzer::CallTest() {
10762
printf("Start test %d\n", test_number_);
10763
CallTestNumber(test_number_);
10765
printf("End test %d\n", test_number_);
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;";
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());
10787
return v8::ThrowException(exception);
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;";
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");
10807
// These are locking tests that don't need to be run again
10808
// as part of the locking aggregation tests.
10809
TEST(NestedLockers) {
10811
CHECK(v8::Locker::IsLocked());
10812
v8::HandleScope scope;
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 () {"
10825
CHECK_EQ(91, script->Run()->Int32Value());
10829
// These are locking tests that don't need to be run again
10830
// as part of the locking aggregation tests.
10831
TEST(NestedLockersNoTryCatch) {
10833
v8::HandleScope scope;
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 () {"
10847
CHECK_EQ(91, script->Run()->Int32Value());
10851
THREADED_TEST(RecursiveLocking) {
10854
v8::Locker locker2;
10855
CHECK(v8::Locker::IsLocked());
10860
static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10861
ApiTestFuzzer::Fuzz();
10862
v8::Unlocker unlocker;
10863
return v8::Undefined();
10867
THREADED_TEST(LockUnlockLock) {
10870
v8::HandleScope scope;
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();"
10880
CHECK_EQ(42, script->Run()->Int32Value());
10884
v8::HandleScope scope;
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();"
10894
CHECK_EQ(42, script->Run()->Int32Value());
10899
static int GetGlobalObjectsCount() {
10900
i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10902
i::HeapIterator it;
10903
for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10904
if (object->IsJSGlobalObject()) count++;
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();
10919
if (count != expected) HEAP->TracePathToGlobal();
10921
CHECK_EQ(expected, count);
10925
TEST(DontLeakGlobalObjects) {
10926
// Regression test for issues 1139850 and 1174891.
10928
v8::V8::Initialize();
10930
for (int i = 0; i < 5; i++) {
10931
{ v8::HandleScope scope;
10932
LocalContext context;
10934
v8::V8::ContextDisposedNotification();
10935
CheckSurvivingGlobalObjectsCount(0);
10937
{ v8::HandleScope scope;
10938
LocalContext context;
10939
v8_compile("Date")->Run();
10941
v8::V8::ContextDisposedNotification();
10942
CheckSurvivingGlobalObjectsCount(0);
10944
{ v8::HandleScope scope;
10945
LocalContext context;
10946
v8_compile("/aaa/")->Run();
10948
v8::V8::ContextDisposedNotification();
10949
CheckSurvivingGlobalObjectsCount(0);
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();
10957
v8::V8::ContextDisposedNotification();
10958
CheckSurvivingGlobalObjectsCount(0);
10963
v8::Persistent<v8::Object> some_object;
10964
v8::Persistent<v8::Object> bad_handle;
10966
void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10967
v8::HandleScope scope;
10968
bad_handle = v8::Persistent<v8::Object>::New(some_object);
10973
THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10974
LocalContext context;
10976
v8::Persistent<v8::Object> handle1, handle2;
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());
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);
10989
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10993
v8::Persistent<v8::Object> to_be_disposed;
10995
void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10996
to_be_disposed.Dispose();
10997
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11002
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11003
LocalContext context;
11005
v8::Persistent<v8::Object> handle1, handle2;
11007
v8::HandleScope scope;
11008
handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11009
handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11011
handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11012
to_be_disposed = handle2;
11013
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11016
void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11020
void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11021
v8::HandleScope scope;
11022
v8::Persistent<v8::Object>::New(v8::Object::New());
11027
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11028
LocalContext context;
11030
v8::Persistent<v8::Object> handle1, handle2, handle3;
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());
11037
handle2.MakeWeak(NULL, DisposingCallback);
11038
handle3.MakeWeak(NULL, HandleCreatingCallback);
11039
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11043
THREADED_TEST(CheckForCrossContextObjectLiterals) {
11044
v8::V8::Initialize();
11047
const char* sources[nof] = {
11048
"try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11052
for (int i = 0; i < nof; i++) {
11053
const char* source = sources[i];
11054
{ v8::HandleScope scope;
11055
LocalContext context;
11056
CompileRun(source);
11058
{ v8::HandleScope scope;
11059
LocalContext context;
11060
CompileRun(source);
11066
static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11067
v8::HandleScope inner;
11069
v8::Handle<Value> three = v8_num(3);
11070
v8::Handle<Value> value = inner.Close(three);
11076
THREADED_TEST(NestedHandleScopeAndContexts) {
11077
v8::HandleScope outer;
11078
v8::Persistent<Context> env = Context::New();
11080
v8::Handle<Value> value = NestedScope(env);
11081
v8::Handle<String> str(value->ToString());
11082
CHECK(!str.IsEmpty());
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;
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);
11100
if (bar_ptr != NULL && code == (*bar_ptr)->code())
11103
if (foo_ptr != NULL && code == (*foo_ptr)->code())
11106
// TODO(siggi): Verify return_addr_location.
11107
// This can be done by capturing JitCodeEvents, but requires an ordered
11112
static void RunLoopInNewEnv() {
11116
v8::HandleScope outer;
11117
v8::Persistent<Context> env = Context::New();
11120
const char* script =
11123
" for (i = 0; i < 100; ++i)"
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"))));
11134
i::Handle<i::JSFunction> foo =
11135
i::Handle<i::JSFunction>::cast(
11136
v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11142
v8::Handle<v8::Value> value = CompileRun("bar();");
11143
CHECK(value->IsNumber());
11144
CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11146
// Test the optimized codegen path.
11147
value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11149
CHECK(value->IsNumber());
11150
CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11156
TEST(SetFunctionEntryHook) {
11157
i::FLAG_allow_natives_syntax = true;
11159
// Test setting and resetting the entry hook.
11160
// Nulling it should always succeed.
11161
CHECK(v8::V8::SetFunctionEntryHook(NULL));
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));
11167
CHECK(v8::V8::SetFunctionEntryHook(NULL));
11169
// Reset the entry count to zero and set the entry hook.
11172
CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11175
CHECK_EQ(2, bar_count);
11176
CHECK_EQ(200, foo_count);
11178
// Clear the entry hook and count.
11181
v8::V8::SetFunctionEntryHook(NULL);
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();
11187
// Verify that entry hooking is now disabled.
11189
CHECK_EQ(0u, bar_count);
11190
CHECK_EQ(0u, foo_count);
11194
static i::HashMap* code_map = NULL;
11195
static int saw_bar = 0;
11196
static int move_events = 0;
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
11204
static const char kPreamble[] = "LazyCompile:";
11205
static size_t kPreambleLen = sizeof(kPreamble) - 1;
11207
if (event->name.len < sizeof(kPreamble) - 1 ||
11208
strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
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 == '~') {
11224
if (tail_len != expected_len)
11227
return strncmp(tail, expected, expected_len) == 0;
11231
static void event_handler(const v8::JitCodeEvent* event) {
11232
CHECK(event != NULL);
11233
CHECK(code_map != NULL);
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),
11244
entry->value = reinterpret_cast<void*>(event->code_len);
11246
if (FunctionNameIs("bar", event)) {
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) {
11266
CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11267
code_map->Remove(event->code_start, hash);
11269
entry = code_map->Lookup(event->new_code_start,
11270
i::ComputePointerHash(event->new_code_start),
11272
CHECK(entry != NULL);
11273
entry->value = reinterpret_cast<void*>(event->code_len);
11278
case v8::JitCodeEvent::CODE_REMOVED:
11279
// Object/code removal events are currently not dispatched from the GC.
11283
// Impossible event.
11290
// Implemented in the test-alloc.cc test suite.
11291
void SimulateFullSpace(i::PagedSpace* space);
11294
static bool MatchPointers(void* key1, void* key2) {
11295
return key1 == key2;
11299
TEST(SetJitCodeEventHandler) {
11300
const char* script =
11303
" for (i = 0; i < 100; ++i)"
11307
"function foo(i) { return i * i; };"
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();
11316
i::HashMap code(MatchPointers);
11322
i::FLAG_stress_compaction = true;
11323
V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
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) {
11332
v8::Handle<v8::Script> compiled_script;
11334
i::AlwaysAllocateScope always_allocate;
11335
SimulateFullSpace(HEAP->code_space());
11336
compiled_script = v8_compile(script);
11338
compiled_script->Run();
11340
// Clear the compilation cache to get more wastage.
11341
ISOLATE->compilation_cache()->Clear();
11344
// Force code movement.
11345
HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11347
CHECK_LE(kIterations, saw_bar);
11348
CHECK_NE(0, move_events);
11351
V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11355
isolate->Dispose();
11357
// Do this in a new isolate.
11358
isolate = v8::Isolate::New();
11361
// Verify that we get callbacks for existing code objects when we
11362
// request enumeration of existing code.
11364
v8::HandleScope scope;
11366
CompileRun(script);
11368
// Now get code through initial iteration.
11369
i::HashMap code(MatchPointers);
11372
V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11373
V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
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());
11385
isolate->Dispose();
11389
static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
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)),
11399
CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11404
THREADED_TEST(DisposeEnteredContext) {
11405
v8::HandleScope scope;
11406
LocalContext outer;
11407
{ v8::Persistent<v8::Context> inner = v8::Context::New();
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));
11429
v8::Handle<v8::Object> result = templ->NewInstance();
11430
CHECK_EQ(1, result->InternalFieldCount());
11434
// If part of the threaded tests, this test makes ThreadingTest fail
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(
11446
v8::Handle<v8::Value> result = script->Run();
11447
CHECK(result.IsEmpty());
11451
static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11452
const char* resource_name,
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);
11473
THREADED_TEST(TryCatchSourceInfo) {
11474
v8::HandleScope scope;
11475
LocalContext context;
11476
v8::Handle<v8::String> source = v8::String::New(
11477
"function Foo() {\n"
11481
"function Bar() {\n"
11485
"function Baz() {\n"
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);
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);
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);
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());
11526
static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11527
ApiTestFuzzer::Fuzz();
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);
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());
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);
11565
void CheckOwnProperties(v8::Handle<v8::Value> val,
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);
11578
THREADED_TEST(PropertyEnumeration) {
11579
v8::HandleScope scope;
11580
LocalContext context;
11581
v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
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 };"
11589
"result;"))->Run();
11590
v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11591
CHECK_EQ(4, elms->Length());
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);
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);
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);
11605
const char* elmv3[] = {"w", "z", "x", "y"};
11606
CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
11608
const char* elmv4[] = {"w", "z"};
11609
CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
11612
THREADED_TEST(PropertyEnumeration2) {
11613
v8::HandleScope scope;
11614
LocalContext context;
11615
v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
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 };"
11623
"result;"))->Run();
11624
v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11625
CHECK_EQ(4, elms->Length());
11627
const char** elmv0 = NULL;
11628
CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
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);
11638
static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11640
v8::AccessType type,
11641
Local<Value> data) {
11642
return type != v8::ACCESS_SET;
11646
static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11648
v8::AccessType type,
11649
Local<Value> data) {
11650
return type != v8::ACCESS_SET;
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());
11668
static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11670
v8::AccessType type,
11671
Local<Value> data) {
11676
static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11678
v8::AccessType type,
11679
Local<Value> data) {
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.
11696
for (char i = '0'; i <= '9' ; i++) {
11698
for (char j = '0'; j <= '9'; j++) {
11700
for (char k = '0'; k <= '9'; k++) {
11703
templ->Set(v8_str(buf), v8::Number::New(k));
11708
Local<v8::Object> instance_1 = templ->NewInstance();
11709
context->Global()->Set(v8_str("obj_1"), instance_1);
11711
Local<Value> value_1 = CompileRun("obj_1.a");
11712
CHECK(value_1->IsUndefined());
11714
Local<v8::Object> instance_2 = templ->NewInstance();
11715
context->Global()->Set(v8_str("obj_2"), instance_2);
11717
Local<Value> value_2 = CompileRun("obj_2.a");
11718
CHECK(value_2->IsUndefined());
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());
11741
THREADED_TEST(TurnOnAccessCheck) {
11742
v8::HandleScope handle_scope;
11744
// Create an environment with access check to the global object disabled by
11746
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11747
global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11748
IndexedGetAccessBlocker,
11749
v8::Handle<v8::Value>(),
11751
v8::Persistent<Context> context = Context::New(NULL, global_template);
11752
Context::Scope context_scope(context);
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")));
11772
// Get the global object.
11773
v8::Handle<v8::Object> global = context->Global();
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
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)));
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)));
11789
// Detach the global and turn on access check.
11790
context->DetachGlobal();
11791
context->Global()->TurnOnAccessCheck();
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());
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());
11801
// No failing access check when just returning a constant.
11802
CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11806
static const char* kPropertyA = "a";
11807
static const char* kPropertyH = "h";
11809
static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
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));
11821
THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11822
v8::HandleScope handle_scope;
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
11827
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11828
global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11829
IndexedGetAccessBlocker,
11830
v8::Handle<v8::Value>(),
11832
v8::Persistent<Context> context = Context::New(NULL, global_template);
11833
Context::Scope context_scope(context);
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;}";
11843
CompileRun(source);
11844
Local<Function> f1;
11845
Local<Function> f2;
11846
Local<Function> g1;
11847
Local<Function> g2;
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")));
11855
// Get the global object.
11856
v8::Handle<v8::Object> global = context->Global();
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
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)));
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)));
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();
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());
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());
11885
// No failing access check when just returning a constant.
11886
CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
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());
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());
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());
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.
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());
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());
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());
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));
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);
11957
v8::ScriptData* deserialized_sd =
11958
v8::ScriptData::New(serialized_data, serialized_data_length);
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());
11966
delete deserialized_sd;
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);
11977
CHECK_EQ(0, sd->Length());
11983
// Attempts to deserialize bad data.
11984
TEST(PreCompileInvalidPreparseDataError) {
11985
v8::V8::Initialize();
11986
v8::HandleScope scope;
11987
LocalContext context;
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()));
12002
// Overwrite function bar's end position with 0.
12003
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12004
v8::TryCatch try_catch;
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",
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] =
12022
compiled_script = Script::New(source, NULL, sd);
12023
CHECK(!try_catch.HasCaught());
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;
12035
const char* cstring = "function foo(a) { return a+1; }";
12037
v8::ScriptData* sd_from_cstring =
12038
v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12040
TestAsciiResource* resource = new TestAsciiResource(cstring);
12041
v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
12042
v8::String::NewExternal(resource));
12044
v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12045
v8::String::New(cstring));
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()));
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()));
12058
delete sd_from_cstring;
12059
delete sd_from_external_string;
12060
delete sd_from_string;
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
12069
THREADED_TEST(DictionaryICLoadedFunction) {
12070
v8::HandleScope scope;
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('');");
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('')");
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();
12095
// Allow cross-domain access.
12096
Local<String> token = v8_str("<security token>");
12097
context0->SetSecurityToken(token);
12098
context1->SetSecurityToken(token);
12100
// Set an 'x' property on the Object prototype and define a
12101
// constructor function in context0.
12103
CompileRun("Object.prototype.x = 42; function C() {};");
12106
// Call the constructor function from context0 and check that the
12107
// result has the 'x' property.
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());
12115
// Dispose the contexts to allow them to be garbage collected.
12116
context0.Dispose();
12117
context1.Dispose();
12121
class RegExpInterruptTest {
12123
RegExpInterruptTest() : block_(NULL) {}
12124
~RegExpInterruptTest() { delete block_; }
12126
block_ = i::OS::CreateSemaphore(0);
12128
gc_during_regexp_ = 0;
12129
regexp_success_ = false;
12130
gc_success_ = false;
12131
GCThread gc_thread(this);
12133
v8::Locker::StartPreemption(1);
12135
LongRunningRegExp();
12137
v8::Unlocker unlock;
12140
v8::Locker::StopPreemption();
12141
CHECK(regexp_success_);
12142
CHECK(gc_success_);
12146
// Number of garbage collections required.
12147
static const int kRequiredGCs = 5;
12149
class GCThread : public i::Thread {
12151
explicit GCThread(RegExpInterruptTest* test)
12152
: Thread("GCThread"), test_(test) {}
12153
virtual void Run() {
12154
test_->CollectGarbage();
12157
RegExpInterruptTest* test_;
12160
void CollectGarbage() {
12162
while (gc_during_regexp_ < kRequiredGCs) {
12165
// TODO(lrn): Perhaps create some garbage before collecting.
12166
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12171
gc_success_ = true;
12174
void LongRunningRegExp() {
12175
block_->Signal(); // Enable garbage collection thread on next preemption.
12177
while (gc_during_regexp_ < kRequiredGCs) {
12178
int gc_before = gc_count_;
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.
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;
12205
int gc_after = gc_count_;
12206
gc_during_regexp_ += gc_after - gc_before;
12210
regexp_success_ = true;
12213
i::Semaphore* block_;
12215
int gc_during_regexp_;
12216
bool regexp_success_;
12221
// Test that a regular expression execution can be interrupted and
12222
// survive a garbage collection.
12223
TEST(RegExpInterruption) {
12225
v8::V8::Initialize();
12226
v8::HandleScope scope;
12227
Local<Context> local_env;
12230
local_env = env.local();
12233
// Local context should still be live.
12234
CHECK(!local_env.IsEmpty());
12235
local_env->Enter();
12237
// Should complete without problems.
12238
RegExpInterruptTest().RunTest();
12244
class ApplyInterruptTest {
12246
ApplyInterruptTest() : block_(NULL) {}
12247
~ApplyInterruptTest() { delete block_; }
12249
block_ = i::OS::CreateSemaphore(0);
12251
gc_during_apply_ = 0;
12252
apply_success_ = false;
12253
gc_success_ = false;
12254
GCThread gc_thread(this);
12256
v8::Locker::StartPreemption(1);
12258
LongRunningApply();
12260
v8::Unlocker unlock;
12263
v8::Locker::StopPreemption();
12264
CHECK(apply_success_);
12265
CHECK(gc_success_);
12269
// Number of garbage collections required.
12270
static const int kRequiredGCs = 2;
12272
class GCThread : public i::Thread {
12274
explicit GCThread(ApplyInterruptTest* test)
12275
: Thread("GCThread"), test_(test) {}
12276
virtual void Run() {
12277
test_->CollectGarbage();
12280
ApplyInterruptTest* test_;
12283
void CollectGarbage() {
12285
while (gc_during_apply_ < kRequiredGCs) {
12288
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12293
gc_success_ = true;
12296
void LongRunningApply() {
12299
while (gc_during_apply_ < kRequiredGCs) {
12300
int gc_before = gc_count_;
12302
const char* c_source =
12303
"function do_very_little(bar) {"
12306
"for (var i = 0; i < 100000; i++) {"
12307
" do_very_little.apply(this, ['bar']);"
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());
12315
int gc_after = gc_count_;
12316
gc_during_apply_ += gc_after - gc_before;
12319
apply_success_ = true;
12322
i::Semaphore* block_;
12324
int gc_during_apply_;
12325
bool apply_success_;
12330
// Test that nothing bad happens if we get a preemption just when we were
12331
// about to do an apply().
12332
TEST(ApplyInterruption) {
12334
v8::V8::Initialize();
12335
v8::HandleScope scope;
12336
Local<Context> local_env;
12339
local_env = env.local();
12342
// Local context should still be live.
12343
CHECK(!local_env.IsEmpty());
12344
local_env->Enter();
12346
// Should complete without problems.
12347
ApplyInterruptTest().RunTest();
12353
// Verify that we can clone an object
12354
TEST(ObjectClone) {
12355
v8::HandleScope scope;
12358
const char* sample =
12360
"rv.alpha = 'hello';" \
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"));
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")));
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")));
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")));
12387
class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12389
explicit AsciiVectorResource(i::Vector<const char> vector)
12391
virtual ~AsciiVectorResource() {}
12392
virtual size_t length() const { return data_.length(); }
12393
virtual const char* data() const { return data_.start(); }
12395
i::Vector<const char> data_;
12399
class UC16VectorResource : public v8::String::ExternalStringResource {
12401
explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12403
virtual ~UC16VectorResource() {}
12404
virtual size_t length() const { return data_.length(); }
12405
virtual const i::uc16* data() const { return data_.start(); }
12407
i::Vector<const i::uc16> data_;
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);
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);
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);
12443
v8::HandleScope scope;
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)));
12451
Local<String> lhs(v8::Utils::ToLocal(
12452
FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12453
Local<String> rhs(v8::Utils::ToLocal(
12454
FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12456
env->Global()->Set(v8_str("lhs"), lhs);
12457
env->Global()->Set(v8_str("rhs"), rhs);
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);");
12464
CHECK(!lhs->MayContainNonAscii());
12465
CHECK(!rhs->MayContainNonAscii());
12467
MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12468
MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
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());
12474
CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12475
CHECK_EQ(128, nchars);
12476
CHECK_EQ(0, strcmp(
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"));
12481
// Now do some stuff to make sure the strings are flattened, etc.
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")));
12501
i::DeleteArray(two_byte_string);
12505
TEST(CompileExternalTwoByteSource) {
12506
v8::HandleScope scope;
12507
LocalContext context;
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[] = {
12513
"-0.5", // This mainly testes PushBack in the Scanner.
12514
"--0.5", // This mainly testes PushBack in the Scanner.
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);
12531
class RegExpStringModificationTest {
12533
RegExpStringModificationTest()
12534
: block_(i::OS::CreateSemaphore(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_; }
12541
regexp_success_ = false;
12542
morph_success_ = false;
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';
12549
two_byte_content_[14] = 'b';
12551
// Create the input string for the regexp - the one we are going to change
12553
input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
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(
12562
i::kNonStrictMode)->ToObjectChecked();
12564
MorphThread morph_thread(this);
12565
morph_thread.Start();
12566
v8::Locker::StartPreemption(1);
12567
LongRunningRegExp();
12569
v8::Unlocker unlock;
12570
morph_thread.Join();
12572
v8::Locker::StopPreemption();
12573
CHECK(regexp_success_);
12574
CHECK(morph_success_);
12578
// Number of string modifications required.
12579
static const int kRequiredModifications = 5;
12580
static const int kMaxModifications = 100;
12582
class MorphThread : public i::Thread {
12584
explicit MorphThread(RegExpStringModificationTest* test)
12585
: Thread("MorphThread"), test_(test) {}
12586
virtual void Run() {
12587
test_->MorphString();
12590
RegExpStringModificationTest* test_;
12593
void MorphString() {
12595
while (morphs_during_regexp_ < kRequiredModifications &&
12596
morphs_ < kMaxModifications) {
12599
// Swap string between ascii and two-byte representation.
12600
i::String* string = *input_;
12601
MorphAString(string, &ascii_resource_, &uc16_resource_);
12606
morph_success_ = true;
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_;
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());
12625
int morphs_after = morphs_;
12626
morphs_during_regexp_ += morphs_after - morphs_before;
12628
regexp_success_ = true;
12631
i::uc16 two_byte_content_[15];
12632
i::Semaphore* block_;
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_;
12643
// Test that a regular expression execution can be interrupted and
12644
// the string changed without failing.
12645
TEST(RegExpStringModification) {
12647
v8::V8::Initialize();
12648
v8::HandleScope scope;
12649
Local<Context> local_env;
12652
local_env = env.local();
12655
// Local context should still be live.
12656
CHECK(!local_env.IsEmpty());
12657
local_env->Enter();
12659
// Should complete without problems.
12660
RegExpStringModificationTest().RunTest();
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);
12690
static int force_set_set_count = 0;
12691
static int force_set_get_count = 0;
12692
bool pass_on_get = false;
12694
static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12695
const v8::AccessorInfo& info) {
12696
force_set_get_count++;
12698
return v8::Handle<v8::Value>();
12700
return v8::Int32::New(3);
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++;
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();
12719
force_set_get_count = 0;
12720
force_set_set_count = 0;
12721
pass_on_get = false;
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();
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());
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
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);
12759
TEST(ForceSetWithInterceptor) {
12760
force_set_get_count = 0;
12761
force_set_set_count = 0;
12762
pass_on_get = false;
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();
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
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);
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();
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());
12825
static int force_delete_interceptor_count = 0;
12826
static bool pass_on_delete = false;
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>();
12841
THREADED_TEST(ForceDeleteWithInterceptor) {
12842
force_delete_interceptor_count = 0;
12843
pass_on_delete = false;
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();
12851
v8::Handle<v8::String> some_property = v8::String::New("a");
12852
global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12854
// Deleting a property should get intercepted and nothing should
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);
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
12892
CHECK_EQ(5, CompileRun("f()")->Int32Value());
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();
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"));
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);"
12914
CHECK_EQ(42, res->Int32Value());
12916
v8::Handle<v8::String> G_property = v8::String::New("G");
12917
CHECK(ctx1->Global()->ForceDelete(G_property));
12924
" return e.toString();"
12927
"ReferenceError: G is not defined");
12936
v8::Persistent<Context> calling_context0;
12937
v8::Persistent<Context> calling_context1;
12938
v8::Persistent<Context> calling_context2;
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);
12953
THREADED_TEST(GetCallingContext) {
12954
v8::HandleScope scope;
12956
calling_context0 = Context::New();
12957
calling_context1 = Context::New();
12958
calling_context2 = Context::New();
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);
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();
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();
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();
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();
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());
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());
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"
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());
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,
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);
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]);
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());
13085
result = CompileRun("var sum = 0;"
13086
"for (var i = 0; i < 8; i++) {"
13087
" sum += pixels[i] = pixels[i] = -i;"
13090
CHECK_EQ(-28, result->Int32Value());
13092
result = CompileRun("var sum = 0;"
13093
"for (var i = 0; i < 8; i++) {"
13094
" sum += pixels[i] = pixels[i] = 0;"
13097
CHECK_EQ(0, result->Int32Value());
13099
result = CompileRun("var sum = 0;"
13100
"for (var i = 0; i < 8; i++) {"
13101
" sum += pixels[i] = pixels[i] = 255;"
13104
CHECK_EQ(8 * 255, result->Int32Value());
13106
result = CompileRun("var sum = 0;"
13107
"for (var i = 0; i < 8; i++) {"
13108
" sum += pixels[i] = pixels[i] = 256 + i;"
13111
CHECK_EQ(2076, result->Int32Value());
13113
result = CompileRun("var sum = 0;"
13114
"for (var i = 0; i < 8; i++) {"
13115
" sum += pixels[i] = pixels[i] = i;"
13118
CHECK_EQ(28, result->Int32Value());
13120
result = CompileRun("var sum = 0;"
13121
"for (var i = 0; i < 8; i++) {"
13122
" sum += pixels[i];"
13125
CHECK_EQ(28, result->Int32Value());
13127
i::Handle<i::Smi> value(i::Smi::FromInt(2));
13128
i::Handle<i::Object> 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);
13136
i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13137
ASSERT(!no_failure.is_null());
13138
i::USE(no_failure);
13140
i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13141
*value.location() = i::Smi::FromInt(-1);
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());
13148
result = CompileRun("for (var i = 0; i < 8; i++) {"
13149
" pixels[i] = (i * 65) - 109;"
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());
13156
i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13158
i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13160
i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13162
i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13164
i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
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];"
13172
CHECK_EQ(984, result->Int32Value());
13174
result = CompileRun("for (var i = 0; i < 8; i++) {"
13175
" pixels[i] = (i * 1.1);"
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());
13188
result = CompileRun("for (var i = 0; i < 8; i++) {"
13189
" pixels[7] = undefined;"
13192
CHECK_EQ(0, result->Int32Value());
13193
CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13195
result = CompileRun("for (var i = 0; i < 8; i++) {"
13196
" pixels[6] = '2.3';"
13199
CHECK_EQ(2, result->Int32Value());
13200
CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13202
result = CompileRun("for (var i = 0; i < 8; i++) {"
13203
" pixels[5] = NaN;"
13206
CHECK_EQ(0, result->Int32Value());
13207
CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13209
result = CompileRun("for (var i = 0; i < 8; i++) {"
13210
" pixels[8] = Infinity;"
13213
CHECK_EQ(255, result->Int32Value());
13215
i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
13217
result = CompileRun("for (var i = 0; i < 8; i++) {"
13218
" pixels[9] = -Infinity;"
13221
CHECK_EQ(0, result->Int32Value());
13222
CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
13224
result = CompileRun("pixels[3] = 33;"
13225
"delete pixels[3];"
13227
CHECK_EQ(33, result->Int32Value());
13229
result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13230
"pixels[2] = 12; pixels[3] = 13;"
13231
"pixels.__defineGetter__('2',"
13232
"function() { return 120; });"
13234
CHECK_EQ(12, result->Int32Value());
13236
result = CompileRun("var js_array = new Array(40);"
13237
"js_array[0] = 77;"
13239
CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
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());
13248
result = CompileRun("pixels[1] = 23;");
13249
CHECK_EQ(23, result->Int32Value());
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]; }"
13258
CHECK_EQ(255, result->Int32Value());
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) {"
13264
" for (var j = 0; j < 256; j++) { sum += p[j]; }"
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);"
13275
CHECK_EQ(32640, result->Int32Value());
13277
// Make sure that pixel array ICs recognize out-of-bound accesses.
13278
result = CompileRun("function pa_load(p, start) {"
13280
" for (var j = start; j < 256; j++) { sum += p[j]; }"
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);"
13289
CHECK_EQ(0, result->Int32Value());
13291
// Make sure that generic ICs properly handles a pixel array.
13292
result = CompileRun("function pa_load(p) {"
13294
" for (var j = 0; j < 256; j++) { sum += p[j]; }"
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);"
13305
CHECK_EQ(32640, result->Int32Value());
13307
// Make sure that generic load ICs recognize out-of-bound accesses in
13309
result = CompileRun("function pa_load(p, start) {"
13311
" for (var j = start; j < 256; j++) { sum += p[j]; }"
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);"
13323
CHECK_EQ(0, result->Int32Value());
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) {"
13330
" for (var j = 0; j < 256; j++) { sum += p[j]; }"
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);"
13345
CHECK_EQ(32640, result->Int32Value());
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; }"
13351
"pa_store(pixels);"
13353
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13355
CHECK_EQ(48896, result->Int32Value());
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;"
13364
"pa_store(pixels,0);"
13365
"pa_store(pixels,-128);"
13367
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13369
CHECK_EQ(65280, result->Int32Value());
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;"
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);"
13384
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13386
CHECK_EQ(65280, result->Int32Value());
13388
// Make sure that the generic keyed store stub clamps pixel array values
13390
result = CompileRun("function pa_store(p) {"
13391
" for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13393
"pa_store(pixels);"
13394
"just_ints = new Object();"
13395
"pa_store(just_ints);"
13396
"pa_store(pixels);"
13398
"for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13400
CHECK_EQ(48896, result->Int32Value());
13402
// Make sure that pixel array loads are optimized by crankshaft.
13403
result = CompileRun("function pa_load(p) {"
13405
" for (var i=0; i<256; ++i) {"
13410
"for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13411
"for (var i = 0; i < 5000; ++i) {"
13412
" result = pa_load(pixels);"
13415
CHECK_EQ(32640, result->Int32Value());
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; }"
13421
"function pa_load(p) {"
13423
" for (var i=0; i<256; ++i) {"
13428
"for (var i = 0; i < 5000; ++i) {"
13429
" pa_init(pixels);"
13431
"result = pa_load(pixels);"
13433
CHECK_EQ(32640, result->Int32Value());
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());
13454
static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13456
const AccessorInfo& info) {
13457
ApiTestFuzzer::Fuzz();
13458
return v8::Handle<Value>();
13462
static v8::Handle<Value> NotHandledIndexedPropertySetter(
13464
Local<Value> value,
13465
const AccessorInfo& info) {
13466
ApiTestFuzzer::Fuzz();
13467
return v8::Handle<Value>();
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,
13481
for (int i = 0; i < kElementCount; i++) {
13482
pixels->set(i, i % 256);
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;"
13497
CHECK_EQ(-28, result->Int32Value());
13498
result = CompileRun("pixels.hasOwnProperty('1')");
13499
CHECK(result->BooleanValue());
13504
static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13505
switch (array_type) {
13506
case v8::kExternalByteArray:
13507
case v8::kExternalUnsignedByteArray:
13508
case v8::kExternalPixelArray:
13511
case v8::kExternalShortArray:
13512
case v8::kExternalUnsignedShortArray:
13515
case v8::kExternalIntArray:
13516
case v8::kExternalUnsignedIntArray:
13517
case v8::kExternalFloatArray:
13520
case v8::kExternalDoubleArray:
13532
template <class ExternalArrayClass, class ElementType>
13533
static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
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));
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]));
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,
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());
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;"
13579
CHECK_EQ(-28, result->Int32Value());
13581
// Check assigned smis
13582
result = CompileRun("for (var i = 0; i < 8; i++) {"
13583
" ext_array[i] = i;"
13586
"for (var i = 0; i < 8; i++) {"
13587
" sum += ext_array[i];"
13590
CHECK_EQ(28, result->Int32Value());
13592
// Check assigned smis in reverse order
13593
result = CompileRun("for (var i = 8; --i >= 0; ) {"
13594
" ext_array[i] = i;"
13597
"for (var i = 0; i < 8; i++) {"
13598
" sum += ext_array[i];"
13601
CHECK_EQ(28, result->Int32Value());
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);"
13609
CHECK_EQ(-28, result->Int32Value());
13611
// Check assigned HeapNumbers
13612
result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13613
" ext_array[i] = (i * 0.5);"
13616
"for (var i = 0; i < 16; i+=2) {"
13617
" sum += ext_array[i];"
13620
CHECK_EQ(28, result->Int32Value());
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);"
13627
"for (var i = 0; i < 16; i+=2) {"
13628
" sum += ext_array[i];"
13631
CHECK_EQ(28, result->Int32Value());
13633
i::ScopedVector<char> test_buf(1024);
13635
// Check legal boundary conditions.
13636
// The repeated loads and stores ensure the ICs are exercised.
13637
const char* boundary_program =
13639
"for (var i = 0; i < 16; i++) {"
13640
" ext_array[i] = %lld;"
13642
" res = ext_array[i];"
13646
i::OS::SNPrintF(test_buf,
13649
result = CompileRun(test_buf.start());
13650
CHECK_EQ(low, result->IntegerValue());
13652
i::OS::SNPrintF(test_buf,
13655
result = CompileRun(test_buf.start());
13656
CHECK_EQ(high, result->IntegerValue());
13658
// Check misprediction of type in IC.
13659
result = CompileRun("var tmp_array = ext_array;"
13661
"for (var i = 0; i < 8; i++) {"
13662
" tmp_array[i] = i;"
13663
" sum += tmp_array[i];"
13669
// Force GC to trigger verification.
13670
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13671
CHECK_EQ(28, result->Int32Value());
13673
// Make sure out-of-range loads do not throw.
13674
i::OS::SNPrintF(test_buf,
13675
"var caught_exception = false;"
13679
" caught_exception = true;"
13681
"caught_exception;",
13683
result = CompileRun(test_buf.start());
13684
CHECK_EQ(false, result->BooleanValue());
13686
// Make sure out-of-range stores do not throw.
13687
i::OS::SNPrintF(test_buf,
13688
"var caught_exception = false;"
13690
" ext_array[%d] = 1;"
13692
" caught_exception = true;"
13694
"caught_exception;",
13696
result = CompileRun(test_buf.start());
13697
CHECK_EQ(false, result->BooleanValue());
13699
// Check other boundary conditions, values and operations.
13700
result = CompileRun("for (var i = 0; i < 8; i++) {"
13701
" ext_array[7] = undefined;"
13704
CHECK_EQ(0, result->Int32Value());
13705
if (array_type == v8::kExternalDoubleArray ||
13706
array_type == v8::kExternalFloatArray) {
13708
static_cast<int>(i::OS::nan_value()),
13709
static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13711
CHECK_EQ(0, static_cast<int>(
13712
jsobj->GetElement(7)->ToObjectChecked()->Number()));
13715
result = CompileRun("for (var i = 0; i < 8; i++) {"
13716
" ext_array[6] = '2.3';"
13719
CHECK_EQ(2, result->Int32Value());
13721
2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
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;"
13730
"for (var i = 0; i < 8; i++) {"
13731
" ext_array[i] = NaN;"
13734
CHECK_EQ(0, result->Int32Value());
13736
i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13738
result = CompileRun("for (var i = 0; i < 8; i++) {"
13739
" ext_array[i] = 5;"
13741
"for (var i = 0; i < 8; i++) {"
13742
" ext_array[i] = Infinity;"
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());
13751
result = CompileRun("for (var i = 0; i < 8; i++) {"
13752
" ext_array[i] = 5;"
13754
"for (var i = 0; i < 8; i++) {"
13755
" ext_array[i] = -Infinity;"
13758
CHECK_EQ(0, result->Int32Value());
13760
i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
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];";
13773
(array_type == v8::kExternalUnsignedByteArray ||
13774
array_type == v8::kExternalUnsignedShortArray ||
13775
array_type == v8::kExternalUnsignedIntArray);
13776
bool is_pixel_data = array_type == v8::kExternalPixelArray;
13778
i::OS::SNPrintF(test_buf,
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];"
13785
" all_passed = all_passed &&"
13786
" (ext_array[5] == expected_results[i]);"
13791
(is_pixel_data ? pixel_data : signed_data)));
13792
result = CompileRun(test_buf.start());
13793
CHECK_EQ(true, result->BooleanValue());
13796
for (int i = 0; i < kElementCount; i++) {
13797
array->set(i, static_cast<ElementType>(i));
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);"
13808
"for (var i=0;i<10000;++i) {"
13809
" sum=ee_op_test_complex_func(sum);"
13812
CHECK_EQ(16000000, result->Int32Value());
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]);"
13823
"for (var i=0;i<10000;++i) {"
13824
" sum=ee_op_test_count_func(sum);"
13827
CHECK_EQ(16000000, result->Int32Value());
13829
result = CompileRun("ext_array[3] = 33;"
13830
"delete ext_array[3];"
13832
CHECK_EQ(33, result->Int32Value());
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; });"
13839
CHECK_EQ(12, result->Int32Value());
13841
result = CompileRun("var js_array = new Array(40);"
13842
"js_array[0] = 77;"
13844
CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
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());
13853
result = CompileRun("ext_array[1] = 23;");
13854
CHECK_EQ(23, result->Int32Value());
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.
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,
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++) {
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;
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;
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;
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
13897
result = CompileRun("var failed = false;"
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) {"
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) {"
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) {"
13926
CHECK_EQ(true, result->BooleanValue());
13927
free(large_array_data);
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());
13937
// Property "" set after the external array is associated with the object.
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,
13946
context->Global()->Set(v8_str("ext_array"), obj2);
13947
result = CompileRun("ext_array['']");
13948
CHECK_EQ(1503, result->Int32Value());
13951
// Property "" set after the external array is associated with the object.
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,
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());
13965
// Should reuse the map from previous test.
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,
13974
context->Global()->Set(v8_str("ext_array"), obj2);
13975
result = CompileRun("ext_array['']");
13978
// Property "" is a constant function that shouldn't not be interfered with
13979
// when an external array is set.
13981
v8::Handle<v8::Object> obj2 = v8::Object::New();
13983
obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
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['']();");
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,
13997
context->Global()->Set(v8_str("ext_array"), obj3);
14000
// If a external array transition is in the map, it should get clobbered
14001
// by a constant function.
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,
14010
// Add a constant function to the same map that just got an external array
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['']();");
14023
THREADED_TEST(ExternalByteArray) {
14024
ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
14025
v8::kExternalByteArray,
14031
THREADED_TEST(ExternalUnsignedByteArray) {
14032
ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
14033
v8::kExternalUnsignedByteArray,
14039
THREADED_TEST(ExternalPixelArray) {
14040
ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14041
v8::kExternalPixelArray,
14047
THREADED_TEST(ExternalShortArray) {
14048
ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
14049
v8::kExternalShortArray,
14055
THREADED_TEST(ExternalUnsignedShortArray) {
14056
ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
14057
v8::kExternalUnsignedShortArray,
14063
THREADED_TEST(ExternalIntArray) {
14064
ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
14065
v8::kExternalIntArray,
14066
INT_MIN, // -2147483648
14067
INT_MAX); // 2147483647
14071
THREADED_TEST(ExternalUnsignedIntArray) {
14072
ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
14073
v8::kExternalUnsignedIntArray,
14075
UINT_MAX); // 4294967295
14079
THREADED_TEST(ExternalFloatArray) {
14080
ExternalArrayTestHelper<i::ExternalFloatArray, float>(
14081
v8::kExternalFloatArray,
14087
THREADED_TEST(ExternalDoubleArray) {
14088
ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14089
v8::kExternalDoubleArray,
14095
THREADED_TEST(ExternalArrays) {
14096
TestExternalByteArray();
14097
TestExternalUnsignedByteArray();
14098
TestExternalShortArray();
14099
TestExternalUnsignedShortArray();
14100
TestExternalIntArray();
14101
TestExternalUnsignedIntArray();
14102
TestExternalFloatArray();
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);
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);
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);
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);
14172
THREADED_TEST(ScriptContextDependence) {
14173
v8::HandleScope scope;
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);
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);
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);
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);
14214
CHECK(strstr(*script_name, expected_script_name) != NULL);
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());
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;
14230
ASSERT(args.Length() == 1);
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));
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
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));
14270
CHECK(stackTrace->AsArray()->IsArray());
14272
return v8::Undefined();
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);
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"
14293
"function foo() {\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());
14304
// Test getting DETAILED information.
14305
const char *detailed_source =
14306
"function bat() {AnalyzeStackInNativeCode(2);\n"
14309
"function baz() {\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());
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));
14337
TEST(CaptureStackTraceForUncaughtException) {
14339
v8::HandleScope scope;
14341
v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14342
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14344
Script::Compile(v8_str("function foo() {\n"
14347
"function bar() {\n"
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);
14360
TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14361
v8::HandleScope scope;
14363
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14365
v8::StackTrace::kDetailed);
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"
14375
CompileRun("throw 'exception';");
14376
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
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());
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;
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"
14409
"} catch (e1) { \n"
14412
" } catch (e2) { \n"
14416
v8::V8::AddMessageListener(RethrowStackTraceHandler);
14417
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14418
CompileRun(source);
14419
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14420
v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
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());
14437
// Test that we do not recognize identity for primitive exceptions.
14438
TEST(RethrowPrimitiveStackTrace) {
14439
v8::HandleScope scope;
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"
14449
"} catch (e1) { \n"
14452
v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14453
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14454
CompileRun(source);
14455
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14456
v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
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());
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;
14475
const char* source =
14476
"var e = new Error(); \n"
14478
v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14479
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14480
CompileRun(source);
14481
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14482
v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
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());
14496
// Test that the stack trace is captured where the bogus Error object is thrown.
14497
TEST(RethrowBogusErrorStackTrace) {
14498
v8::HandleScope scope;
14500
const char* source =
14501
"var e = {__proto__: new Error()} \n"
14503
v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14504
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14505
CompileRun(source);
14506
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14507
v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
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);
14523
return v8::Undefined();
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);
14534
const char *source =
14535
"function outer() {\n"
14536
"function bar() {\n"
14537
" AnalyzeStackOfEvalWithSourceURL();\n"
14539
"function foo() {\n"
14545
"eval('(' + outer +')()//@ sourceURL=eval_url');";
14546
CHECK(CompileRun(source)->IsUndefined());
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);
14563
return v8::Undefined();
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);
14575
const char *source =
14576
"function outer() {\n"
14577
"function bar() {\n"
14578
" AnalyzeStackOfInlineScriptWithSourceURL();\n"
14580
"function foo() {\n"
14587
"//@ sourceURL=source_url";
14588
CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
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);
14605
return v8::Undefined();
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);
14617
const char *source =
14618
"function outer() {\n"
14619
"function bar() {\n"
14620
" AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14622
"function foo() {\n"
14629
"//@ sourceURL=source_url";
14630
CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
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);
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;
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();
14654
intptr_t final_size = HEAP->SizeOfObjects();
14656
CHECK_LT(final_size, initial_size + 1);
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;
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);
14674
intptr_t final_size = HEAP->SizeOfObjects();
14676
CHECK_LT(final_size, initial_size + 1);
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;
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);
14694
intptr_t final_size = HEAP->SizeOfObjects();
14696
CHECK_LT(final_size, initial_size + 1);
14700
TEST(Regress2107) {
14701
const intptr_t MB = 1024 * 1024;
14702
const int kShortIdlePauseInMs = 100;
14703
const int kLongIdlePauseInMs = 1000;
14704
v8::HandleScope scope;
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();
14713
CreateGarbageInOldSpace();
14716
v8::V8::ContextDisposedNotification();
14717
v8::V8::IdleNotification(kLongIdlePauseInMs);
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);
14727
intptr_t final_size = HEAP->SizeOfObjects();
14728
CHECK_LT(final_size, initial_size + 1);
14731
static uint32_t* stack_limit;
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();
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
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));
14754
TEST(SetResourceConstraints) {
14755
static const int K = 1024;
14756
uint32_t* set_limit = ComputeStackLimit(128 * K);
14758
// Set stack limit.
14759
v8::ResourceConstraints constraints;
14760
constraints.set_stack_limit(set_limit);
14761
CHECK(v8::SetResourceConstraints(&constraints));
14763
// Execute a script.
14764
v8::HandleScope scope;
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();");
14772
CHECK(stack_limit == set_limit);
14776
TEST(SetResourceConstraintsInThread) {
14777
uint32_t* set_limit;
14780
static const int K = 1024;
14781
set_limit = ComputeStackLimit(128 * K);
14783
// Set stack limit.
14784
v8::ResourceConstraints constraints;
14785
constraints.set_stack_limit(set_limit);
14786
CHECK(v8::SetResourceConstraints(&constraints));
14788
// Execute a script.
14789
v8::HandleScope scope;
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();");
14797
CHECK(stack_limit == set_limit);
14801
CHECK(stack_limit == set_limit);
14806
THREADED_TEST(GetHeapStatistics) {
14807
v8::HandleScope scope;
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);
14818
class VisitorImpl : public v8::ExternalResourceVisitor {
14820
VisitorImpl(TestResource* r1, TestResource* 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());
14831
v8::String::ExternalStringResource* resource =
14832
string->GetExternalStringResource();
14834
if (resource1_ == resource) {
14835
CHECK(!found_resource1_);
14836
found_resource1_ = true;
14838
if (resource2_ == resource) {
14839
CHECK(!found_resource2_);
14840
found_resource2_ = true;
14843
void CheckVisitedResources() {
14844
CHECK(found_resource1_);
14845
CHECK(found_resource2_);
14849
v8::String::ExternalStringResource* resource1_;
14850
v8::String::ExternalStringResource* resource2_;
14851
bool found_resource1_;
14852
bool found_resource2_;
14855
TEST(VisitExternalStrings) {
14856
v8::HandleScope scope;
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);
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());
14869
VisitorImpl visitor(resource1, resource2);
14870
v8::V8::VisitExternalResources(&visitor);
14871
visitor.CheckVisitedResources();
14875
static double DoubleFromBits(uint64_t value) {
14877
memcpy(&target, &value, sizeof(target));
14882
static uint64_t DoubleToBits(double value) {
14884
memcpy(&target, &value, sizeof(target));
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();
14894
return (input < 0) ? -(floor(-input)) : floor(input);
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);
14904
THREADED_TEST(QuietSignalingNaNs) {
14905
v8::HandleScope scope;
14906
LocalContext context;
14907
v8::TryCatch try_catch;
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);
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;
14922
double test_values[] = {
14944
int num_test_values = 20;
14946
for (int i = 0; i < num_test_values; i++) {
14947
double test_value = test_values[i];
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);
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));
14962
CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14966
// Check that Date::New preserves non-NaNs in the date range and
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);
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));
14981
CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14988
static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14989
v8::HandleScope scope;
14991
v8::Handle<v8::String> str(args[0]->ToString());
14993
if (tc.HasCaught())
14994
return tc.ReThrow();
14995
return v8::Undefined();
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;
15011
" toString: function () {"
15021
CHECK(try_catch.HasCaught());
15022
v8::String::Utf8Value value(try_catch.Exception());
15023
CHECK_EQ(0, strcmp(*value, "Hey!"));
15028
v8::V8::Initialize();
15030
v8::HandleScope scope;
15031
v8::Persistent<Context> context;
15032
v8::Persistent<Context> other_context;
15035
// Create a context used to keep the code from aging in the compilation
15037
other_context = Context::New();
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();
15044
v8::HandleScope scope;
15047
Local<v8::String> obj = v8::String::New("");
15048
context->SetData(obj);
15049
CompileRun(source_simple);
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;
15061
CHECK_GE(2, gc_count);
15062
CHECK_EQ(1, GetGlobalObjectsCount());
15064
// Eval in a function creates reference from the compilation cache to the
15066
const char* source_eval = "function f(){eval('1')}; f()";
15067
context = Context::New();
15069
v8::HandleScope scope;
15072
CompileRun(source_eval);
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;
15084
CHECK_GE(2, gc_count);
15085
CHECK_EQ(1, GetGlobalObjectsCount());
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();
15092
v8::HandleScope scope;
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());
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;
15112
CHECK_GE(2, gc_count);
15113
CHECK_EQ(1, GetGlobalObjectsCount());
15115
other_context.Dispose();
15116
v8::V8::ContextDisposedNotification();
15120
THREADED_TEST(ScriptOrigin) {
15121
v8::HandleScope scope;
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")));
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());
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());
15141
THREADED_TEST(FunctionGetInferredName) {
15142
v8::HandleScope scope;
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()));
15153
THREADED_TEST(ScriptLineNumber) {
15154
v8::HandleScope scope;
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());
15169
THREADED_TEST(ScriptColumnNumber) {
15170
v8::HandleScope scope;
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());
15186
THREADED_TEST(FunctionGetScriptId) {
15187
v8::HandleScope scope;
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));
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());
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());
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));
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>();
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));
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() {"
15252
"C1.prototype = P;"
15256
"C2.prototype = { };"
15257
"C2.prototype.__proto__ = P;");
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());
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());
15276
static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15277
Local<String> name, const AccessorInfo& info) {
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));
15287
return v8::Handle<Value>();
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() {"
15301
"C1.prototype = P;"
15305
"C2.prototype = { };"
15306
"C2.prototype.__proto__ = P;");
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());
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());
15326
const char* source = "function C1() {"
15329
"C1.prototype = P;";
15331
v8::HandleScope scope;
15332
LocalContext context;
15333
v8::Local<v8::Script> script;
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);
15340
// This compile will add the code to the compilation cache.
15341
CompileRun(source);
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());
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());
15359
// This compile will get the code from the compilation cache.
15360
CompileRun(source);
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());
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;
15375
void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15376
++prologue_call_count;
15379
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15380
++epilogue_call_count;
15383
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15384
++prologue_call_count_second;
15387
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15388
++epilogue_call_count_second;
15391
TEST(GCCallbacks) {
15392
LocalContext context;
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);
15425
THREADED_TEST(AddToJSFunctionResultCache) {
15426
i::FLAG_allow_natives_syntax = true;
15427
v8::HandleScope scope;
15429
LocalContext context;
15435
" var r0 = %_GetFromCache(0, key0);"
15436
" var r1 = %_GetFromCache(0, key1);"
15437
" var r0_ = %_GetFromCache(0, key0);"
15439
" return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15440
" var r1_ = %_GetFromCache(0, key1);"
15442
" return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15443
" return 'PASSED';"
15445
HEAP->ClearJSFunctionResultCaches();
15446
ExpectString(code, "PASSED");
15450
static const int k0CacheSize = 16;
15452
THREADED_TEST(FillJSFunctionResultCache) {
15453
i::FLAG_allow_natives_syntax = true;
15454
v8::HandleScope scope;
15456
LocalContext context;
15461
" var r = %_GetFromCache(0, k);"
15462
" for (var i = 0; i < 16; i++) {"
15463
" %_GetFromCache(0, 'a' + i);"
15465
" if (r === %_GetFromCache(0, k))"
15466
" return 'FAILED: k0CacheSize is too small';"
15467
" return 'PASSED';"
15469
HEAP->ClearJSFunctionResultCaches();
15470
ExpectString(code, "PASSED");
15474
THREADED_TEST(RoundRobinGetFromCache) {
15475
i::FLAG_allow_natives_syntax = true;
15476
v8::HandleScope scope;
15478
LocalContext context;
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];"
15492
" return 'PASSED';"
15494
HEAP->ClearJSFunctionResultCaches();
15495
ExpectString(code, "PASSED");
15499
THREADED_TEST(ReverseGetFromCache) {
15500
i::FLAG_allow_natives_syntax = true;
15501
v8::HandleScope scope;
15503
LocalContext context;
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];"
15517
" return 'PASSED';"
15519
HEAP->ClearJSFunctionResultCaches();
15520
ExpectString(code, "PASSED");
15524
THREADED_TEST(TestEviction) {
15525
i::FLAG_allow_natives_syntax = true;
15526
v8::HandleScope scope;
15528
LocalContext context;
15532
" for (var i = 0; i < 2*16; i++) {"
15533
" %_GetFromCache(0, 'a' + i);"
15535
" return 'PASSED';"
15537
HEAP->ClearJSFunctionResultCaches();
15538
ExpectString(code, "PASSED");
15542
THREADED_TEST(TwoByteStringInAsciiCons) {
15543
// See Chromium issue 47824.
15544
v8::HandleScope scope;
15546
LocalContext context;
15547
const char* init_code =
15548
"var str1 = 'abelspendabel';"
15549
"var str2 = str1 + str1 + str1;"
15551
Local<Value> result = CompileRun(init_code);
15553
Local<Value> indexof = CompileRun("str2.indexOf('els')");
15554
Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
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());
15561
FlattenString(string);
15562
i::Handle<i::String> flat_string = FlattenGetString(string);
15564
CHECK(string->IsAsciiRepresentation());
15565
CHECK(flat_string->IsAsciiRepresentation());
15567
// Create external resource.
15568
uint16_t* uc16_buffer = new uint16_t[length + 1];
15570
i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15571
uc16_buffer[length] = 0;
15573
TestResource resource(uc16_buffer);
15575
flat_string->MakeExternal(&resource);
15577
CHECK(flat_string->IsTwoByteRepresentation());
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
15584
CHECK(string->IsAsciiRepresentation());
15585
i::ConsString* cons = i::ConsString::cast(*string);
15586
CHECK_EQ(0, cons->second()->length());
15587
CHECK(cons->first()->IsTwoByteRepresentation());
15589
// Check that some string operations work.
15592
Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15593
CHECK_EQ(6, reresult->Int32Value());
15596
reresult = CompileRun("str2.match(/abe./g).length;");
15597
CHECK_EQ(6, reresult->Int32Value());
15599
reresult = CompileRun("str2.search(/bel/g);");
15600
CHECK_EQ(1, reresult->Int32Value());
15602
reresult = CompileRun("str2.search(/be./g);");
15603
CHECK_EQ(1, reresult->Int32Value());
15605
ExpectTrue("/bel/g.test(str2);");
15607
ExpectTrue("/be./g.test(str2);");
15609
reresult = CompileRun("/bel/g.exec(str2);");
15610
CHECK(!reresult->IsNull());
15612
reresult = CompileRun("/be./g.exec(str2);");
15613
CHECK(!reresult->IsNull());
15615
ExpectString("str2.substring(2, 10);", "elspenda");
15617
ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15619
ExpectString("str2.charAt(2);", "e");
15621
ExpectObject("str2.indexOf('els');", indexof);
15623
ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15625
reresult = CompileRun("str2.charCodeAt(2);");
15626
CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
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);
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
15642
v8::V8::Initialize();
15643
v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
15645
v8::HandleScope scope;
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>(),
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();
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);
15665
// Get property with failed access check.
15666
ExpectUndefined("other.x");
15668
// Get element with failed access check.
15669
ExpectUndefined("other[0]");
15671
// Set property with failed access check.
15672
v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15673
CHECK(result->IsObject());
15675
// Set element with failed access check.
15676
result = CompileRun("other[0] = new Object()");
15677
CHECK(result->IsObject());
15679
// Get property attribute with failed access check.
15680
ExpectFalse("\'x\' in other");
15682
// Get property attribute for element with failed access check.
15683
ExpectFalse("0 in other");
15685
// Delete property.
15686
ExpectFalse("delete other.x");
15689
CHECK_EQ(false, global0->Delete(0));
15693
global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15695
// Define JavaScript accessor.
15696
ExpectUndefined("Object.prototype.__defineGetter__.call("
15697
" other, \'x\', function() { return 42; })");
15700
ExpectUndefined("Object.prototype.__lookupGetter__.call("
15703
// HasLocalElement.
15704
ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
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")));
15710
// Reset the failed access check callback so it does not influence
15711
// the other tests.
15712
v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
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");
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());
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);
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");
15755
TEST(DisposeDefaultIsolate) {
15756
v8::V8::SetFatalErrorHandler(StoringErrorCallback);
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");
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);
15772
TEST(RunDefaultAndAnotherIsolate) {
15773
v8::HandleScope scope;
15774
LocalContext context;
15776
// Enter new isolate.
15777
v8::Isolate* isolate = v8::Isolate::New();
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;
15785
// Run something in new isolate.
15786
CompileRun("var foo = 153;");
15787
ExpectTrue("function f() { return foo == 153; }; f()");
15791
// This runs automatically in default isolate.
15792
// Variables in another isolate should be not available.
15793
ExpectTrue("function f() {"
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);
15810
// Check that default isolate still runs.
15811
ExpectTrue("function f() { return bar == 371; }; f()");
15814
TEST(DisposeIsolateWhenInUse) {
15815
v8::Isolate* isolate = v8::Isolate::New();
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);
15830
TEST(RunTwoIsolatesOnSingleThread) {
15832
v8::Isolate* isolate1 = v8::Isolate::New();
15834
v8::Persistent<v8::Context> context1 = v8::Context::New();
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");
15845
v8::Isolate* isolate2 = v8::Isolate::New();
15846
v8::Persistent<v8::Context> context2;
15849
v8::Isolate::Scope iscope(isolate2);
15850
context2 = v8::Context::New();
15851
v8::Context::Scope cscope(context2);
15852
v8::HandleScope scope;
15854
// Run something in new isolate.
15855
CompileRun("var foo = 'isolate 2';");
15856
ExpectString("function f() { return foo; }; f()", "isolate 2");
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");
15868
// Run some stuff in default isolate.
15869
v8::Persistent<v8::Context> context_default = v8::Context::New();
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() {"
15884
"var isDefaultIsolate = true;"
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");
15898
v8::Context::Scope cscope(context1);
15899
v8::HandleScope scope;
15900
ExpectString("function f() { return foo; }; f()", "isolate 1");
15904
v8::Isolate::Scope iscope(isolate2);
15905
context2.Dispose();
15908
context1.Dispose();
15911
v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15912
last_location = last_message = NULL;
15914
isolate1->Dispose();
15915
CHECK_EQ(last_location, NULL);
15916
CHECK_EQ(last_message, NULL);
15918
isolate2->Dispose();
15919
CHECK_EQ(last_location, NULL);
15920
CHECK_EQ(last_message, NULL);
15922
// Check that default isolate still runs.
15924
v8::Context::Scope cscope(context_default);
15925
v8::HandleScope scope;
15926
ExpectTrue("function f() { return isDefaultIsolate; }; f()");
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);"
15940
Local<Value> value = CompileRun(code.start());
15941
CHECK(value->IsNumber());
15942
return static_cast<int>(value->NumberValue());
15945
class IsolateThread : public v8::internal::Thread {
15947
IsolateThread(v8::Isolate* isolate, int fib_limit)
15948
: Thread("IsolateThread"),
15950
fib_limit_(fib_limit),
15954
result_ = CalcFibonacci(isolate_, fib_limit_);
15957
int result() { return result_; }
15960
v8::Isolate* isolate_;
15965
TEST(MultipleIsolatesOnIndividualThreads) {
15966
v8::Isolate* isolate1 = v8::Isolate::New();
15967
v8::Isolate* isolate2 = v8::Isolate::New();
15969
IsolateThread thread1(isolate1, 21);
15970
IsolateThread thread2(isolate2, 12);
15972
// Compute some fibonacci numbers on 3 threads in 3 isolates.
15976
int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15977
int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
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());
15989
isolate1->Dispose();
15990
isolate2->Dispose();
15993
TEST(IsolateDifferentContexts) {
15994
v8::Isolate* isolate = v8::Isolate::New();
15995
Persistent<v8::Context> context;
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()));
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()));
16016
class InitDefaultIsolateThread : public v8::internal::Thread {
16020
SetResourceConstraints,
16022
SetCounterFunction,
16023
SetCreateHistogramFunction,
16024
SetAddHistogramSampleFunction
16027
explicit InitDefaultIsolateThread(TestCase testCase)
16028
: Thread("InitDefaultIsolateThread"),
16029
testCase_(testCase),
16033
switch (testCase_) {
16035
v8::V8::IgnoreOutOfMemoryException();
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);
16047
case SetFatalHandler:
16048
v8::V8::SetFatalErrorHandler(NULL);
16051
case SetCounterFunction:
16052
v8::V8::SetCounterFunction(NULL);
16055
case SetCreateHistogramFunction:
16056
v8::V8::SetCreateHistogramFunction(NULL);
16059
case SetAddHistogramSampleFunction:
16060
v8::V8::SetAddHistogramSampleFunction(NULL);
16066
bool result() { return result_; }
16069
TestCase testCase_;
16074
static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16075
InitDefaultIsolateThread thread(testCase);
16078
CHECK_EQ(thread.result(), true);
16081
TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16082
InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16085
TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16086
InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16089
TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16090
InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16093
TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16094
InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16097
TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16098
InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16101
TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16102
InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16106
TEST(StringCheckMultipleContexts) {
16108
"(function() { return \"a\".charAt(0); })()";
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");
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");
16129
TEST(NumberCheckMultipleContexts) {
16131
"(function() { return (42).toString(); })()";
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");
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");
16152
TEST(BooleanCheckMultipleContexts) {
16154
"(function() { return true.toString(); })()";
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");
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, "");
16175
TEST(DontDeleteCellLoadIC) {
16176
const char* function_code =
16177
"function readCell() { while (true) { return cell; } }";
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");
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() {"
16201
" return readCell();"
16203
" return e.toString();"
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");
16215
TEST(DontDeleteCellLoadICForceDelete) {
16216
const char* function_code =
16217
"function readCell() { while (true) { return cell; } }";
16219
// Run the code twice to initialize the load IC for a don't delete
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");
16229
// Delete the cell using the API and check the inlined code works
16231
CHECK(context->Global()->ForceDelete(v8_str("cell")));
16232
ExpectString("(function() {"
16234
" return readCell();"
16236
" return e.toString();"
16239
"ReferenceError: cell is not defined");
16243
TEST(DontDeleteCellLoadICAPI) {
16244
const char* function_code =
16245
"function readCell() { while (true) { return cell; } }";
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");
16257
// Delete the cell using the API and check the inlined code works
16259
CHECK(context->Global()->ForceDelete(v8_str("cell")));
16260
ExpectString("(function() {"
16262
" return readCell();"
16264
" return e.toString();"
16267
"ReferenceError: cell is not defined");
16271
class Visitor42 : public v8::PersistentHandleVisitor {
16273
explicit Visitor42(v8::Persistent<v8::Object> object)
16274
: counter_(0), object_(object) { }
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);
16289
v8::Persistent<v8::Object> object_;
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());
16302
Visitor42 visitor(object);
16303
v8::V8::VisitHandlesWithClassIds(&visitor);
16304
CHECK_EQ(1, visitor.counter_);
16311
v8::HandleScope scope;
16312
LocalContext context;
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());
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()));
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()));
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());
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()));
16346
// Override the RegExp constructor and check the API constructor
16348
CompileRun("RegExp = function() {}");
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());
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()));
16363
context->Global()->Set(v8_str("re"), re);
16364
ExpectTrue("re.test('FoobarbaZ')");
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());
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");
16380
THREADED_TEST(Equals) {
16381
v8::HandleScope handleScope;
16382
LocalContext localContext;
16384
v8::Handle<v8::Object> globalProxy = localContext->Global();
16385
v8::Handle<Value> global = globalProxy->GetPrototype();
16387
CHECK(global->StrictEquals(global));
16388
CHECK(!global->StrictEquals(globalProxy));
16389
CHECK(!globalProxy->StrictEquals(global));
16390
CHECK(globalProxy->StrictEquals(globalProxy));
16392
CHECK(global->Equals(global));
16393
CHECK(!global->Equals(globalProxy));
16394
CHECK(!globalProxy->Equals(global));
16395
CHECK(globalProxy->Equals(globalProxy));
16399
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16400
const v8::AccessorInfo& info ) {
16401
return v8_str("42!");
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"));
16412
TEST(NamedEnumeratorAndForIn) {
16413
v8::HandleScope handle_scope;
16414
LocalContext context;
16415
v8::Context::Scope context_scope(context.local());
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));
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("
16436
" { configurable: true, enumerable: true, value: 3 });"
16437
"})").As<Function>();
16438
context->DetachGlobal();
16439
define_property->Call(proxy, 0, NULL);
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));
16450
static void CheckContextId(v8::Handle<Object> object, int expected) {
16451
CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
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);
16464
Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16466
Local<Object> object1;
16467
Local<Function> func1;
16469
Context::Scope scope(context1);
16470
object1 = Object::New();
16471
func1 = tmpl->GetFunction();
16474
Local<Object> object2;
16475
Local<Function> func2;
16477
Context::Scope scope(context2);
16478
object2 = Object::New();
16479
func2 = tmpl->GetFunction();
16482
Local<Object> instance1;
16483
Local<Object> instance2;
16486
Context::Scope scope(context3);
16487
instance1 = func1->NewInstance();
16488
instance2 = func2->NewInstance();
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);
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);
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);
16536
context1.Dispose();
16537
context2.Dispose();
16538
context3.Dispose();
16542
THREADED_TEST(CreationContextOfJsFunction) {
16543
HandleScope handle_scope;
16544
Persistent<Context> context = Context::New();
16545
InstallContextId(context, 1);
16547
Local<Object> function;
16549
Context::Scope scope(context);
16550
function = CompileRun("function foo() {}; foo").As<Object>();
16553
CHECK(function->CreationContext() == context);
16554
CheckContextId(function, 1);
16560
Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16561
const AccessorInfo& info) {
16562
if (index == 42) return v8_str("yes");
16563
return Handle<v8::Integer>();
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>();
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>();
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>();
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>();
16595
Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16596
const AccessorInfo& info) {
16597
return v8_str("yes");
16601
TEST(HasOwnProperty) {
16602
v8::HandleScope scope;
16604
{ // Check normal properties and defined getters.
16605
Handle<Value> value = CompileRun(
16608
" this.__defineGetter__('baz', function() { return 1; });"
16610
"function Bar() { "
16612
" this.__defineGetter__('bla', function() { return 2; });"
16614
"Bar.prototype = new Foo();"
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")));
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")));
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")));
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")));
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")));
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")));
16662
{ // Check that query wins on disagreement.
16663
Handle<ObjectTemplate> templ = ObjectTemplate::New();
16664
templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16666
HasOwnPropertyNamedPropertyQuery2);
16667
Handle<Object> instance = templ->NewInstance();
16668
CHECK(!instance->HasOwnProperty(v8_str("foo")));
16669
CHECK(instance->HasOwnProperty(v8_str("bar")));
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());
16684
void CheckCodeGenerationDisallowed() {
16685
TryCatch try_catch;
16687
Handle<Value> result = CompileRun("eval('42')");
16688
CHECK(result.IsEmpty());
16689
CHECK(try_catch.HasCaught());
16692
result = CompileRun("(function(e) { return e('42'); })(eval)");
16693
CHECK(result.IsEmpty());
16694
CHECK(try_catch.HasCaught());
16697
result = CompileRun("var f = new Function('return 42'); f()");
16698
CHECK(result.IsEmpty());
16699
CHECK(try_catch.HasCaught());
16703
bool CodeGenerationAllowed(Local<Context> context) {
16704
ApiTestFuzzer::Fuzz();
16709
bool CodeGenerationDisallowed(Local<Context> context) {
16710
ApiTestFuzzer::Fuzz();
16715
THREADED_TEST(AllowCodeGenFromStrings) {
16716
v8::HandleScope scope;
16717
LocalContext context;
16719
// eval and the Function constructor allowed by default.
16720
CHECK(context->IsCodeGenerationFromStringsAllowed());
16721
CheckCodeGenerationAllowed();
16723
// Disallow eval and the Function constructor.
16724
context->AllowCodeGenerationFromStrings(false);
16725
CHECK(!context->IsCodeGenerationFromStringsAllowed());
16726
CheckCodeGenerationDisallowed();
16729
context->AllowCodeGenerationFromStrings(true);
16730
CheckCodeGenerationAllowed();
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();
16738
// Set a callback that disallows the code generation.
16739
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16740
CHECK(!context->IsCodeGenerationFromStringsAllowed());
16741
CheckCodeGenerationDisallowed();
16745
TEST(SetErrorMessageForCodeGenFromStrings) {
16746
v8::HandleScope scope;
16747
LocalContext context;
16748
TryCatch try_catch;
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));
16763
static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16764
return v8::Undefined();
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)");
16779
// Regression test for issue 1470.
16780
THREADED_TEST(ReadOnlyIndexedProperties) {
16781
v8::HandleScope scope;
16782
Local<ObjectTemplate> templ = ObjectTemplate::New();
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)));
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")));
16801
THREADED_TEST(Regress1516) {
16802
v8::HandleScope scope;
16804
LocalContext context;
16805
{ v8::HandleScope temp_scope;
16806
CompileRun("({'a': 0})");
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);
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());
16827
static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
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) {
16837
CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16838
return strncmp(buffer, "__proto__", 9) != 0;
16845
THREADED_TEST(Regress93759) {
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);
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);
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);
16866
// Context for "foreign" objects used in test.
16867
Persistent<Context> context = v8::Context::New();
16870
// Plain object, no security check.
16871
Local<Object> simple_object = Object::New();
16873
// Object with explicit security check.
16874
Local<Object> protected_object =
16875
no_proto_template->NewInstance();
16877
// JSGlobalProxy object, always have security check.
16878
Local<Object> proxy_object =
16881
// Global object, the prototype of proxy_object. No security checks.
16882
Local<Object> global_object =
16883
proxy_object->GetPrototype()->ToObject();
16885
// Hidden prototype without security check.
16886
Local<Object> hidden_prototype =
16887
hidden_proto_template->GetFunction()->NewInstance();
16888
Local<Object> object_with_hidden =
16890
object_with_hidden->SetPrototype(hidden_prototype);
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 =
16897
object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16901
// Template for object for second context. Values to test are put on it as
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);
16911
LocalContext context2(NULL, global_template);
16913
Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16914
CHECK(result1->Equals(simple_object->GetPrototype()));
16916
Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16917
CHECK(result2->Equals(Undefined()));
16919
Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16920
CHECK(result3->Equals(global_object->GetPrototype()));
16922
Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16923
CHECK(result4->Equals(Undefined()));
16925
Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16926
CHECK(result5->Equals(
16927
object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16929
Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16930
CHECK(result6->Equals(Undefined()));
16936
THREADED_TEST(Regress125988) {
16937
v8::HandleScope scope;
16938
Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16939
AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
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();"
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);
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)));
16970
THREADED_TEST(ForeignFunctionReceiver) {
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).
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, "
16983
" toString: function() { "
16990
CHECK(foreign_function->IsFunction());
16991
foreign_context->Exit();
16993
LocalContext context;
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);
17001
Local<String> i = v8_str("i");
17002
Local<String> o = v8_str("o");
17003
Local<String> id = v8_str("id");
17005
CompileRun("function ownfunc() { return { 0: this.id, "
17007
" toString: function() { "
17014
context->Global()->Set(v8_str("func"), foreign_function);
17016
// Sanity check the contexts.
17017
CHECK(i->Equals(foreign_context->Global()->Get(id)));
17018
CHECK(o->Equals(context->Global()->Get(id)));
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)()");
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]")));
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)()");
17060
foreign_context.Dispose();
17064
uint8_t callback_fired = 0;
17067
void CallCompletedCallback1() {
17068
i::OS::Print("Firing callback 1.\n");
17069
callback_fired ^= 1; // Toggle first bit.
17073
void CallCompletedCallback2() {
17074
i::OS::Print("Firing callback 2.\n");
17075
callback_fired ^= 2; // Toggle second bit.
17079
Handle<Value> RecursiveCall(const Arguments& args) {
17080
int32_t level = args[0]->Int32Value();
17083
i::OS::Print("Entering recursion level %d.\n", level);
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);
17091
i::OS::Print("Recursion ends.\n");
17092
CHECK_EQ(0, callback_fired);
17094
return Undefined();
17098
TEST(CallCompletedCallback) {
17099
v8::HandleScope scope;
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)"));
17113
CHECK_EQ(3, callback_fired);
17115
i::OS::Print("\n--- Script (2) ---\n");
17116
callback_fired = 0;
17117
v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17119
CHECK_EQ(2, callback_fired);
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);
17131
void CallCompletedCallbackNoException() {
17132
v8::HandleScope scope;
17133
CompileRun("1+1;");
17137
void CallCompletedCallbackException() {
17138
v8::HandleScope scope;
17139
CompileRun("throw 'second exception';");
17143
TEST(CallCompletedCallbackOneException) {
17144
v8::HandleScope scope;
17146
v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17147
CompileRun("throw 'exception';");
17151
TEST(CallCompletedCallbackTwoExceptions) {
17152
v8::HandleScope scope;
17154
v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17155
CompileRun("throw 'first exception';");
17159
static int probes_counter = 0;
17160
static int misses_counter = 0;
17161
static int updates_counter = 0;
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;
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++) {"
17190
static void StubCacheHelper(bool primary) {
17191
V8::SetCounterFunction(LookupCounter);
17192
USE(kMegamorphicTestProgram);
17194
i::FLAG_native_code_counters = true;
17196
i::FLAG_test_primary_stub_cache = true;
17198
i::FLAG_test_secondary_stub_cache = true;
17200
i::FLAG_crankshaft = false;
17201
v8::HandleScope scope;
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);
17217
TEST(SecondaryStubCache) {
17218
StubCacheHelper(true);
17222
TEST(PrimaryStubCache) {
17223
StubCacheHelper(false);
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++;
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);
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);
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());
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);
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);
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++;
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++;
17338
static void CheckInstanceCheckedResult(int getters,
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);
17347
CHECK(try_catch->HasCaught());
17348
CHECK_EQ(0, instance_checked_getter_count);
17349
CHECK_EQ(0, instance_checked_setter_count);
17351
try_catch->Reset();
17355
static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17356
instance_checked_getter_count = 0;
17357
instance_checked_setter_count = 0;
17358
TryCatch try_catch;
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);
17366
// Test path through generated LoadIC and StoredIC.
17367
CompileRun("function test_get(o) { o.foo; }"
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; }"
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);
17382
// Test path through optimized code.
17383
CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17385
CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17386
CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17388
CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
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);");
17398
THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17399
v8::internal::FLAG_allow_natives_syntax = true;
17400
v8::HandleScope scope;
17401
LocalContext context;
17403
Local<FunctionTemplate> templ = FunctionTemplate::New();
17404
Local<ObjectTemplate> inst = templ->InstanceTemplate();
17405
inst->SetAccessor(v8_str("foo"),
17406
InstanceCheckedGetter, InstanceCheckedSetter,
17410
v8::AccessorSignature::New(templ));
17411
context->Global()->Set(v8_str("f"), templ->GetFunction());
17413
printf("Testing positive ...\n");
17414
CompileRun("var obj = new f();");
17415
CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17416
CheckInstanceCheckedAccessors(true);
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);
17426
THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17427
v8::internal::FLAG_allow_natives_syntax = true;
17428
v8::HandleScope scope;
17429
LocalContext context;
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,
17439
v8::AccessorSignature::New(templ));
17440
context->Global()->Set(v8_str("f"), templ->GetFunction());
17442
printf("Testing positive ...\n");
17443
CompileRun("var obj = new f();");
17444
CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17445
CheckInstanceCheckedAccessors(true);
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);
17455
THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17456
v8::internal::FLAG_allow_natives_syntax = true;
17457
v8::HandleScope scope;
17458
LocalContext context;
17460
Local<FunctionTemplate> templ = FunctionTemplate::New();
17461
Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17462
proto->SetAccessor(v8_str("foo"),
17463
InstanceCheckedGetter, InstanceCheckedSetter,
17467
v8::AccessorSignature::New(templ));
17468
context->Global()->Set(v8_str("f"), templ->GetFunction());
17470
printf("Testing positive ...\n");
17471
CompileRun("var obj = new f();");
17472
CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17473
CheckInstanceCheckedAccessors(true);
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);
17481
printf("Testing positive with modified prototype chain ...\n");
17482
CompileRun("var obj = new f();"
17484
"pro.__proto__ = obj.__proto__;"
17485
"obj.__proto__ = pro;");
17486
CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17487
CheckInstanceCheckedAccessors(true);
17491
TEST(TryFinallyMessage) {
17492
v8::HandleScope scope;
17493
LocalContext context;
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 =
17501
" throw new Error('test'); \n"
17504
" x++; \n" // Trigger an IC initialization here.
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());
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 =
17519
" throw new Error('test'); \n"
17523
" throw new Error('again'); \n" // This is the new uncaught error.
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());
17534
static void Helper137002(bool do_store,
17536
bool remove_accessor,
17537
bool interceptor) {
17538
LocalContext context;
17539
Local<ObjectTemplate> templ = ObjectTemplate::New();
17541
templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17543
templ->SetAccessor(v8_str("foo"),
17544
GetterWhichReturns42,
17545
SetterWhichSetsYOnThisTo23);
17547
context->Global()->Set(v8_str("obj"), templ->NewInstance());
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);");
17558
CompileRun("obj.__proto__ = null;"
17559
"f(obj); f(obj); f(obj);");
17561
CompileRun("f({});");
17563
CompileRun("obj.y = void 0;"
17564
"%OptimizeFunctionOnNextCall(f);");
17565
if (remove_accessor) {
17566
CompileRun("delete obj.foo;");
17568
CompileRun("var result = f(obj);");
17570
CompileRun("result = obj.y;");
17572
if (remove_accessor && !interceptor) {
17573
CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17575
CHECK_EQ(do_store ? 23 : 42,
17576
context->Global()->Get(v8_str("result"))->Int32Value());
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);
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());
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]; }"
17614
"obj.__proto__ = null;"
17616
"subobj.y = void 0;"
17617
"subobj.__proto__ = obj;"
17618
"%OptimizeObjectForAddingMultipleProperties(obj, 1);"
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');"
17628
// Actually test the shiny new ICs and better not crash. This
17629
// serves as a regression test for issue 142088 as well.
17634
"keyed_load(obj, 'foo');"
17635
"keyed_load2(subobj, 'foo');"
17637
// Delete the accessor. It better not be called any more now.
17640
"subobj.y = void 0;"
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');"
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());
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());
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);");
17676
THREADED_TEST(Regress137496) {
17677
i::FLAG_expose_gc = true;
17678
v8::HandleScope scope;
17679
LocalContext context;
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());
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();");
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"));
17711
class ThreadInterruptTest {
17713
ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17714
~ThreadInterruptTest() { delete sem_; }
17717
sem_ = i::OS::CreateSemaphore(0);
17719
InterruptThread i_thread(this);
17723
CHECK_EQ(kExpectedValue, sem_value_);
17727
static const int kExpectedValue = 1;
17729
class InterruptThread : public i::Thread {
17731
explicit InterruptThread(ThreadInterruptTest* test)
17732
: Thread("InterruptThread"), test_(test) {}
17734
virtual void Run() {
17735
struct sigaction action;
17737
// Ensure that we'll enter waiting condition
17740
// Setup signal handler
17741
memset(&action, 0, sizeof(action));
17742
action.sa_handler = SignalHandler;
17743
sigaction(SIGCHLD, &action, NULL);
17746
kill(getpid(), SIGCHLD);
17748
// Ensure that if wait has returned because of error
17751
// Set value and signal semaphore
17752
test_->sem_value_ = 1;
17753
test_->sem_->Signal();
17756
static void SignalHandler(int signal) {
17760
ThreadInterruptTest* test_;
17761
struct sigaction sa_;
17764
i::Semaphore* sem_;
17765
volatile int sem_value_;
17769
THREADED_TEST(SemaphoreInterruption) {
17770
ThreadInterruptTest().RunTest();