blob: c45ccf8f328e28870dfc6dd373b369e694bff053 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2007-2008 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <map>
29#include <string>
30
31#include "v8.h"
32
33#include "api.h"
34#include "snapshot.h"
35#include "platform.h"
36#include "top.h"
37#include "cctest.h"
38
39static bool IsNaN(double x) {
40#ifdef WIN32
41 return _isnan(x);
42#else
43 return isnan(x);
44#endif
45}
46
47using ::v8::ObjectTemplate;
48using ::v8::Value;
49using ::v8::Context;
50using ::v8::Local;
51using ::v8::String;
52using ::v8::Script;
53using ::v8::Function;
54using ::v8::AccessorInfo;
55using ::v8::Extension;
56
57namespace i = ::v8::internal;
58
59static Local<Value> v8_num(double x) {
60 return v8::Number::New(x);
61}
62
63
64static Local<String> v8_str(const char* x) {
65 return String::New(x);
66}
67
68
69static Local<Script> v8_compile(const char* x) {
70 return Script::Compile(v8_str(x));
71}
72
73
74// A LocalContext holds a reference to a v8::Context.
75class LocalContext {
76 public:
77 LocalContext(v8::ExtensionConfiguration* extensions = 0,
78 v8::Handle<ObjectTemplate> global_template =
79 v8::Handle<ObjectTemplate>(),
80 v8::Handle<Value> global_object = v8::Handle<Value>())
81 : context_(Context::New(extensions, global_template, global_object)) {
82 context_->Enter();
83 }
84
85 virtual ~LocalContext() {
86 context_->Exit();
87 context_.Dispose();
88 }
89
90 Context* operator->() { return *context_; }
91 Context* operator*() { return *context_; }
92 Local<Context> local() { return Local<Context>::New(context_); }
93 bool IsReady() { return !context_.IsEmpty(); }
94
95 private:
96 v8::Persistent<Context> context_;
97};
98
99
100// Switches between all the Api tests using the threading support.
101// In order to get a surprising but repeatable pattern of thread
102// switching it has extra semaphores to control the order in which
103// the tests alternate, not relying solely on the big V8 lock.
104//
105// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
106// callbacks. This will have no effect when we are not running the
107// thread fuzzing test. In the thread fuzzing test it will
108// pseudorandomly select a successor thread and switch execution
109// to that thread, suspending the current test.
110class ApiTestFuzzer: public v8::internal::Thread {
111 public:
112 void CallTest();
113 explicit ApiTestFuzzer(int num)
114 : test_number_(num),
115 gate_(v8::internal::OS::CreateSemaphore(0)),
116 active_(true) {
117 }
118
119 // The ApiTestFuzzer is also a Thread, so it has a Run method.
120 virtual void Run();
121
122 enum PartOfTest { FIRST_PART, SECOND_PART };
123
124 static void Setup(PartOfTest part);
125 static void RunAllTests();
126 static void TearDown();
127 // This method switches threads if we are running the Threading test.
128 // Otherwise it does nothing.
129 static void Fuzz();
130 private:
131 static bool fuzzing_;
132 static int tests_being_run_;
133 static int current_;
134 static int active_tests_;
135 static bool NextThread();
136 int test_number_;
137 v8::internal::Semaphore* gate_;
138 bool active_;
139 void ContextSwitch();
140 static int GetNextTestNumber();
141 static v8::internal::Semaphore* all_tests_done_;
142};
143
144
145#define THREADED_TEST(Name) \
146 static void Test##Name(); \
147 RegisterThreadedTest register_##Name(Test##Name); \
148 /* */ TEST(Name)
149
150
151class RegisterThreadedTest {
152 public:
153 explicit RegisterThreadedTest(CcTest::TestFunction* callback)
154 : callback_(callback) {
155 prev_ = first_;
156 first_ = this;
157 count_++;
158 }
159 static int count() { return count_; }
160 static RegisterThreadedTest* nth(int i) {
161 ASSERT(i < count());
162 RegisterThreadedTest* current = first_;
163 while (i > 0) {
164 i--;
165 current = current->prev_;
166 }
167 return current;
168 }
169 CcTest::TestFunction* callback() { return callback_; }
170 ApiTestFuzzer* fuzzer_;
171
172 private:
173 static RegisterThreadedTest* first_;
174 static int count_;
175 CcTest::TestFunction* callback_;
176 RegisterThreadedTest* prev_;
177};
178
179
180RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
181int RegisterThreadedTest::count_ = 0;
182
183
184static int signature_callback_count;
185static v8::Handle<Value> IncrementingSignatureCallback(
186 const v8::Arguments& args) {
187 ApiTestFuzzer::Fuzz();
188 signature_callback_count++;
189 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
190 for (int i = 0; i < args.Length(); i++)
191 result->Set(v8::Integer::New(i), args[i]);
192 return result;
193}
194
195
196static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
197 ApiTestFuzzer::Fuzz();
198 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
199 for (int i = 0; i < args.Length(); i++) {
200 result->Set(v8::Integer::New(i), args[i]);
201 }
202 return result;
203}
204
205
206THREADED_TEST(Handles) {
207 v8::HandleScope scope;
208 Local<Context> local_env;
209 {
210 LocalContext env;
211 local_env = env.local();
212 }
213
214 // Local context should still be live.
215 CHECK(!local_env.IsEmpty());
216 local_env->Enter();
217
218 v8::Handle<v8::Primitive> undef = v8::Undefined();
219 CHECK(!undef.IsEmpty());
220 CHECK(undef->IsUndefined());
221
222 const char* c_source = "1 + 2 + 3";
223 Local<String> source = String::New(c_source);
224 Local<Script> script = Script::Compile(source);
225 CHECK_EQ(6, script->Run()->Int32Value());
226
227 local_env->Exit();
228}
229
230
231// Helper function that compiles and runs the source.
232static Local<Value> CompileRun(const char* source) {
233 return Script::Compile(String::New(source))->Run();
234}
235
236THREADED_TEST(ReceiverSignature) {
237 v8::HandleScope scope;
238 LocalContext env;
239 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
240 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
241 fun->PrototypeTemplate()->Set(
242 v8_str("m"),
243 v8::FunctionTemplate::New(IncrementingSignatureCallback,
244 v8::Handle<Value>(),
245 sig));
246 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
247 signature_callback_count = 0;
248 CompileRun(
249 "var o = new Fun();"
250 "o.m();");
251 CHECK_EQ(1, signature_callback_count);
252 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
253 sub_fun->Inherit(fun);
254 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
255 CompileRun(
256 "var o = new SubFun();"
257 "o.m();");
258 CHECK_EQ(2, signature_callback_count);
259
260 v8::TryCatch try_catch;
261 CompileRun(
262 "var o = { };"
263 "o.m = Fun.prototype.m;"
264 "o.m();");
265 CHECK_EQ(2, signature_callback_count);
266 CHECK(try_catch.HasCaught());
267 try_catch.Reset();
268 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
269 sub_fun->Inherit(fun);
270 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
271 CompileRun(
272 "var o = new UnrelFun();"
273 "o.m = Fun.prototype.m;"
274 "o.m();");
275 CHECK_EQ(2, signature_callback_count);
276 CHECK(try_catch.HasCaught());
277}
278
279
280
281
282THREADED_TEST(ArgumentSignature) {
283 v8::HandleScope scope;
284 LocalContext env;
285 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
286 cons->SetClassName(v8_str("Cons"));
287 v8::Handle<v8::Signature> sig =
288 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
289 v8::Handle<v8::FunctionTemplate> fun =
290 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
291 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
292 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
293
294 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
295 ASSERT(value1->IsTrue());
296
297 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
298 ASSERT(value2->IsTrue());
299
300 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
301 ASSERT(value3->IsTrue());
302
303 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
304 cons1->SetClassName(v8_str("Cons1"));
305 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
306 cons2->SetClassName(v8_str("Cons2"));
307 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
308 cons3->SetClassName(v8_str("Cons3"));
309
310 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
311 v8::Handle<v8::Signature> wsig =
312 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
313 v8::Handle<v8::FunctionTemplate> fun2 =
314 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
315
316 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
317 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
318 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
319 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
320 v8::Handle<Value> value4 = CompileRun(
321 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
322 "'[object Cons1],[object Cons2],[object Cons3]'");
323 ASSERT(value4->IsTrue());
324
325 v8::Handle<Value> value5 = CompileRun(
326 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
327 ASSERT(value5->IsTrue());
328
329 v8::Handle<Value> value6 = CompileRun(
330 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
331 ASSERT(value6->IsTrue());
332
333 v8::Handle<Value> value7 = CompileRun(
334 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
335 "'[object Cons1],[object Cons2],[object Cons3],d';");
336 ASSERT(value7->IsTrue());
337
338 v8::Handle<Value> value8 = CompileRun(
339 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
340 ASSERT(value8->IsTrue());
341}
342
343
344THREADED_TEST(HulIgennem) {
345 v8::HandleScope scope;
346 LocalContext env;
347 v8::Handle<v8::Primitive> undef = v8::Undefined();
348 Local<String> undef_str = undef->ToString();
349 char* value = i::NewArray<char>(undef_str->Length() + 1);
350 undef_str->WriteAscii(value);
351 CHECK_EQ(0, strcmp(value, "undefined"));
352 i::DeleteArray(value);
353}
354
355
356THREADED_TEST(Access) {
357 v8::HandleScope scope;
358 LocalContext env;
359 Local<v8::Object> obj = v8::Object::New();
360 Local<Value> foo_before = obj->Get(v8_str("foo"));
361 CHECK(foo_before->IsUndefined());
362 Local<String> bar_str = v8_str("bar");
363 obj->Set(v8_str("foo"), bar_str);
364 Local<Value> foo_after = obj->Get(v8_str("foo"));
365 CHECK(!foo_after->IsUndefined());
366 CHECK(foo_after->IsString());
367 CHECK_EQ(bar_str, foo_after);
368}
369
370
371THREADED_TEST(Script) {
372 v8::HandleScope scope;
373 LocalContext env;
374 const char* c_source = "1 + 2 + 3";
375 Local<String> source = String::New(c_source);
376 Local<Script> script = Script::Compile(source);
377 CHECK_EQ(6, script->Run()->Int32Value());
378}
379
380
381static uint16_t* AsciiToTwoByteString(const char* source) {
382 size_t array_length = strlen(source) + 1;
383 uint16_t* converted = i::NewArray<uint16_t>(array_length);
384 for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
385 return converted;
386}
387
388
389class TestResource: public String::ExternalStringResource {
390 public:
391 static int dispose_count;
392
393 explicit TestResource(uint16_t* data)
394 : data_(data), length_(0) {
395 while (data[length_]) ++length_;
396 }
397
398 ~TestResource() {
399 i::DeleteArray(data_);
400 ++dispose_count;
401 }
402
403 const uint16_t* data() const {
404 return data_;
405 }
406
407 size_t length() const {
408 return length_;
409 }
410 private:
411 uint16_t* data_;
412 size_t length_;
413};
414
415
416int TestResource::dispose_count = 0;
417
418
419class TestAsciiResource: public String::ExternalAsciiStringResource {
420 public:
421 static int dispose_count;
422
423 explicit TestAsciiResource(char* data)
424 : data_(data),
425 length_(strlen(data)) { }
426
427 ~TestAsciiResource() {
428 i::DeleteArray(data_);
429 ++dispose_count;
430 }
431
432 const char* data() const {
433 return data_;
434 }
435
436 size_t length() const {
437 return length_;
438 }
439 private:
440 char* data_;
441 size_t length_;
442};
443
444
445int TestAsciiResource::dispose_count = 0;
446
447
448THREADED_TEST(ScriptUsingStringResource) {
449 TestResource::dispose_count = 0;
450 const char* c_source = "1 + 2 * 3";
451 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
452 {
453 v8::HandleScope scope;
454 LocalContext env;
455 TestResource* resource = new TestResource(two_byte_source);
456 Local<String> source = String::NewExternal(resource);
457 Local<Script> script = Script::Compile(source);
458 Local<Value> value = script->Run();
459 CHECK(value->IsNumber());
460 CHECK_EQ(7, value->Int32Value());
461 CHECK(source->IsExternal());
462 CHECK_EQ(resource,
463 static_cast<TestResource*>(source->GetExternalStringResource()));
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000464 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000465 CHECK_EQ(0, TestResource::dispose_count);
466 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000467 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000468 CHECK_EQ(1, TestResource::dispose_count);
469}
470
471
472THREADED_TEST(ScriptUsingAsciiStringResource) {
473 TestAsciiResource::dispose_count = 0;
474 const char* c_source = "1 + 2 * 3";
475 {
476 v8::HandleScope scope;
477 LocalContext env;
478 Local<String> source =
479 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
480 Local<Script> script = Script::Compile(source);
481 Local<Value> value = script->Run();
482 CHECK(value->IsNumber());
483 CHECK_EQ(7, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000484 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000485 CHECK_EQ(0, TestAsciiResource::dispose_count);
486 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000487 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000488 CHECK_EQ(1, TestAsciiResource::dispose_count);
489}
490
491
492THREADED_TEST(GlobalProperties) {
493 v8::HandleScope scope;
494 LocalContext env;
495 v8::Handle<v8::Object> global = env->Global();
496 global->Set(v8_str("pi"), v8_num(3.1415926));
497 Local<Value> pi = global->Get(v8_str("pi"));
498 CHECK_EQ(3.1415926, pi->NumberValue());
499}
500
501
502static v8::Handle<Value> handle_call(const v8::Arguments& args) {
503 ApiTestFuzzer::Fuzz();
504 return v8_num(102);
505}
506
507
508static v8::Handle<Value> construct_call(const v8::Arguments& args) {
509 ApiTestFuzzer::Fuzz();
510 args.This()->Set(v8_str("x"), v8_num(1));
511 args.This()->Set(v8_str("y"), v8_num(2));
512 return args.This();
513}
514
515THREADED_TEST(FunctionTemplate) {
516 v8::HandleScope scope;
517 LocalContext env;
518 {
519 Local<v8::FunctionTemplate> fun_templ =
520 v8::FunctionTemplate::New(handle_call);
521 Local<Function> fun = fun_templ->GetFunction();
522 env->Global()->Set(v8_str("obj"), fun);
523 Local<Script> script = v8_compile("obj()");
524 CHECK_EQ(102, script->Run()->Int32Value());
525 }
526 // Use SetCallHandler to initialize a function template, should work like the
527 // previous one.
528 {
529 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
530 fun_templ->SetCallHandler(handle_call);
531 Local<Function> fun = fun_templ->GetFunction();
532 env->Global()->Set(v8_str("obj"), fun);
533 Local<Script> script = v8_compile("obj()");
534 CHECK_EQ(102, script->Run()->Int32Value());
535 }
536 // Test constructor calls.
537 {
538 Local<v8::FunctionTemplate> fun_templ =
539 v8::FunctionTemplate::New(construct_call);
540 fun_templ->SetClassName(v8_str("funky"));
541 Local<Function> fun = fun_templ->GetFunction();
542 env->Global()->Set(v8_str("obj"), fun);
543 Local<Script> script = v8_compile("var s = new obj(); s.x");
544 CHECK_EQ(1, script->Run()->Int32Value());
545
546 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
547 CHECK_EQ(v8_str("[object funky]"), result);
548 }
549}
550
551
552static v8::Handle<Value> handle_property(Local<String> name,
553 const AccessorInfo&) {
554 ApiTestFuzzer::Fuzz();
555 return v8_num(900);
556}
557
558
559THREADED_TEST(PropertyHandler) {
560 v8::HandleScope scope;
561 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
562 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
563 LocalContext env;
564 Local<Function> fun = fun_templ->GetFunction();
565 env->Global()->Set(v8_str("Fun"), fun);
566 Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
567 CHECK_EQ(900, getter->Run()->Int32Value());
568 Local<Script> setter = v8_compile("obj.foo = 901;");
569 CHECK_EQ(901, setter->Run()->Int32Value());
570}
571
572
573THREADED_TEST(Number) {
574 v8::HandleScope scope;
575 LocalContext env;
576 double PI = 3.1415926;
577 Local<v8::Number> pi_obj = v8::Number::New(PI);
578 CHECK_EQ(PI, pi_obj->NumberValue());
579}
580
581
582THREADED_TEST(ToNumber) {
583 v8::HandleScope scope;
584 LocalContext env;
585 Local<String> str = v8_str("3.1415926");
586 CHECK_EQ(3.1415926, str->NumberValue());
587 v8::Handle<v8::Boolean> t = v8::True();
588 CHECK_EQ(1.0, t->NumberValue());
589 v8::Handle<v8::Boolean> f = v8::False();
590 CHECK_EQ(0.0, f->NumberValue());
591}
592
593
594THREADED_TEST(Date) {
595 v8::HandleScope scope;
596 LocalContext env;
597 double PI = 3.1415926;
598 Local<Value> date_obj = v8::Date::New(PI);
599 CHECK_EQ(3.0, date_obj->NumberValue());
600}
601
602
603THREADED_TEST(Boolean) {
604 v8::HandleScope scope;
605 LocalContext env;
606 v8::Handle<v8::Boolean> t = v8::True();
607 CHECK(t->Value());
608 v8::Handle<v8::Boolean> f = v8::False();
609 CHECK(!f->Value());
610 v8::Handle<v8::Primitive> u = v8::Undefined();
611 CHECK(!u->BooleanValue());
612 v8::Handle<v8::Primitive> n = v8::Null();
613 CHECK(!n->BooleanValue());
614 v8::Handle<String> str1 = v8_str("");
615 CHECK(!str1->BooleanValue());
616 v8::Handle<String> str2 = v8_str("x");
617 CHECK(str2->BooleanValue());
618 CHECK(!v8::Number::New(0)->BooleanValue());
619 CHECK(v8::Number::New(-1)->BooleanValue());
620 CHECK(v8::Number::New(1)->BooleanValue());
621 CHECK(v8::Number::New(42)->BooleanValue());
622 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
623}
624
625
626static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
627 ApiTestFuzzer::Fuzz();
628 return v8_num(13.4);
629}
630
631
632static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
633 ApiTestFuzzer::Fuzz();
634 return v8_num(876);
635}
636
637
638THREADED_TEST(GlobalPrototype) {
639 v8::HandleScope scope;
640 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
641 func_templ->PrototypeTemplate()->Set(
642 "dummy",
643 v8::FunctionTemplate::New(DummyCallHandler));
644 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
645 templ->Set("x", v8_num(200));
646 templ->SetAccessor(v8_str("m"), GetM);
647 LocalContext env(0, templ);
648 v8::Handle<v8::Object> obj = env->Global();
649 v8::Handle<Script> script = v8_compile("dummy()");
650 v8::Handle<Value> result = script->Run();
651 CHECK_EQ(13.4, result->NumberValue());
652 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
653 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
654}
655
656
657static v8::Handle<Value> GetIntValue(Local<String> property,
658 const AccessorInfo& info) {
659 ApiTestFuzzer::Fuzz();
660 int* value =
661 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
662 return v8_num(*value);
663}
664
665static void SetIntValue(Local<String> property,
666 Local<Value> value,
667 const AccessorInfo& info) {
668 int* field =
669 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
670 *field = value->Int32Value();
671}
672
673int foo, bar, baz;
674
675THREADED_TEST(GlobalVariableAccess) {
676 foo = 0;
677 bar = -4;
678 baz = 10;
679 v8::HandleScope scope;
680 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
681 templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
682 GetIntValue,
683 SetIntValue,
684 v8::External::New(&foo));
685 templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
686 GetIntValue,
687 SetIntValue,
688 v8::External::New(&bar));
689 templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
690 GetIntValue,
691 SetIntValue,
692 v8::External::New(&baz));
693 LocalContext env(0, templ->InstanceTemplate());
694 v8_compile("foo = (++bar) + baz")->Run();
695 CHECK_EQ(bar, -3);
696 CHECK_EQ(foo, 7);
697}
698
699
700THREADED_TEST(ObjectTemplate) {
701 v8::HandleScope scope;
702 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
703 templ1->Set("x", v8_num(10));
704 templ1->Set("y", v8_num(13));
705 LocalContext env;
706 Local<v8::Object> instance1 = templ1->NewInstance();
707 env->Global()->Set(v8_str("p"), instance1);
708 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
709 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
710 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
711 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
712 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
713 templ2->Set("a", v8_num(12));
714 templ2->Set("b", templ1);
715 Local<v8::Object> instance2 = templ2->NewInstance();
716 env->Global()->Set(v8_str("q"), instance2);
717 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
718 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
719 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
720 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
721}
722
723
724static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
725 ApiTestFuzzer::Fuzz();
726 return v8_num(17.2);
727}
728
729
730static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
731 ApiTestFuzzer::Fuzz();
732 return v8_num(15.2);
733}
734
735
736THREADED_TEST(DescriptorInheritance) {
737 v8::HandleScope scope;
738 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
739 super->PrototypeTemplate()->Set("flabby",
740 v8::FunctionTemplate::New(GetFlabby));
741 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
742
743 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
744
745 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
746 base1->Inherit(super);
747 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
748
749 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
750 base2->Inherit(super);
751 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
752
753 LocalContext env;
754
755 env->Global()->Set(v8_str("s"), super->GetFunction());
756 env->Global()->Set(v8_str("base1"), base1->GetFunction());
757 env->Global()->Set(v8_str("base2"), base2->GetFunction());
758
759 // Checks right __proto__ chain.
760 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
761 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
762
763 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
764
765 // Instance accessor should not be visible on function object or its prototype
766 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
767 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
768 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
769
770 env->Global()->Set(v8_str("obj"),
771 base1->GetFunction()->NewInstance());
772 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
773 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
774 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
775 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
776 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
777
778 env->Global()->Set(v8_str("obj2"),
779 base2->GetFunction()->NewInstance());
780 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
781 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
782 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
783 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
784 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
785
786 // base1 and base2 cannot cross reference to each's prototype
787 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
788 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
789}
790
791
792int echo_named_call_count;
793
794
795static v8::Handle<Value> EchoNamedProperty(Local<String> name,
796 const AccessorInfo& info) {
797 ApiTestFuzzer::Fuzz();
798 CHECK_EQ(v8_str("data"), info.Data());
799 echo_named_call_count++;
800 return name;
801}
802
803
804THREADED_TEST(NamedPropertyHandlerGetter) {
805 echo_named_call_count = 0;
806 v8::HandleScope scope;
807 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
808 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
809 0, 0, 0, 0,
810 v8_str("data"));
811 LocalContext env;
812 env->Global()->Set(v8_str("obj"),
813 templ->GetFunction()->NewInstance());
814 CHECK_EQ(echo_named_call_count, 0);
815 v8_compile("obj.x")->Run();
816 CHECK_EQ(echo_named_call_count, 1);
817 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
818 v8::Handle<Value> str = CompileRun(code);
819 String::AsciiValue value(str);
820 CHECK_EQ(*value, "oddlepoddle");
821 // Check default behavior
822 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
823 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
824 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
825}
826
827
828int echo_indexed_call_count = 0;
829
830
831static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
832 const AccessorInfo& info) {
833 ApiTestFuzzer::Fuzz();
834 CHECK_EQ(v8_num(637), info.Data());
835 echo_indexed_call_count++;
836 return v8_num(index);
837}
838
839
840THREADED_TEST(IndexedPropertyHandlerGetter) {
841 v8::HandleScope scope;
842 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
843 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
844 0, 0, 0, 0,
845 v8_num(637));
846 LocalContext env;
847 env->Global()->Set(v8_str("obj"),
848 templ->GetFunction()->NewInstance());
849 Local<Script> script = v8_compile("obj[900]");
850 CHECK_EQ(script->Run()->Int32Value(), 900);
851}
852
853
854v8::Handle<v8::Object> bottom;
855
856static v8::Handle<Value> CheckThisIndexedPropertyHandler(
857 uint32_t index,
858 const AccessorInfo& info) {
859 ApiTestFuzzer::Fuzz();
860 CHECK(info.This()->Equals(bottom));
861 return v8::Handle<Value>();
862}
863
864static v8::Handle<Value> CheckThisNamedPropertyHandler(
865 Local<String> name,
866 const AccessorInfo& info) {
867 ApiTestFuzzer::Fuzz();
868 CHECK(info.This()->Equals(bottom));
869 return v8::Handle<Value>();
870}
871
872
873v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
874 Local<Value> value,
875 const AccessorInfo& info) {
876 ApiTestFuzzer::Fuzz();
877 CHECK(info.This()->Equals(bottom));
878 return v8::Handle<Value>();
879}
880
881
882v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
883 Local<Value> value,
884 const AccessorInfo& info) {
885 ApiTestFuzzer::Fuzz();
886 CHECK(info.This()->Equals(bottom));
887 return v8::Handle<Value>();
888}
889
890v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
891 uint32_t index,
892 const AccessorInfo& info) {
893 ApiTestFuzzer::Fuzz();
894 CHECK(info.This()->Equals(bottom));
895 return v8::Handle<v8::Boolean>();
896}
897
898
899v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
900 const AccessorInfo& info) {
901 ApiTestFuzzer::Fuzz();
902 CHECK(info.This()->Equals(bottom));
903 return v8::Handle<v8::Boolean>();
904}
905
906
907v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
908 uint32_t index,
909 const AccessorInfo& info) {
910 ApiTestFuzzer::Fuzz();
911 CHECK(info.This()->Equals(bottom));
912 return v8::Handle<v8::Boolean>();
913}
914
915
916v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
917 Local<String> property,
918 const AccessorInfo& info) {
919 ApiTestFuzzer::Fuzz();
920 CHECK(info.This()->Equals(bottom));
921 return v8::Handle<v8::Boolean>();
922}
923
924
925v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
926 const AccessorInfo& info) {
927 ApiTestFuzzer::Fuzz();
928 CHECK(info.This()->Equals(bottom));
929 return v8::Handle<v8::Array>();
930}
931
932
933v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
934 const AccessorInfo& info) {
935 ApiTestFuzzer::Fuzz();
936 CHECK(info.This()->Equals(bottom));
937 return v8::Handle<v8::Array>();
938}
939
940
941THREADED_TEST(PropertyHandlerInPrototype) {
942 v8::HandleScope scope;
943 LocalContext env;
944
945 // Set up a prototype chain with three interceptors.
946 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
947 templ->InstanceTemplate()->SetIndexedPropertyHandler(
948 CheckThisIndexedPropertyHandler,
949 CheckThisIndexedPropertySetter,
950 CheckThisIndexedPropertyQuery,
951 CheckThisIndexedPropertyDeleter,
952 CheckThisIndexedPropertyEnumerator);
953
954 templ->InstanceTemplate()->SetNamedPropertyHandler(
955 CheckThisNamedPropertyHandler,
956 CheckThisNamedPropertySetter,
957 CheckThisNamedPropertyQuery,
958 CheckThisNamedPropertyDeleter,
959 CheckThisNamedPropertyEnumerator);
960
961 bottom = templ->GetFunction()->NewInstance();
962 Local<v8::Object> top = templ->GetFunction()->NewInstance();
963 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
964
965 bottom->Set(v8_str("__proto__"), middle);
966 middle->Set(v8_str("__proto__"), top);
967 env->Global()->Set(v8_str("obj"), bottom);
968
969 // Indexed and named get.
970 Script::Compile(v8_str("obj[0]"))->Run();
971 Script::Compile(v8_str("obj.x"))->Run();
972
973 // Indexed and named set.
974 Script::Compile(v8_str("obj[1] = 42"))->Run();
975 Script::Compile(v8_str("obj.y = 42"))->Run();
976
977 // Indexed and named query.
978 Script::Compile(v8_str("0 in obj"))->Run();
979 Script::Compile(v8_str("'x' in obj"))->Run();
980
981 // Indexed and named deleter.
982 Script::Compile(v8_str("delete obj[0]"))->Run();
983 Script::Compile(v8_str("delete obj.x"))->Run();
984
985 // Enumerators.
986 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
987}
988
989
990v8::Handle<Value> pre_post_global;
991
992static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
993 const AccessorInfo& info) {
994 ApiTestFuzzer::Fuzz();
995 CHECK(info.This()->Equals(pre_post_global));
996 CHECK(info.Holder()->Equals(pre_post_global));
997 if (v8_str("pre")->Equals(key)) {
998 return v8_str("PrePropertyHandler: pre");
999 }
1000 return v8::Handle<String>();
1001}
1002
1003
1004static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1005 const AccessorInfo&) {
1006 if (v8_str("pre")->Equals(key)) {
1007 return v8::True();
1008 }
1009
1010 return v8::Handle<v8::Boolean>(); // do not intercept the call
1011}
1012
1013
1014THREADED_TEST(PrePropertyHandler) {
1015 v8::HandleScope scope;
1016 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1017 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1018 0,
1019 PrePropertyHandlerHas);
1020 LocalContext env(NULL, desc->InstanceTemplate());
1021 pre_post_global = env->Global();
1022 Script::Compile(v8_str(
1023 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1024 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1025 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1026 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1027 CHECK_EQ(v8_str("Object: on"), result_on);
1028 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1029 CHECK(result_post.IsEmpty());
1030}
1031
1032
1033v8::Handle<Script> call_recursively_script;
1034static const int kTargetRecursionDepth = 300; // near maximum
1035
1036
1037static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1038 ApiTestFuzzer::Fuzz();
1039 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1040 if (depth == kTargetRecursionDepth) return v8::Undefined();
1041 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1042 return call_recursively_script->Run();
1043}
1044
1045
1046static v8::Handle<Value> CallFunctionRecursivelyCall(
1047 const v8::Arguments& args) {
1048 ApiTestFuzzer::Fuzz();
1049 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1050 if (depth == kTargetRecursionDepth) {
1051 printf("[depth = %d]\n", depth);
1052 return v8::Undefined();
1053 }
1054 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1055 v8::Handle<Value> function =
1056 args.This()->Get(v8_str("callFunctionRecursively"));
1057 return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1058}
1059
1060
1061THREADED_TEST(DeepCrossLanguageRecursion) {
1062 v8::HandleScope scope;
1063 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1064 global->Set(v8_str("callScriptRecursively"),
1065 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1066 global->Set(v8_str("callFunctionRecursively"),
1067 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1068 LocalContext env(NULL, global);
1069
1070 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1071 call_recursively_script = v8_compile("callScriptRecursively()");
1072 v8::Handle<Value> result = call_recursively_script->Run();
1073 call_recursively_script = v8::Handle<Script>();
1074
1075 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1076 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1077}
1078
1079
1080static v8::Handle<Value>
1081 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1082 ApiTestFuzzer::Fuzz();
1083 return v8::ThrowException(key);
1084}
1085
1086
1087static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1088 Local<Value>,
1089 const AccessorInfo&) {
1090 v8::ThrowException(key);
1091 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1092}
1093
1094
1095THREADED_TEST(CallbackExceptionRegression) {
1096 v8::HandleScope scope;
1097 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1098 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1099 ThrowingPropertyHandlerSet);
1100 LocalContext env;
1101 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1102 v8::Handle<Value> otto = Script::Compile(v8_str(
1103 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1104 CHECK_EQ(v8_str("otto"), otto);
1105 v8::Handle<Value> netto = Script::Compile(v8_str(
1106 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1107 CHECK_EQ(v8_str("netto"), netto);
1108}
1109
1110
1111static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
1112 const AccessorInfo& info) {
1113 ApiTestFuzzer::Fuzz();
1114 return v8::ThrowException(v8_str("g"));
1115}
1116
1117
1118static void ThrowingSetAccessor(Local<String> name,
1119 Local<Value> value,
1120 const AccessorInfo& info) {
1121 v8::ThrowException(value);
1122}
1123
1124
1125THREADED_TEST(Regress1054726) {
1126 v8::HandleScope scope;
1127 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1128 obj->SetAccessor(v8_str("x"),
1129 ThrowingGetAccessor,
1130 ThrowingSetAccessor,
1131 Local<Value>());
1132
1133 LocalContext env;
1134 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1135
1136 // Use the throwing property setter/getter in a loop to force
1137 // the accessor ICs to be initialized.
1138 v8::Handle<Value> result;
1139 result = Script::Compile(v8_str(
1140 "var result = '';"
1141 "for (var i = 0; i < 5; i++) {"
1142 " try { obj.x; } catch (e) { result += e; }"
1143 "}; result"))->Run();
1144 CHECK_EQ(v8_str("ggggg"), result);
1145
1146 result = Script::Compile(String::New(
1147 "var result = '';"
1148 "for (var i = 0; i < 5; i++) {"
1149 " try { obj.x = i; } catch (e) { result += e; }"
1150 "}; result"))->Run();
1151 CHECK_EQ(v8_str("01234"), result);
1152}
1153
1154
1155THREADED_TEST(FunctionPrototype) {
1156 v8::HandleScope scope;
1157 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1158 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1159 LocalContext env;
1160 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1161 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1162 CHECK_EQ(script->Run()->Int32Value(), 321);
1163}
1164
1165
1166THREADED_TEST(InternalFields) {
1167 v8::HandleScope scope;
1168 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1169 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1170 instance_templ->SetInternalFieldCount(1);
1171 LocalContext env(0, instance_templ);
1172 CHECK_EQ(1, env->Global()->InternalFieldCount());
1173
1174 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1175 CHECK_EQ(1, obj->InternalFieldCount());
1176 CHECK(obj->GetInternalField(0)->IsUndefined());
1177 obj->SetInternalField(0, v8_num(17));
1178 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1179}
1180
1181
1182THREADED_TEST(External) {
1183 v8::HandleScope scope;
1184 int x = 3;
1185 Local<v8::External> ext = v8::External::New(&x);
1186 LocalContext env;
1187 env->Global()->Set(v8_str("ext"), ext);
1188 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1189 v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1190 int* ptr = static_cast<int*>(reext->Value());
1191 CHECK_EQ(x, 3);
1192 *ptr = 10;
1193 CHECK_EQ(x, 10);
1194}
1195
1196
1197THREADED_TEST(GlobalHandle) {
1198 v8::Persistent<String> global;
1199 {
1200 v8::HandleScope scope;
1201 Local<String> str = v8_str("str");
1202 global = v8::Persistent<String>::New(str);
1203 }
1204 CHECK_EQ(global->Length(), 3);
1205 global.Dispose();
1206}
1207
1208
1209THREADED_TEST(ScriptException) {
1210 v8::HandleScope scope;
1211 LocalContext env;
1212 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1213 v8::TryCatch try_catch;
1214 Local<Value> result = script->Run();
1215 CHECK(result.IsEmpty());
1216 CHECK(try_catch.HasCaught());
1217 String::AsciiValue exception_value(try_catch.Exception());
1218 CHECK_EQ(*exception_value, "panama!");
1219}
1220
1221
1222bool message_received;
1223
1224
1225static void check_message(v8::Handle<v8::Message> message,
1226 v8::Handle<Value> data) {
1227 CHECK_EQ(5.76, data->NumberValue());
1228 CHECK_EQ(6.75, message->GetSourceData()->NumberValue());
1229 message_received = true;
1230}
1231
1232
1233THREADED_TEST(MessageHandlerData) {
1234 message_received = false;
1235 v8::HandleScope scope;
1236 CHECK(!message_received);
1237 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1238 LocalContext context;
1239 v8::ScriptOrigin origin =
1240 v8::ScriptOrigin(v8_str("6.75"));
1241 Script::Compile(v8_str("throw 'error'"), &origin)->Run();
1242 CHECK(message_received);
1243 // clear out the message listener
1244 v8::V8::RemoveMessageListeners(check_message);
1245}
1246
1247
1248THREADED_TEST(GetSetProperty) {
1249 v8::HandleScope scope;
1250 LocalContext context;
1251 context->Global()->Set(v8_str("foo"), v8_num(14));
1252 context->Global()->Set(v8_str("12"), v8_num(92));
1253 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1254 context->Global()->Set(v8_num(13), v8_num(56));
1255 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1256 CHECK_EQ(14, foo->Int32Value());
1257 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1258 CHECK_EQ(92, twelve->Int32Value());
1259 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1260 CHECK_EQ(32, sixteen->Int32Value());
1261 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1262 CHECK_EQ(56, thirteen->Int32Value());
1263 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1264 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1265 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1266 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1267 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1268 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1269 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1270 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1271 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1272}
1273
1274
1275THREADED_TEST(PropertyAttributes) {
1276 v8::HandleScope scope;
1277 LocalContext context;
1278 // read-only
1279 Local<String> prop = v8_str("read_only");
1280 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1281 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1282 Script::Compile(v8_str("read_only = 9"))->Run();
1283 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1284 context->Global()->Set(prop, v8_num(10));
1285 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1286 // dont-delete
1287 prop = v8_str("dont_delete");
1288 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1289 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1290 Script::Compile(v8_str("delete dont_delete"))->Run();
1291 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1292}
1293
1294
1295THREADED_TEST(Array) {
1296 v8::HandleScope scope;
1297 LocalContext context;
1298 Local<v8::Array> array = v8::Array::New();
1299 CHECK_EQ(0, array->Length());
1300 CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1301 CHECK(!array->Has(0));
1302 CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1303 CHECK(!array->Has(100));
1304 array->Set(v8::Integer::New(2), v8_num(7));
1305 CHECK_EQ(3, array->Length());
1306 CHECK(!array->Has(0));
1307 CHECK(!array->Has(1));
1308 CHECK(array->Has(2));
1309 CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1310 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1311 Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1312 CHECK_EQ(3, arr->Length());
1313 CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1314 CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1315 CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1316}
1317
1318
1319v8::Handle<Value> HandleF(const v8::Arguments& args) {
1320 v8::HandleScope scope;
1321 ApiTestFuzzer::Fuzz();
1322 Local<v8::Array> result = v8::Array::New(args.Length());
1323 for (int i = 0; i < args.Length(); i++)
1324 result->Set(v8::Integer::New(i), args[i]);
1325 return scope.Close(result);
1326}
1327
1328
1329THREADED_TEST(Vector) {
1330 v8::HandleScope scope;
1331 Local<ObjectTemplate> global = ObjectTemplate::New();
1332 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1333 LocalContext context(0, global);
1334
1335 const char* fun = "f()";
1336 Local<v8::Array> a0 =
1337 Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1338 CHECK_EQ(0, a0->Length());
1339
1340 const char* fun2 = "f(11)";
1341 Local<v8::Array> a1 =
1342 Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1343 CHECK_EQ(1, a1->Length());
1344 CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1345
1346 const char* fun3 = "f(12, 13)";
1347 Local<v8::Array> a2 =
1348 Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1349 CHECK_EQ(2, a2->Length());
1350 CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1351 CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1352
1353 const char* fun4 = "f(14, 15, 16)";
1354 Local<v8::Array> a3 =
1355 Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1356 CHECK_EQ(3, a3->Length());
1357 CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1358 CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1359 CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1360
1361 const char* fun5 = "f(17, 18, 19, 20)";
1362 Local<v8::Array> a4 =
1363 Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1364 CHECK_EQ(4, a4->Length());
1365 CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1366 CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1367 CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1368 CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1369}
1370
1371
1372THREADED_TEST(FunctionCall) {
1373 v8::HandleScope scope;
1374 LocalContext context;
1375 CompileRun(
1376 "function Foo() {"
1377 " var result = [];"
1378 " for (var i = 0; i < arguments.length; i++) {"
1379 " result.push(arguments[i]);"
1380 " }"
1381 " return result;"
1382 "}");
1383 Local<Function> Foo =
1384 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1385
1386 v8::Handle<Value>* args0 = NULL;
1387 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1388 CHECK_EQ(0, a0->Length());
1389
1390 v8::Handle<Value> args1[] = { v8_num(1.1) };
1391 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1392 CHECK_EQ(1, a1->Length());
1393 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1394
1395 v8::Handle<Value> args2[] = { v8_num(2.2),
1396 v8_num(3.3) };
1397 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1398 CHECK_EQ(2, a2->Length());
1399 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1400 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1401
1402 v8::Handle<Value> args3[] = { v8_num(4.4),
1403 v8_num(5.5),
1404 v8_num(6.6) };
1405 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1406 CHECK_EQ(3, a3->Length());
1407 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1408 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1409 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1410
1411 v8::Handle<Value> args4[] = { v8_num(7.7),
1412 v8_num(8.8),
1413 v8_num(9.9),
1414 v8_num(10.11) };
1415 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1416 CHECK_EQ(4, a4->Length());
1417 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1418 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1419 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1420 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1421}
1422
1423
1424static const char* js_code_causing_out_of_memory =
1425 "var a = new Array(); while(true) a.push(a);";
1426
1427
1428// These tests run for a long time and prevent us from running tests
1429// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001430TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001431 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001432 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001433 // Set heap limits.
1434 static const int K = 1024;
1435 v8::ResourceConstraints constraints;
1436 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001437 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001438 v8::SetResourceConstraints(&constraints);
1439
1440 // Execute a script that causes out of memory.
1441 v8::HandleScope scope;
1442 LocalContext context;
1443 v8::V8::IgnoreOutOfMemoryException();
1444 Local<Script> script =
1445 Script::Compile(String::New(js_code_causing_out_of_memory));
1446 Local<Value> result = script->Run();
1447
1448 // Check for out of memory state.
1449 CHECK(result.IsEmpty());
1450 CHECK(context->HasOutOfMemoryException());
1451}
1452
1453
1454v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1455 ApiTestFuzzer::Fuzz();
1456
1457 v8::HandleScope scope;
1458 LocalContext context;
1459 Local<Script> script =
1460 Script::Compile(String::New(js_code_causing_out_of_memory));
1461 Local<Value> result = script->Run();
1462
1463 // Check for out of memory state.
1464 CHECK(result.IsEmpty());
1465 CHECK(context->HasOutOfMemoryException());
1466
1467 return result;
1468}
1469
1470
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001471TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001472 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001473 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001474 // Set heap limits.
1475 static const int K = 1024;
1476 v8::ResourceConstraints constraints;
1477 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001478 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001479 v8::SetResourceConstraints(&constraints);
1480
1481 v8::HandleScope scope;
1482 Local<ObjectTemplate> templ = ObjectTemplate::New();
1483 templ->Set(v8_str("ProvokeOutOfMemory"),
1484 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1485 LocalContext context(0, templ);
1486 v8::V8::IgnoreOutOfMemoryException();
1487 Local<Value> result = CompileRun(
1488 "var thrown = false;"
1489 "try {"
1490 " ProvokeOutOfMemory();"
1491 "} catch (e) {"
1492 " thrown = true;"
1493 "}");
1494 // Check for out of memory state.
1495 CHECK(result.IsEmpty());
1496 CHECK(context->HasOutOfMemoryException());
1497}
1498
1499
1500TEST(HugeConsStringOutOfMemory) {
1501 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001502 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001503 v8::HandleScope scope;
1504 LocalContext context;
1505 // Set heap limits.
1506 static const int K = 1024;
1507 v8::ResourceConstraints constraints;
1508 constraints.set_max_young_space_size(256 * K);
1509 constraints.set_max_old_space_size(2 * K * K);
1510 v8::SetResourceConstraints(&constraints);
1511
1512 // Execute a script that causes out of memory.
1513 v8::V8::IgnoreOutOfMemoryException();
1514
1515 // Build huge string. This should fail with out of memory exception.
1516 Local<Value> result = CompileRun(
1517 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1518 "for (var i = 0; i < 21; i++) { str = str + str; }");
1519
1520 // Check for out of memory state.
1521 CHECK(result.IsEmpty());
1522 CHECK(context->HasOutOfMemoryException());
1523}
1524
1525
1526THREADED_TEST(ConstructCall) {
1527 v8::HandleScope scope;
1528 LocalContext context;
1529 CompileRun(
1530 "function Foo() {"
1531 " var result = [];"
1532 " for (var i = 0; i < arguments.length; i++) {"
1533 " result.push(arguments[i]);"
1534 " }"
1535 " return result;"
1536 "}");
1537 Local<Function> Foo =
1538 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1539
1540 v8::Handle<Value>* args0 = NULL;
1541 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1542 CHECK_EQ(0, a0->Length());
1543
1544 v8::Handle<Value> args1[] = { v8_num(1.1) };
1545 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1546 CHECK_EQ(1, a1->Length());
1547 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1548
1549 v8::Handle<Value> args2[] = { v8_num(2.2),
1550 v8_num(3.3) };
1551 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1552 CHECK_EQ(2, a2->Length());
1553 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1554 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1555
1556 v8::Handle<Value> args3[] = { v8_num(4.4),
1557 v8_num(5.5),
1558 v8_num(6.6) };
1559 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1560 CHECK_EQ(3, a3->Length());
1561 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1562 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1563 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1564
1565 v8::Handle<Value> args4[] = { v8_num(7.7),
1566 v8_num(8.8),
1567 v8_num(9.9),
1568 v8_num(10.11) };
1569 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1570 CHECK_EQ(4, a4->Length());
1571 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1572 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1573 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1574 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1575}
1576
1577
1578static void CheckUncle(v8::TryCatch* try_catch) {
1579 CHECK(try_catch->HasCaught());
1580 String::AsciiValue str_value(try_catch->Exception());
1581 CHECK_EQ(*str_value, "uncle?");
1582 try_catch->Reset();
1583}
1584
1585
1586THREADED_TEST(ConversionException) {
1587 v8::HandleScope scope;
1588 LocalContext env;
1589 CompileRun(
1590 "function TestClass() { };"
1591 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1592 "var obj = new TestClass();");
1593 Local<Value> obj = env->Global()->Get(v8_str("obj"));
1594
1595 v8::TryCatch try_catch;
1596
1597 Local<Value> to_string_result = obj->ToString();
1598 CHECK(to_string_result.IsEmpty());
1599 CheckUncle(&try_catch);
1600
1601 Local<Value> to_number_result = obj->ToNumber();
1602 CHECK(to_number_result.IsEmpty());
1603 CheckUncle(&try_catch);
1604
1605 Local<Value> to_integer_result = obj->ToInteger();
1606 CHECK(to_integer_result.IsEmpty());
1607 CheckUncle(&try_catch);
1608
1609 Local<Value> to_uint32_result = obj->ToUint32();
1610 CHECK(to_uint32_result.IsEmpty());
1611 CheckUncle(&try_catch);
1612
1613 Local<Value> to_int32_result = obj->ToInt32();
1614 CHECK(to_int32_result.IsEmpty());
1615 CheckUncle(&try_catch);
1616
1617 Local<Value> to_object_result = v8::Undefined()->ToObject();
1618 CHECK(to_object_result.IsEmpty());
1619 CHECK(try_catch.HasCaught());
1620 try_catch.Reset();
1621
1622 int32_t int32_value = obj->Int32Value();
1623 CHECK_EQ(0, int32_value);
1624 CheckUncle(&try_catch);
1625
1626 uint32_t uint32_value = obj->Uint32Value();
1627 CHECK_EQ(0, uint32_value);
1628 CheckUncle(&try_catch);
1629
1630 double number_value = obj->NumberValue();
1631 CHECK_NE(0, IsNaN(number_value));
1632 CheckUncle(&try_catch);
1633
1634 int64_t integer_value = obj->IntegerValue();
1635 CHECK_EQ(0.0, static_cast<double>(integer_value));
1636 CheckUncle(&try_catch);
1637}
1638
1639
1640v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1641 ApiTestFuzzer::Fuzz();
1642 return v8::ThrowException(v8_str("konto"));
1643}
1644
1645
1646THREADED_TEST(APICatch) {
1647 v8::HandleScope scope;
1648 Local<ObjectTemplate> templ = ObjectTemplate::New();
1649 templ->Set(v8_str("ThrowFromC"),
1650 v8::FunctionTemplate::New(ThrowFromC));
1651 LocalContext context(0, templ);
1652 CompileRun(
1653 "var thrown = false;"
1654 "try {"
1655 " ThrowFromC();"
1656 "} catch (e) {"
1657 " thrown = true;"
1658 "}");
1659 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
1660 CHECK(thrown->BooleanValue());
1661}
1662
1663
1664THREADED_TEST(ExternalScriptException) {
1665 v8::HandleScope scope;
1666 Local<ObjectTemplate> templ = ObjectTemplate::New();
1667 templ->Set(v8_str("ThrowFromC"),
1668 v8::FunctionTemplate::New(ThrowFromC));
1669 LocalContext context(0, templ);
1670
1671 v8::TryCatch try_catch;
1672 Local<Script> script
1673 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
1674 Local<Value> result = script->Run();
1675 CHECK(result.IsEmpty());
1676 CHECK(try_catch.HasCaught());
1677 String::AsciiValue exception_value(try_catch.Exception());
1678 CHECK_EQ("konto", *exception_value);
1679}
1680
1681
1682
1683v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
1684 ApiTestFuzzer::Fuzz();
1685 CHECK_EQ(4, args.Length());
1686 int count = args[0]->Int32Value();
1687 int cInterval = args[2]->Int32Value();
1688 if (count == 0) {
1689 return v8::ThrowException(v8_str("FromC"));
1690 } else {
1691 Local<v8::Object> global = Context::GetCurrent()->Global();
1692 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
1693 v8::Handle<Value> argv[] = { v8_num(count - 1),
1694 args[1],
1695 args[2],
1696 args[3] };
1697 if (count % cInterval == 0) {
1698 v8::TryCatch try_catch;
1699 Local<Value> result =
1700 v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
1701 int expected = args[3]->Int32Value();
1702 if (try_catch.HasCaught()) {
1703 CHECK_EQ(expected, count);
1704 CHECK(!i::Top::has_scheduled_exception());
1705 } else {
1706 CHECK_NE(expected, count);
1707 }
1708 return result;
1709 } else {
1710 return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
1711 }
1712 }
1713}
1714
1715
1716v8::Handle<Value> JSCheck(const v8::Arguments& args) {
1717 ApiTestFuzzer::Fuzz();
1718 CHECK_EQ(3, args.Length());
1719 bool equality = args[0]->BooleanValue();
1720 int count = args[1]->Int32Value();
1721 int expected = args[2]->Int32Value();
1722 if (equality) {
1723 CHECK_EQ(count, expected);
1724 } else {
1725 CHECK_NE(count, expected);
1726 }
1727 return v8::Undefined();
1728}
1729
1730
1731// This test works by making a stack of alternating JavaScript and C
1732// activations. These activations set up exception handlers with regular
1733// intervals, one interval for C activations and another for JavaScript
1734// activations. When enough activations have been created an exception is
1735// thrown and we check that the right activation catches the exception and that
1736// no other activations do. The right activation is always the topmost one with
1737// a handler, regardless of whether it is in JavaScript or C.
1738//
1739// The notation used to describe a test case looks like this:
1740//
1741// *JS[4] *C[3] @JS[2] C[1] JS[0]
1742//
1743// Each entry is an activation, either JS or C. The index is the count at that
1744// level. Stars identify activations with exception handlers, the @ identifies
1745// the exception handler that should catch the exception.
1746THREADED_TEST(ExceptionOrder) {
1747 v8::HandleScope scope;
1748 Local<ObjectTemplate> templ = ObjectTemplate::New();
1749 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
1750 templ->Set(v8_str("CThrowCountDown"),
1751 v8::FunctionTemplate::New(CThrowCountDown));
1752 LocalContext context(0, templ);
1753 CompileRun(
1754 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
1755 " if (count == 0) throw 'FromJS';"
1756 " if (count % jsInterval == 0) {"
1757 " try {"
1758 " var value = CThrowCountDown(count - 1,"
1759 " jsInterval,"
1760 " cInterval,"
1761 " expected);"
1762 " check(false, count, expected);"
1763 " return value;"
1764 " } catch (e) {"
1765 " check(true, count, expected);"
1766 " }"
1767 " } else {"
1768 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
1769 " }"
1770 "}");
1771 Local<Function> fun =
1772 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
1773
1774 const int argc = 4;
1775 // count jsInterval cInterval expected
1776
1777 // *JS[4] *C[3] @JS[2] C[1] JS[0]
1778 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
1779 fun->Call(fun, argc, a0);
1780
1781 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
1782 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
1783 fun->Call(fun, argc, a1);
1784
1785 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
1786 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
1787 fun->Call(fun, argc, a2);
1788
1789 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
1790 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
1791 fun->Call(fun, argc, a3);
1792
1793 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
1794 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
1795 fun->Call(fun, argc, a4);
1796
1797 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
1798 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
1799 fun->Call(fun, argc, a5);
1800}
1801
1802
1803v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
1804 ApiTestFuzzer::Fuzz();
1805 CHECK_EQ(1, args.Length());
1806 return v8::ThrowException(args[0]);
1807}
1808
1809
1810THREADED_TEST(ThrowValues) {
1811 v8::HandleScope scope;
1812 Local<ObjectTemplate> templ = ObjectTemplate::New();
1813 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
1814 LocalContext context(0, templ);
1815 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
1816 "function Run(obj) {"
1817 " try {"
1818 " Throw(obj);"
1819 " } catch (e) {"
1820 " return e;"
1821 " }"
1822 " return 'no exception';"
1823 "}"
1824 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
1825 CHECK_EQ(5, result->Length());
1826 CHECK(result->Get(v8::Integer::New(0))->IsString());
1827 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
1828 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
1829 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
1830 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
1831 CHECK(result->Get(v8::Integer::New(3))->IsNull());
1832 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
1833}
1834
1835
1836THREADED_TEST(CatchZero) {
1837 v8::HandleScope scope;
1838 LocalContext context;
1839 v8::TryCatch try_catch;
1840 CHECK(!try_catch.HasCaught());
1841 Script::Compile(v8_str("throw 10"))->Run();
1842 CHECK(try_catch.HasCaught());
1843 CHECK_EQ(10, try_catch.Exception()->Int32Value());
1844 try_catch.Reset();
1845 CHECK(!try_catch.HasCaught());
1846 Script::Compile(v8_str("throw 0"))->Run();
1847 CHECK(try_catch.HasCaught());
1848 CHECK_EQ(0, try_catch.Exception()->Int32Value());
1849}
1850
1851
1852THREADED_TEST(CatchExceptionFromWith) {
1853 v8::HandleScope scope;
1854 LocalContext context;
1855 v8::TryCatch try_catch;
1856 CHECK(!try_catch.HasCaught());
1857 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
1858 CHECK(try_catch.HasCaught());
1859}
1860
1861
1862THREADED_TEST(Equality) {
1863 v8::HandleScope scope;
1864 LocalContext context;
1865 // Check that equality works at all before relying on CHECK_EQ
1866 CHECK(v8_str("a")->Equals(v8_str("a")));
1867 CHECK(!v8_str("a")->Equals(v8_str("b")));
1868
1869 CHECK_EQ(v8_str("a"), v8_str("a"));
1870 CHECK_NE(v8_str("a"), v8_str("b"));
1871 CHECK_EQ(v8_num(1), v8_num(1));
1872 CHECK_EQ(v8_num(1.00), v8_num(1));
1873 CHECK_NE(v8_num(1), v8_num(2));
1874
1875 // Assume String is not symbol.
1876 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
1877 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
1878 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
1879 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
1880 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
1881 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
1882 Local<Value> not_a_number = v8_num(i::OS::nan_value());
1883 CHECK(!not_a_number->StrictEquals(not_a_number));
1884 CHECK(v8::False()->StrictEquals(v8::False()));
1885 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
1886
1887 v8::Handle<v8::Object> obj = v8::Object::New();
1888 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
1889 CHECK(alias->StrictEquals(obj));
1890 alias.Dispose();
1891}
1892
1893
1894THREADED_TEST(MultiRun) {
1895 v8::HandleScope scope;
1896 LocalContext context;
1897 Local<Script> script = Script::Compile(v8_str("x"));
1898 for (int i = 0; i < 10; i++)
1899 script->Run();
1900}
1901
1902
1903static v8::Handle<Value> GetXValue(Local<String> name,
1904 const AccessorInfo& info) {
1905 ApiTestFuzzer::Fuzz();
1906 CHECK_EQ(info.Data(), v8_str("donut"));
1907 CHECK_EQ(name, v8_str("x"));
1908 return name;
1909}
1910
1911
1912THREADED_TEST(SimplePropertyRead) {
1913 v8::HandleScope scope;
1914 Local<ObjectTemplate> templ = ObjectTemplate::New();
1915 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
1916 LocalContext context;
1917 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1918 Local<Script> script = Script::Compile(v8_str("obj.x"));
1919 for (int i = 0; i < 10; i++) {
1920 Local<Value> result = script->Run();
1921 CHECK_EQ(result, v8_str("x"));
1922 }
1923}
1924
1925
1926v8::Persistent<Value> xValue;
1927
1928
1929static void SetXValue(Local<String> name,
1930 Local<Value> value,
1931 const AccessorInfo& info) {
1932 CHECK_EQ(value, v8_num(4));
1933 CHECK_EQ(info.Data(), v8_str("donut"));
1934 CHECK_EQ(name, v8_str("x"));
1935 CHECK(xValue.IsEmpty());
1936 xValue = v8::Persistent<Value>::New(value);
1937}
1938
1939
1940THREADED_TEST(SimplePropertyWrite) {
1941 v8::HandleScope scope;
1942 Local<ObjectTemplate> templ = ObjectTemplate::New();
1943 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
1944 LocalContext context;
1945 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1946 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
1947 for (int i = 0; i < 10; i++) {
1948 CHECK(xValue.IsEmpty());
1949 script->Run();
1950 CHECK_EQ(v8_num(4), xValue);
1951 xValue.Dispose();
1952 xValue = v8::Persistent<Value>();
1953 }
1954}
1955
1956
1957static v8::Handle<Value> XPropertyGetter(Local<String> property,
1958 const AccessorInfo& info) {
1959 ApiTestFuzzer::Fuzz();
1960 CHECK(info.Data()->IsUndefined());
1961 return property;
1962}
1963
1964
1965THREADED_TEST(NamedInterceporPropertyRead) {
1966 v8::HandleScope scope;
1967 Local<ObjectTemplate> templ = ObjectTemplate::New();
1968 templ->SetNamedPropertyHandler(XPropertyGetter);
1969 LocalContext context;
1970 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1971 Local<Script> script = Script::Compile(v8_str("obj.x"));
1972 for (int i = 0; i < 10; i++) {
1973 Local<Value> result = script->Run();
1974 CHECK_EQ(result, v8_str("x"));
1975 }
1976}
1977
1978THREADED_TEST(MultiContexts) {
1979 v8::HandleScope scope;
1980 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
1981 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
1982
1983 Local<String> password = v8_str("Password");
1984
1985 // Create an environment
1986 LocalContext context0(0, templ);
1987 context0->SetSecurityToken(password);
1988 v8::Handle<v8::Object> global0 = context0->Global();
1989 global0->Set(v8_str("custom"), v8_num(1234));
1990 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
1991
1992 // Create an independent environment
1993 LocalContext context1(0, templ);
1994 context1->SetSecurityToken(password);
1995 v8::Handle<v8::Object> global1 = context1->Global();
1996 global1->Set(v8_str("custom"), v8_num(1234));
1997 CHECK_NE(global0, global1);
1998 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
1999 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2000
2001 // Now create a new context with the old global
2002 LocalContext context2(0, templ, global1);
2003 context2->SetSecurityToken(password);
2004 v8::Handle<v8::Object> global2 = context2->Global();
2005 CHECK_EQ(global1, global2);
2006 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2007 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2008}
2009
2010
2011THREADED_TEST(FunctionPrototypeAcrossContexts) {
2012 // Make sure that functions created by cloning boilerplates cannot
2013 // communicate through their __proto__ field.
2014
2015 v8::HandleScope scope;
2016
2017 LocalContext env0;
2018 v8::Handle<v8::Object> global0 =
2019 env0->Global();
2020 v8::Handle<v8::Object> object0 =
2021 v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2022 v8::Handle<v8::Object> tostring0 =
2023 v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2024 v8::Handle<v8::Object> proto0 =
2025 v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2026 proto0->Set(v8_str("custom"), v8_num(1234));
2027
2028 LocalContext env1;
2029 v8::Handle<v8::Object> global1 =
2030 env1->Global();
2031 v8::Handle<v8::Object> object1 =
2032 v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2033 v8::Handle<v8::Object> tostring1 =
2034 v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2035 v8::Handle<v8::Object> proto1 =
2036 v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2037 CHECK(!proto1->Has(v8_str("custom")));
2038}
2039
2040
2041THREADED_TEST(Regress892105) {
2042 // Make sure that object and array literals created by cloning
2043 // boilerplates cannot communicate through their __proto__
2044 // field. This is rather difficult to check, but we try to add stuff
2045 // to Object.prototype and Array.prototype and create a new
2046 // environment. This should succeed.
2047
2048 v8::HandleScope scope;
2049
2050 Local<String> source = v8_str("Object.prototype.obj = 1234;"
2051 "Array.prototype.arr = 4567;"
2052 "8901");
2053
2054 LocalContext env0;
2055 Local<Script> script0 = Script::Compile(source);
2056 CHECK_EQ(8901.0, script0->Run()->NumberValue());
2057
2058 LocalContext env1;
2059 Local<Script> script1 = Script::Compile(source);
2060 CHECK_EQ(8901.0, script1->Run()->NumberValue());
2061}
2062
2063
2064static void ExpectString(const char* code, const char* expected) {
2065 Local<Value> result = CompileRun(code);
2066 CHECK(result->IsString());
2067 String::AsciiValue ascii(result);
2068 CHECK_EQ(0, strcmp(*ascii, expected));
2069}
2070
2071
2072static void ExpectBoolean(const char* code, bool expected) {
2073 Local<Value> result = CompileRun(code);
2074 CHECK(result->IsBoolean());
2075 CHECK_EQ(expected, result->BooleanValue());
2076}
2077
2078
2079static void ExpectObject(const char* code, Local<Value> expected) {
2080 Local<Value> result = CompileRun(code);
2081 CHECK(result->Equals(expected));
2082}
2083
2084
2085THREADED_TEST(UndetectableObject) {
2086 v8::HandleScope scope;
2087 LocalContext env;
2088
2089 Local<v8::FunctionTemplate> desc =
2090 v8::FunctionTemplate::New(0, v8::Handle<Value>());
2091 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
2092
2093 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2094 env->Global()->Set(v8_str("undetectable"), obj);
2095
2096 ExpectString("undetectable.toString()", "[object Object]");
2097 ExpectString("typeof undetectable", "undefined");
2098 ExpectString("typeof(undetectable)", "undefined");
2099 ExpectBoolean("typeof undetectable == 'undefined'", true);
2100 ExpectBoolean("typeof undetectable == 'object'", false);
2101 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2102 ExpectBoolean("!undetectable", true);
2103
2104 ExpectObject("true&&undetectable", obj);
2105 ExpectBoolean("false&&undetectable", false);
2106 ExpectBoolean("true||undetectable", true);
2107 ExpectObject("false||undetectable", obj);
2108
2109 ExpectObject("undetectable&&true", obj);
2110 ExpectObject("undetectable&&false", obj);
2111 ExpectBoolean("undetectable||true", true);
2112 ExpectBoolean("undetectable||false", false);
2113
2114 ExpectBoolean("undetectable==null", true);
2115 ExpectBoolean("undetectable==undefined", true);
2116 ExpectBoolean("undetectable==undetectable", true);
2117
2118 ExpectBoolean("undetectable===null", false);
2119 ExpectBoolean("undetectable===undefined", true);
2120 ExpectBoolean("undetectable===undetectable", true);
2121}
2122
2123
2124THREADED_TEST(UndetectableString) {
2125 v8::HandleScope scope;
2126 LocalContext env;
2127
2128 Local<String> obj = String::NewUndetectable("foo");
2129 env->Global()->Set(v8_str("undetectable"), obj);
2130
2131 ExpectString("undetectable", "foo");
2132 ExpectString("typeof undetectable", "undefined");
2133 ExpectString("typeof(undetectable)", "undefined");
2134 ExpectBoolean("typeof undetectable == 'undefined'", true);
2135 ExpectBoolean("typeof undetectable == 'string'", false);
2136 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2137 ExpectBoolean("!undetectable", true);
2138
2139 ExpectObject("true&&undetectable", obj);
2140 ExpectBoolean("false&&undetectable", false);
2141 ExpectBoolean("true||undetectable", true);
2142 ExpectObject("false||undetectable", obj);
2143
2144 ExpectObject("undetectable&&true", obj);
2145 ExpectObject("undetectable&&false", obj);
2146 ExpectBoolean("undetectable||true", true);
2147 ExpectBoolean("undetectable||false", false);
2148
2149 ExpectBoolean("undetectable==null", true);
2150 ExpectBoolean("undetectable==undefined", true);
2151 ExpectBoolean("undetectable==undetectable", true);
2152
2153 ExpectBoolean("undetectable===null", false);
2154 ExpectBoolean("undetectable===undefined", true);
2155 ExpectBoolean("undetectable===undetectable", true);
2156}
2157
2158
2159template <typename T> static void USE(T) { }
2160
2161
2162// This test is not intended to be run, just type checked.
2163static void PersistentHandles() {
2164 USE(PersistentHandles);
2165 Local<String> str = v8_str("foo");
2166 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
2167 USE(p_str);
2168 Local<Script> scr = Script::Compile(v8_str(""));
2169 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
2170 USE(p_scr);
2171 Local<ObjectTemplate> templ = ObjectTemplate::New();
2172 v8::Persistent<ObjectTemplate> p_templ =
2173 v8::Persistent<ObjectTemplate>::New(templ);
2174 USE(p_templ);
2175}
2176
2177
2178static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
2179 ApiTestFuzzer::Fuzz();
2180 return v8::Undefined();
2181}
2182
2183
2184THREADED_TEST(GlobalObjectTemplate) {
2185 v8::HandleScope handle_scope;
2186 Local<ObjectTemplate> global_template = ObjectTemplate::New();
2187 global_template->Set(v8_str("JSNI_Log"),
2188 v8::FunctionTemplate::New(HandleLogDelegator));
2189 v8::Persistent<Context> context = Context::New(0, global_template);
2190 Context::Scope context_scope(context);
2191 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
2192 context.Dispose();
2193}
2194
2195
2196static const char* kSimpleExtensionSource =
2197 "function Foo() {"
2198 " return 4;"
2199 "}";
2200
2201
2202THREADED_TEST(SimpleExtensions) {
2203 v8::HandleScope handle_scope;
2204 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
2205 const char* extension_names[] = { "simpletest" };
2206 v8::ExtensionConfiguration extensions(1, extension_names);
2207 v8::Handle<Context> context = Context::New(&extensions);
2208 Context::Scope lock(context);
2209 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2210 CHECK_EQ(result, v8::Integer::New(4));
2211}
2212
2213
2214THREADED_TEST(AutoExtensions) {
2215 v8::HandleScope handle_scope;
2216 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
2217 extension->set_auto_enable(true);
2218 v8::RegisterExtension(extension);
2219 v8::Handle<Context> context = Context::New();
2220 Context::Scope lock(context);
2221 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2222 CHECK_EQ(result, v8::Integer::New(4));
2223}
2224
2225
2226static void CheckDependencies(const char* name, const char* expected) {
2227 v8::HandleScope handle_scope;
2228 v8::ExtensionConfiguration config(1, &name);
2229 LocalContext context(&config);
2230 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
2231}
2232
2233
2234/*
2235 * Configuration:
2236 *
2237 * /-- B <--\
2238 * A <- -- D <-- E
2239 * \-- C <--/
2240 */
2241THREADED_TEST(ExtensionDependency) {
2242 static const char* kEDeps[] = { "D" };
2243 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
2244 static const char* kDDeps[] = { "B", "C" };
2245 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
2246 static const char* kBCDeps[] = { "A" };
2247 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
2248 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
2249 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
2250 CheckDependencies("A", "undefinedA");
2251 CheckDependencies("B", "undefinedAB");
2252 CheckDependencies("C", "undefinedAC");
2253 CheckDependencies("D", "undefinedABCD");
2254 CheckDependencies("E", "undefinedABCDE");
2255 v8::HandleScope handle_scope;
2256 static const char* exts[2] = { "C", "E" };
2257 v8::ExtensionConfiguration config(2, exts);
2258 LocalContext context(&config);
2259 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
2260}
2261
2262
2263static const char* kExtensionTestScript =
2264 "native function A();"
2265 "native function B();"
2266 "native function C();"
2267 "function Foo(i) {"
2268 " if (i == 0) return A();"
2269 " if (i == 1) return B();"
2270 " if (i == 2) return C();"
2271 "}";
2272
2273
2274static v8::Handle<Value> CallFun(const v8::Arguments& args) {
2275 ApiTestFuzzer::Fuzz();
2276 return args.Data();
2277}
2278
2279
2280class FunctionExtension : public Extension {
2281 public:
2282 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
2283 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
2284 v8::Handle<String> name);
2285};
2286
2287
2288static int lookup_count = 0;
2289v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
2290 v8::Handle<String> name) {
2291 lookup_count++;
2292 if (name->Equals(v8_str("A"))) {
2293 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
2294 } else if (name->Equals(v8_str("B"))) {
2295 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
2296 } else if (name->Equals(v8_str("C"))) {
2297 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
2298 } else {
2299 return v8::Handle<v8::FunctionTemplate>();
2300 }
2301}
2302
2303
2304THREADED_TEST(FunctionLookup) {
2305 v8::RegisterExtension(new FunctionExtension());
2306 v8::HandleScope handle_scope;
2307 static const char* exts[1] = { "functiontest" };
2308 v8::ExtensionConfiguration config(1, exts);
2309 LocalContext context(&config);
2310 CHECK_EQ(3, lookup_count);
2311 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
2312 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
2313 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
2314}
2315
2316
2317static const char* last_location;
2318static const char* last_message;
2319void StoringErrorCallback(const char* location, const char* message) {
2320 if (last_location == NULL) {
2321 last_location = location;
2322 last_message = message;
2323 }
2324}
2325
2326
2327// ErrorReporting creates a circular extensions configuration and
2328// tests that the fatal error handler gets called. This renders V8
2329// unusable and therefore this test cannot be run in parallel.
2330TEST(ErrorReporting) {
2331 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
2332 static const char* aDeps[] = { "B" };
2333 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
2334 static const char* bDeps[] = { "A" };
2335 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
2336 last_location = NULL;
2337 v8::ExtensionConfiguration config(1, bDeps);
2338 v8::Handle<Context> context = Context::New(&config);
2339 CHECK(context.IsEmpty());
2340 CHECK_NE(last_location, NULL);
2341}
2342
2343
2344static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
2345 v8::Handle<Value> data) {
2346 CHECK_EQ(v8::Undefined(), data);
2347 CHECK(message->GetScriptResourceName().IsEmpty());
2348 CHECK_EQ(v8::Undefined(), message->GetSourceData());
2349 message->GetLineNumber();
2350 message->GetSourceLine();
2351}
2352
2353
2354THREADED_TEST(ErrorWithMissingScriptInfo) {
2355 v8::HandleScope scope;
2356 LocalContext context;
2357 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
2358 Script::Compile(v8_str("throw Error()"))->Run();
2359 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
2360}
2361
2362
2363int global_index = 0;
2364
2365class Snorkel {
2366 public:
2367 Snorkel() { index_ = global_index++; }
2368 int index_;
2369};
2370
2371class Whammy {
2372 public:
2373 Whammy() {
2374 cursor_ = 0;
2375 }
2376 ~Whammy() {
2377 script_.Dispose();
2378 }
2379 v8::Handle<Script> getScript() {
2380 if (script_.IsEmpty())
2381 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
2382 return Local<Script>(*script_);
2383 }
2384
2385 public:
2386 static const int kObjectCount = 256;
2387 int cursor_;
2388 v8::Persistent<v8::Object> objects_[kObjectCount];
2389 v8::Persistent<Script> script_;
2390};
2391
2392static void HandleWeakReference(v8::Persistent<v8::Object> obj, void* data) {
2393 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
2394 delete snorkel;
2395 obj.ClearWeak();
2396}
2397
2398v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
2399 const AccessorInfo& info) {
2400 Whammy* whammy =
2401 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
2402
2403 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
2404
2405 v8::Handle<v8::Object> obj = v8::Object::New();
2406 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
2407 if (!prev.IsEmpty()) {
2408 prev->Set(v8_str("next"), obj);
2409 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
2410 whammy->objects_[whammy->cursor_].Clear();
2411 }
2412 whammy->objects_[whammy->cursor_] = global;
2413 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
2414 return whammy->getScript()->Run();
2415}
2416
2417THREADED_TEST(WeakReference) {
2418 v8::HandleScope handle_scope;
2419 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
2420 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
2421 0, 0, 0, 0,
2422 v8::External::New(new Whammy()));
2423 const char* extension_list[] = { "v8/gc" };
2424 v8::ExtensionConfiguration extensions(1, extension_list);
2425 v8::Persistent<Context> context = Context::New(&extensions);
2426 Context::Scope context_scope(context);
2427
2428 v8::Handle<v8::Object> interceptor = templ->NewInstance();
2429 context->Global()->Set(v8_str("whammy"), interceptor);
2430 const char* code =
2431 "var last;"
2432 "for (var i = 0; i < 10000; i++) {"
2433 " var obj = whammy.length;"
2434 " if (last) last.next = obj;"
2435 " last = obj;"
2436 "}"
2437 "gc();"
2438 "4";
2439 v8::Handle<Value> result = CompileRun(code);
2440 CHECK_EQ(4.0, result->NumberValue());
2441
2442 context.Dispose();
2443}
2444
2445
2446v8::Handle<Function> args_fun;
2447
2448
2449static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
2450 ApiTestFuzzer::Fuzz();
2451 CHECK_EQ(args_fun, args.Callee());
2452 CHECK_EQ(3, args.Length());
2453 CHECK_EQ(v8::Integer::New(1), args[0]);
2454 CHECK_EQ(v8::Integer::New(2), args[1]);
2455 CHECK_EQ(v8::Integer::New(3), args[2]);
2456 CHECK_EQ(v8::Undefined(), args[3]);
2457 v8::HandleScope scope;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002458 i::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002459 return v8::Undefined();
2460}
2461
2462
2463THREADED_TEST(Arguments) {
2464 v8::HandleScope scope;
2465 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2466 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
2467 LocalContext context(NULL, global);
2468 args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
2469 v8_compile("f(1, 2, 3)")->Run();
2470}
2471
2472
2473static int x_register = 0;
2474static v8::Handle<v8::Object> x_receiver;
2475static v8::Handle<v8::Object> x_holder;
2476
2477
2478static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
2479 ApiTestFuzzer::Fuzz();
2480 CHECK_EQ(x_receiver, info.This());
2481 CHECK_EQ(x_holder, info.Holder());
2482 return v8_num(x_register);
2483}
2484
2485
2486static void XSetter(Local<String> name,
2487 Local<Value> value,
2488 const AccessorInfo& info) {
2489 CHECK_EQ(x_holder, info.This());
2490 CHECK_EQ(x_holder, info.Holder());
2491 x_register = value->Int32Value();
2492}
2493
2494
2495THREADED_TEST(AccessorIC) {
2496 v8::HandleScope scope;
2497 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2498 obj->SetAccessor(v8_str("x"), XGetter, XSetter);
2499 LocalContext context;
2500 x_holder = obj->NewInstance();
2501 context->Global()->Set(v8_str("holder"), x_holder);
2502 x_receiver = v8::Object::New();
2503 context->Global()->Set(v8_str("obj"), x_receiver);
2504 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
2505 "obj.__proto__ = holder;"
2506 "var result = [];"
2507 "for (var i = 0; i < 10; i++) {"
2508 " holder.x = i;"
2509 " result.push(obj.x);"
2510 "}"
2511 "result"));
2512 CHECK_EQ(10, array->Length());
2513 for (int i = 0; i < 10; i++) {
2514 v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
2515 CHECK_EQ(v8::Integer::New(i), entry);
2516 }
2517}
2518
2519
2520static v8::Handle<Value> NoBlockGetterX(Local<String> name,
2521 const AccessorInfo&) {
2522 return v8::Handle<Value>();
2523}
2524
2525
2526static v8::Handle<Value> NoBlockGetterI(uint32_t index,
2527 const AccessorInfo&) {
2528 return v8::Handle<Value>();
2529}
2530
2531
2532static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
2533 const AccessorInfo&) {
2534 if (!name->Equals(v8_str("foo"))) {
2535 return v8::Handle<v8::Boolean>(); // not intercepted
2536 }
2537
2538 return v8::False(); // intercepted, and don't delete the property
2539}
2540
2541
2542static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
2543 if (index != 2) {
2544 return v8::Handle<v8::Boolean>(); // not intercepted
2545 }
2546
2547 return v8::False(); // intercepted, and don't delete the property
2548}
2549
2550
2551THREADED_TEST(Deleter) {
2552 v8::HandleScope scope;
2553 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2554 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
2555 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
2556 LocalContext context;
2557 context->Global()->Set(v8_str("k"), obj->NewInstance());
2558 CompileRun(
2559 "k.foo = 'foo';"
2560 "k.bar = 'bar';"
2561 "k[2] = 2;"
2562 "k[4] = 4;");
2563 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
2564 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
2565
2566 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
2567 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
2568
2569 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
2570 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
2571
2572 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
2573 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
2574}
2575
2576
2577static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
2578 ApiTestFuzzer::Fuzz();
2579 return v8::Undefined();
2580}
2581
2582
2583static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
2584 ApiTestFuzzer::Fuzz();
2585 v8::Handle<v8::Array> result = v8::Array::New(3);
2586 result->Set(v8::Integer::New(0), v8_str("foo"));
2587 result->Set(v8::Integer::New(1), v8_str("bar"));
2588 result->Set(v8::Integer::New(2), v8_str("baz"));
2589 return result;
2590}
2591
2592
2593static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
2594 ApiTestFuzzer::Fuzz();
2595 v8::Handle<v8::Array> result = v8::Array::New(2);
2596 result->Set(v8::Integer::New(0), v8_str("hat"));
2597 result->Set(v8::Integer::New(1), v8_str("gyt"));
2598 return result;
2599}
2600
2601
2602THREADED_TEST(Enumerators) {
2603 v8::HandleScope scope;
2604 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2605 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
2606 obj->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, IndexedEnum);
2607 LocalContext context;
2608 context->Global()->Set(v8_str("k"), obj->NewInstance());
2609 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2610 "var result = [];"
2611 "for (var prop in k) {"
2612 " result.push(prop);"
2613 "}"
2614 "result"));
2615 CHECK_EQ(5, result->Length());
2616 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(0)));
2617 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(1)));
2618 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(2)));
2619 CHECK_EQ(v8_str("hat"), result->Get(v8::Integer::New(3)));
2620 CHECK_EQ(v8_str("gyt"), result->Get(v8::Integer::New(4)));
2621}
2622
2623
2624int p_getter_count;
2625int p_getter_count2;
2626
2627
2628static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
2629 ApiTestFuzzer::Fuzz();
2630 p_getter_count++;
2631 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
2632 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
2633 if (name->Equals(v8_str("p1"))) {
2634 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
2635 } else if (name->Equals(v8_str("p2"))) {
2636 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
2637 } else if (name->Equals(v8_str("p3"))) {
2638 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
2639 } else if (name->Equals(v8_str("p4"))) {
2640 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
2641 }
2642 return v8::Undefined();
2643}
2644
2645
2646static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
2647 ApiTestFuzzer::Fuzz();
2648 LocalContext context;
2649 context->Global()->Set(v8_str("o1"), obj->NewInstance());
2650 CompileRun(
2651 "o1.__proto__ = { };"
2652 "var o2 = { __proto__: o1 };"
2653 "var o3 = { __proto__: o2 };"
2654 "var o4 = { __proto__: o3 };"
2655 "for (var i = 0; i < 10; i++) o4.p4;"
2656 "for (var i = 0; i < 10; i++) o3.p3;"
2657 "for (var i = 0; i < 10; i++) o2.p2;"
2658 "for (var i = 0; i < 10; i++) o1.p1;");
2659}
2660
2661
2662static v8::Handle<Value> PGetter2(Local<String> name,
2663 const AccessorInfo& info) {
2664 ApiTestFuzzer::Fuzz();
2665 p_getter_count2++;
2666 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
2667 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
2668 if (name->Equals(v8_str("p1"))) {
2669 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
2670 } else if (name->Equals(v8_str("p2"))) {
2671 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
2672 } else if (name->Equals(v8_str("p3"))) {
2673 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
2674 } else if (name->Equals(v8_str("p4"))) {
2675 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
2676 }
2677 return v8::Undefined();
2678}
2679
2680
2681THREADED_TEST(GetterHolders) {
2682 v8::HandleScope scope;
2683 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2684 obj->SetAccessor(v8_str("p1"), PGetter);
2685 obj->SetAccessor(v8_str("p2"), PGetter);
2686 obj->SetAccessor(v8_str("p3"), PGetter);
2687 obj->SetAccessor(v8_str("p4"), PGetter);
2688 p_getter_count = 0;
2689 RunHolderTest(obj);
2690 CHECK_EQ(40, p_getter_count);
2691}
2692
2693
2694THREADED_TEST(PreInterceptorHolders) {
2695 v8::HandleScope scope;
2696 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2697 obj->SetNamedPropertyHandler(PGetter2);
2698 p_getter_count2 = 0;
2699 RunHolderTest(obj);
2700 CHECK_EQ(40, p_getter_count2);
2701}
2702
2703
2704THREADED_TEST(ObjectInstantiation) {
2705 v8::HandleScope scope;
2706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
2707 templ->SetAccessor(v8_str("t"), PGetter2);
2708 LocalContext context;
2709 context->Global()->Set(v8_str("o"), templ->NewInstance());
2710 for (int i = 0; i < 100; i++) {
2711 v8::HandleScope inner_scope;
2712 v8::Handle<v8::Object> obj = templ->NewInstance();
2713 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
2714 context->Global()->Set(v8_str("o2"), obj);
2715 v8::Handle<Value> value =
2716 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
2717 CHECK_EQ(v8::True(), value);
2718 context->Global()->Set(v8_str("o"), obj);
2719 }
2720}
2721
2722
2723THREADED_TEST(StringWrite) {
2724 v8::HandleScope scope;
2725 v8::Handle<String> str = v8_str("abcde");
2726
2727 char buf[100];
2728 int len;
2729
2730 memset(buf, 0x1, sizeof(buf));
2731 len = str->WriteAscii(buf);
2732 CHECK_EQ(len, 5);
2733 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
2734
2735 memset(buf, 0x1, sizeof(buf));
2736 len = str->WriteAscii(buf, 0, 4);
2737 CHECK_EQ(len, 4);
2738 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
2739
2740 memset(buf, 0x1, sizeof(buf));
2741 len = str->WriteAscii(buf, 0, 5);
2742 CHECK_EQ(len, 5);
2743 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
2744
2745 memset(buf, 0x1, sizeof(buf));
2746 len = str->WriteAscii(buf, 0, 6);
2747 CHECK_EQ(len, 5);
2748 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
2749
2750 memset(buf, 0x1, sizeof(buf));
2751 len = str->WriteAscii(buf, 4, -1);
2752 CHECK_EQ(len, 1);
2753 CHECK_EQ(strncmp("e\0", buf, 2), 0);
2754
2755 memset(buf, 0x1, sizeof(buf));
2756 len = str->WriteAscii(buf, 4, 6);
2757 CHECK_EQ(len, 1);
2758 CHECK_EQ(strncmp("e\0", buf, 2), 0);
2759
2760 memset(buf, 0x1, sizeof(buf));
2761 len = str->WriteAscii(buf, 4, 1);
2762 CHECK_EQ(len, 1);
2763 CHECK_EQ(strncmp("e\1", buf, 2), 0);
2764}
2765
2766
2767THREADED_TEST(ToArrayIndex) {
2768 v8::HandleScope scope;
2769 LocalContext context;
2770
2771 v8::Handle<String> str = v8_str("42");
2772 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
2773 CHECK(!index.IsEmpty());
2774 CHECK_EQ(42.0, index->Uint32Value());
2775 str = v8_str("42asdf");
2776 index = str->ToArrayIndex();
2777 CHECK(index.IsEmpty());
2778 str = v8_str("-42");
2779 index = str->ToArrayIndex();
2780 CHECK(index.IsEmpty());
2781 str = v8_str("4294967295");
2782 index = str->ToArrayIndex();
2783 CHECK(!index.IsEmpty());
2784 CHECK_EQ(4294967295.0, index->Uint32Value());
2785 v8::Handle<v8::Number> num = v8::Number::New(1);
2786 index = num->ToArrayIndex();
2787 CHECK(!index.IsEmpty());
2788 CHECK_EQ(1.0, index->Uint32Value());
2789 num = v8::Number::New(-1);
2790 index = num->ToArrayIndex();
2791 CHECK(index.IsEmpty());
2792 v8::Handle<v8::Object> obj = v8::Object::New();
2793 index = obj->ToArrayIndex();
2794 CHECK(index.IsEmpty());
2795}
2796
2797
2798THREADED_TEST(ErrorConstruction) {
2799 v8::HandleScope scope;
2800 LocalContext context;
2801
2802 v8::Handle<String> foo = v8_str("foo");
2803 v8::Handle<String> message = v8_str("message");
2804 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
2805 CHECK(range_error->IsObject());
2806 v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
2807 CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
2808 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
2809 CHECK(reference_error->IsObject());
2810 CHECK(
2811 v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
2812 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
2813 CHECK(syntax_error->IsObject());
2814 CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
2815 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
2816 CHECK(type_error->IsObject());
2817 CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
2818 v8::Handle<Value> error = v8::Exception::Error(foo);
2819 CHECK(error->IsObject());
2820 CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
2821}
2822
2823
2824static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
2825 ApiTestFuzzer::Fuzz();
2826 return v8_num(10);
2827}
2828
2829
2830static void YSetter(Local<String> name,
2831 Local<Value> value,
2832 const AccessorInfo& info) {
2833 if (info.This()->Has(name)) {
2834 info.This()->Delete(name);
2835 }
2836 info.This()->Set(name, value);
2837}
2838
2839
2840THREADED_TEST(DeleteAccessor) {
2841 v8::HandleScope scope;
2842 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2843 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
2844 LocalContext context;
2845 v8::Handle<v8::Object> holder = obj->NewInstance();
2846 context->Global()->Set(v8_str("holder"), holder);
2847 v8::Handle<Value> result = CompileRun(
2848 "holder.y = 11; holder.y = 12; holder.y");
2849 CHECK_EQ(12, result->Uint32Value());
2850}
2851
2852
2853THREADED_TEST(TypeSwitch) {
2854 v8::HandleScope scope;
2855 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
2856 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
2857 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
2858 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
2859 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
2860 LocalContext context;
2861 v8::Handle<v8::Object> obj0 = v8::Object::New();
2862 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
2863 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
2864 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
2865 for (int i = 0; i < 10; i++) {
2866 CHECK_EQ(0, type_switch->match(obj0));
2867 CHECK_EQ(1, type_switch->match(obj1));
2868 CHECK_EQ(2, type_switch->match(obj2));
2869 CHECK_EQ(3, type_switch->match(obj3));
2870 CHECK_EQ(3, type_switch->match(obj3));
2871 CHECK_EQ(2, type_switch->match(obj2));
2872 CHECK_EQ(1, type_switch->match(obj1));
2873 CHECK_EQ(0, type_switch->match(obj0));
2874 }
2875}
2876
2877
2878// For use within the TestSecurityHandler() test.
2879static bool g_security_callback_result = false;
2880static bool NamedSecurityTestCallback(Local<v8::Object> global,
2881 Local<Value> name,
2882 v8::AccessType type,
2883 Local<Value> data) {
2884 // Always allow read access.
2885 if (type == v8::ACCESS_GET)
2886 return true;
2887
2888 // Sometimes allow other access.
2889 return g_security_callback_result;
2890}
2891
2892
2893static bool IndexedSecurityTestCallback(Local<v8::Object> global,
2894 uint32_t key,
2895 v8::AccessType type,
2896 Local<Value> data) {
2897 // Always allow read access.
2898 if (type == v8::ACCESS_GET)
2899 return true;
2900
2901 // Sometimes allow other access.
2902 return g_security_callback_result;
2903}
2904
2905
2906static int trouble_nesting = 0;
2907static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
2908 ApiTestFuzzer::Fuzz();
2909 trouble_nesting++;
2910
2911 // Call a JS function that throws an uncaught exception.
2912 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
2913 Local<Value> trouble_callee = (trouble_nesting == 3) ?
2914 arg_this->Get(v8_str("trouble_callee")) :
2915 arg_this->Get(v8_str("trouble_caller"));
2916 CHECK(trouble_callee->IsFunction());
2917 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
2918}
2919
2920
2921static int report_count = 0;
2922static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
2923 v8::Handle<Value>) {
2924 report_count++;
2925}
2926
2927
2928// Counts uncaught exceptions, but other tests running in parallel
2929// also have uncaught exceptions.
2930TEST(ApiUncaughtException) {
2931 v8::HandleScope scope;
2932 LocalContext env;
2933 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
2934
2935 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
2936 v8::Local<v8::Object> global = env->Global();
2937 global->Set(v8_str("trouble"), fun->GetFunction());
2938
2939 Script::Compile(v8_str("function trouble_callee() {"
2940 " var x = null;"
2941 " return x.foo;"
2942 "};"
2943 "function trouble_caller() {"
2944 " trouble();"
2945 "};"))->Run();
2946 Local<Value> trouble = global->Get(v8_str("trouble"));
2947 CHECK(trouble->IsFunction());
2948 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
2949 CHECK(trouble_callee->IsFunction());
2950 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
2951 CHECK(trouble_caller->IsFunction());
2952 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
2953 CHECK_EQ(1, report_count);
2954}
2955
2956
2957// SecurityHandler can't be run twice
2958TEST(SecurityHandler) {
2959 v8::HandleScope scope0;
2960 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2961 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
2962 IndexedSecurityTestCallback);
2963 // Create an environment
2964 v8::Persistent<Context> context0 =
2965 Context::New(NULL, global_template);
2966 context0->Enter();
2967
2968 v8::Handle<v8::Object> global0 = context0->Global();
2969 v8::Handle<Script> script0 = v8_compile("foo = 111");
2970 script0->Run();
2971 global0->Set(v8_str("0"), v8_num(999));
2972 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
2973 CHECK_EQ(111, foo0->Int32Value());
2974 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
2975 CHECK_EQ(999, z0->Int32Value());
2976
2977 // Create another environment, should fail security checks.
2978 v8::HandleScope scope1;
2979
2980 v8::Persistent<Context> context1 =
2981 Context::New(NULL, global_template);
2982 context1->Enter();
2983
2984 v8::Handle<v8::Object> global1 = context1->Global();
2985 global1->Set(v8_str("othercontext"), global0);
2986 // This set will fail the security check.
2987 v8::Handle<Script> script1 =
2988 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
2989 script1->Run();
2990 // This read will pass the security check.
2991 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
2992 CHECK_EQ(111, foo1->Int32Value());
2993 // This read will pass the security check.
2994 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
2995 CHECK_EQ(999, z1->Int32Value());
2996
2997 // Create another environment, should pass security checks.
2998 { g_security_callback_result = true; // allow security handler to pass.
2999 v8::HandleScope scope2;
3000 LocalContext context2;
3001 v8::Handle<v8::Object> global2 = context2->Global();
3002 global2->Set(v8_str("othercontext"), global0);
3003 v8::Handle<Script> script2 =
3004 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3005 script2->Run();
3006 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3007 CHECK_EQ(333, foo2->Int32Value());
3008 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3009 CHECK_EQ(888, z2->Int32Value());
3010 }
3011
3012 context1->Exit();
3013 context1.Dispose();
3014
3015 context0->Exit();
3016 context0.Dispose();
3017}
3018
3019
3020THREADED_TEST(SecurityChecks) {
3021 v8::HandleScope handle_scope;
3022 LocalContext env1;
3023 v8::Persistent<Context> env2 = Context::New();
3024
3025 Local<Value> foo = v8_str("foo");
3026 Local<Value> bar = v8_str("bar");
3027
3028 // Set to the same domain.
3029 env1->SetSecurityToken(foo);
3030
3031 // Create a function in env1.
3032 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3033 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3034 CHECK(spy->IsFunction());
3035
3036 // Create another function accessing global objects.
3037 Script::Compile(v8_str("spy2=function(){return new Array();}"))->Run();
3038 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3039 CHECK(spy2->IsFunction());
3040
3041 // Switch to env2 in the same domain and invoke spy on env2.
3042 {
3043 env2->SetSecurityToken(foo);
3044 // Enter env2
3045 Context::Scope scope_env2(env2);
3046 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3047 CHECK(result->IsFunction());
3048 }
3049
3050 // Change env2 to a new domain and invoke spy on env2. It should be blocked
3051 // by security check.
3052 {
3053 env2->SetSecurityToken(bar);
3054 Context::Scope scope_env2(env2);
3055 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3056 CHECK(result->IsUndefined());
3057
3058 // Call cross_domain_call, it should throw an exception
3059 v8::TryCatch try_catch;
3060 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3061 CHECK(try_catch.HasCaught());
3062 }
3063
3064 env2.Dispose();
3065}
3066
3067
3068// Regression test case for issue 1183439.
3069THREADED_TEST(SecurityChecksForPrototypeChain) {
3070 v8::HandleScope scope;
3071 LocalContext current;
3072 v8::Persistent<Context> other = Context::New();
3073
3074 // Change context to be able to get to the Object function in the
3075 // other context without hitting the security checks.
3076 v8::Local<Value> other_object;
3077 { Context::Scope scope(other);
3078 other_object = other->Global()->Get(v8_str("Object"));
3079 other->Global()->Set(v8_num(42), v8_num(87));
3080 }
3081
3082 current->Global()->Set(v8_str("other"), other->Global());
3083 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3084
3085 // Make sure the security check fails here and we get an undefined
3086 // result instead of getting the Object function. Repeat in a loop
3087 // to make sure to exercise the IC code.
3088 v8::Local<Script> access_other0 = v8_compile("other.Object");
3089 v8::Local<Script> access_other1 = v8_compile("other[42]");
3090 for (int i = 0; i < 5; i++) {
3091 CHECK(!access_other0->Run()->Equals(other_object));
3092 CHECK(access_other0->Run()->IsUndefined());
3093 CHECK(!access_other1->Run()->Equals(v8_num(87)));
3094 CHECK(access_other1->Run()->IsUndefined());
3095 }
3096
3097 // Create an object that has 'other' in its prototype chain and make
3098 // sure we cannot access the Object function indirectly through
3099 // that. Repeat in a loop to make sure to exercise the IC code.
3100 v8_compile("function F() { };"
3101 "F.prototype = other;"
3102 "var f = new F();")->Run();
3103 v8::Local<Script> access_f0 = v8_compile("f.Object");
3104 v8::Local<Script> access_f1 = v8_compile("f[42]");
3105 for (int j = 0; j < 5; j++) {
3106 CHECK(!access_f0->Run()->Equals(other_object));
3107 CHECK(access_f0->Run()->IsUndefined());
3108 CHECK(!access_f1->Run()->Equals(v8_num(87)));
3109 CHECK(access_f1->Run()->IsUndefined());
3110 }
3111
3112 // Now it gets hairy: Set the prototype for the other global object
3113 // to be the current global object. The prototype chain for 'f' now
3114 // goes through 'other' but ends up in the current global object.
3115 { Context::Scope scope(other);
3116 other->Global()->Set(v8_str("__proto__"), current->Global());
3117 }
3118 // Set a named and an index property on the current global
3119 // object. To force the lookup to go through the other global object,
3120 // the properties must not exist in the other global object.
3121 current->Global()->Set(v8_str("foo"), v8_num(100));
3122 current->Global()->Set(v8_num(99), v8_num(101));
3123 // Try to read the properties from f and make sure that the access
3124 // gets stopped by the security checks on the other global object.
3125 Local<Script> access_f2 = v8_compile("f.foo");
3126 Local<Script> access_f3 = v8_compile("f[99]");
3127 for (int k = 0; k < 5; k++) {
3128 CHECK(!access_f2->Run()->Equals(v8_num(100)));
3129 CHECK(access_f2->Run()->IsUndefined());
3130 CHECK(!access_f3->Run()->Equals(v8_num(101)));
3131 CHECK(access_f3->Run()->IsUndefined());
3132 }
3133 other.Dispose();
3134}
3135
3136
3137THREADED_TEST(CrossDomainDelete) {
3138 v8::HandleScope handle_scope;
3139 LocalContext env1;
3140 v8::Persistent<Context> env2 = Context::New();
3141
3142 Local<Value> foo = v8_str("foo");
3143 Local<Value> bar = v8_str("bar");
3144
3145 // Set to the same domain.
3146 env1->SetSecurityToken(foo);
3147 env2->SetSecurityToken(foo);
3148
3149 env1->Global()->Set(v8_str("prop"), v8_num(3));
3150 env2->Global()->Set(v8_str("env1"), env1->Global());
3151
3152 // Change env2 to a different domain and delete env1.prop.
3153 env2->SetSecurityToken(bar);
3154 {
3155 Context::Scope scope_env2(env2);
3156 Local<Value> result =
3157 Script::Compile(v8_str("delete env1.prop"))->Run();
3158 CHECK(result->IsFalse());
3159 }
3160
3161 // Check that env1.prop still exists.
3162 Local<Value> v = env1->Global()->Get(v8_str("prop"));
3163 CHECK(v->IsNumber());
3164 CHECK_EQ(3, v->Int32Value());
3165
3166 env2.Dispose();
3167}
3168
3169
ager@chromium.org236ad962008-09-25 09:45:57 +00003170THREADED_TEST(CrossDomainForIn) {
3171 v8::HandleScope handle_scope;
3172 LocalContext env1;
3173 v8::Persistent<Context> env2 = Context::New();
3174
3175 Local<Value> foo = v8_str("foo");
3176 Local<Value> bar = v8_str("bar");
3177
3178 // Set to the same domain.
3179 env1->SetSecurityToken(foo);
3180 env2->SetSecurityToken(foo);
3181
3182 env1->Global()->Set(v8_str("prop"), v8_num(3));
3183 env2->Global()->Set(v8_str("env1"), env1->Global());
3184
3185 // Change env2 to a different domain and set env1's global object
3186 // as the __proto__ of an object in env2 and enumerate properties
3187 // in for-in. It shouldn't enumerate properties on env1's global
3188 // object.
3189 env2->SetSecurityToken(bar);
3190 {
3191 Context::Scope scope_env2(env2);
3192 Local<Value> result =
3193 CompileRun("(function(){var obj = {'__proto__':env1};"
3194 "for (var p in obj)"
3195 " if (p == 'prop') return false;"
3196 "return true;})()");
3197 CHECK(result->IsTrue());
3198 }
3199 env2.Dispose();
3200}
3201
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003202
3203static bool NamedAccessBlocker(Local<v8::Object> global,
3204 Local<Value> name,
3205 v8::AccessType type,
3206 Local<Value> data) {
3207 return Context::GetCurrentSecurityContext()->Global()->Equals(global);
3208}
3209
3210
3211static bool IndexedAccessBlocker(Local<v8::Object> global,
3212 uint32_t key,
3213 v8::AccessType type,
3214 Local<Value> data) {
3215 return Context::GetCurrentSecurityContext()->Global()->Equals(global);
3216}
3217
3218
3219static int g_echo_value = -1;
3220static v8::Handle<Value> EchoGetter(Local<String> name,
3221 const AccessorInfo& info) {
3222 return v8_num(g_echo_value);
3223}
3224
3225
3226static void EchoSetter(Local<String> name,
3227 Local<Value> value,
3228 const AccessorInfo& info) {
3229 if (value->IsNumber())
3230 g_echo_value = value->Int32Value();
3231}
3232
3233
3234static v8::Handle<Value> UnreachableGetter(Local<String> name,
3235 const AccessorInfo& info) {
3236 CHECK(false); // This function should not be called..
3237 return v8::Undefined();
3238}
3239
3240
3241static void UnreachableSetter(Local<String> name,
3242 Local<Value> value,
3243 const AccessorInfo& info) {
3244 CHECK(false); // This function should nto be called.
3245}
3246
3247
3248THREADED_TEST(AccessControl) {
3249 v8::HandleScope handle_scope;
3250 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3251
3252 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
3253 IndexedAccessBlocker);
3254
3255 // Add an accessor accessible by cross-domain JS code.
3256 global_template->SetAccessor(
3257 v8_str("accessible_prop"),
3258 EchoGetter, EchoSetter,
3259 v8::Handle<Value>(),
3260 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
3261
3262 // Add an accessor that is not accessible by cross-domain JS code.
3263 global_template->SetAccessor(v8_str("blocked_access_prop"),
3264 UnreachableGetter, UnreachableSetter,
3265 v8::Handle<Value>(),
3266 v8::DEFAULT);
3267
3268 // Create an environment
3269 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3270 context0->Enter();
3271
3272 v8::Handle<v8::Object> global0 = context0->Global();
3273
3274 v8::HandleScope scope1;
3275
3276 v8::Persistent<Context> context1 = Context::New();
3277 context1->Enter();
3278
3279 v8::Handle<v8::Object> global1 = context1->Global();
3280 global1->Set(v8_str("other"), global0);
3281
3282 v8::Handle<Value> value;
3283
3284 // Access blocked property
3285 value = v8_compile("other.blocked_prop = 1")->Run();
3286 value = v8_compile("other.blocked_prop")->Run();
3287 CHECK(value->IsUndefined());
3288
3289 // Access accessible property
3290 value = v8_compile("other.accessible_prop = 3")->Run();
3291 CHECK(value->IsNumber());
3292 CHECK_EQ(3, value->Int32Value());
3293
3294 value = v8_compile("other.accessible_prop")->Run();
3295 CHECK(value->IsNumber());
3296 CHECK_EQ(3, value->Int32Value());
3297
3298 context1->Exit();
3299 context0->Exit();
3300 context1.Dispose();
3301 context0.Dispose();
3302}
3303
3304
3305static v8::Handle<Value> ConstTenGetter(Local<String> name,
3306 const AccessorInfo& info) {
3307 return v8_num(10);
3308}
3309
3310
3311THREADED_TEST(CrossDomainAccessors) {
3312 v8::HandleScope handle_scope;
3313
3314 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
3315
3316 v8::Handle<v8::ObjectTemplate> global_template =
3317 func_template->InstanceTemplate();
3318
3319 v8::Handle<v8::ObjectTemplate> proto_template =
3320 func_template->PrototypeTemplate();
3321
3322 // Add an accessor to proto that's accessible by cross-domain JS code.
3323 proto_template->SetAccessor(v8_str("accessible"),
3324 ConstTenGetter, 0,
3325 v8::Handle<Value>(),
3326 v8::ALL_CAN_READ);
3327
3328 // Add an accessor that is not accessible by cross-domain JS code.
3329 global_template->SetAccessor(v8_str("unreachable"),
3330 UnreachableGetter, 0,
3331 v8::Handle<Value>(),
3332 v8::DEFAULT);
3333
3334 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3335 context0->Enter();
3336
3337 Local<v8::Object> global = context0->Global();
3338 // Add a normal property that shadows 'accessible'
3339 global->Set(v8_str("accessible"), v8_num(11));
3340
3341 // Enter a new context.
3342 v8::HandleScope scope1;
3343 v8::Persistent<Context> context1 = Context::New();
3344 context1->Enter();
3345
3346 v8::Handle<v8::Object> global1 = context1->Global();
3347 global1->Set(v8_str("other"), global);
3348
3349 // Should return 10, instead of 11
3350 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
3351 CHECK(value->IsNumber());
3352 CHECK_EQ(10, value->Int32Value());
3353
3354 value = v8_compile("other.unreachable")->Run();
3355 CHECK(value->IsUndefined());
3356
3357 context1->Exit();
3358 context0->Exit();
3359 context1.Dispose();
3360 context0.Dispose();
3361}
3362
3363
3364static int named_access_count = 0;
3365static int indexed_access_count = 0;
3366
3367static bool NamedAccessCounter(Local<v8::Object> global,
3368 Local<Value> name,
3369 v8::AccessType type,
3370 Local<Value> data) {
3371 named_access_count++;
3372 return true;
3373}
3374
3375
3376static bool IndexedAccessCounter(Local<v8::Object> global,
3377 uint32_t key,
3378 v8::AccessType type,
3379 Local<Value> data) {
3380 indexed_access_count++;
3381 return true;
3382}
3383
3384
3385// This one is too easily disturbed by other tests.
3386TEST(AccessControlIC) {
3387 named_access_count = 0;
3388 indexed_access_count = 0;
3389
3390 v8::HandleScope handle_scope;
3391
3392 // Create an environment.
3393 v8::Persistent<Context> context0 = Context::New();
3394 context0->Enter();
3395
3396 // Create an object that requires access-check functions to be
3397 // called for cross-domain access.
3398 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3399 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
3400 IndexedAccessCounter);
3401 Local<v8::Object> object = object_template->NewInstance();
3402
3403 v8::HandleScope scope1;
3404
3405 // Create another environment.
3406 v8::Persistent<Context> context1 = Context::New();
3407 context1->Enter();
3408
3409 // Make easy access to the object from the other environment.
3410 v8::Handle<v8::Object> global1 = context1->Global();
3411 global1->Set(v8_str("obj"), object);
3412
3413 v8::Handle<Value> value;
3414
3415 // Check that the named access-control function is called every time.
3416 value = v8_compile("for (var i = 0; i < 10; i++) obj.prop = 1;")->Run();
3417 value = v8_compile("for (var i = 0; i < 10; i++) obj.prop;"
3418 "obj.prop")->Run();
3419 CHECK(value->IsNumber());
3420 CHECK_EQ(1, value->Int32Value());
3421 CHECK_EQ(21, named_access_count);
3422
3423 // Check that the named access-control function is called every time.
3424 value = v8_compile("var p = 'prop';")->Run();
3425 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
3426 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
3427 "obj[p]")->Run();
3428 CHECK(value->IsNumber());
3429 CHECK_EQ(1, value->Int32Value());
3430 CHECK_EQ(42, named_access_count);
3431
3432 // Check that the indexed access-control function is called every time.
3433 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
3434 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
3435 "obj[0]")->Run();
3436 CHECK(value->IsNumber());
3437 CHECK_EQ(1, value->Int32Value());
3438 CHECK_EQ(21, indexed_access_count);
3439
3440 context1->Exit();
3441 context0->Exit();
3442 context1.Dispose();
3443 context0.Dispose();
3444}
3445
3446
3447static bool NamedAccessFlatten(Local<v8::Object> global,
3448 Local<Value> name,
3449 v8::AccessType type,
3450 Local<Value> data) {
3451 char buf[100];
3452 int len;
3453
3454 CHECK(name->IsString());
3455
3456 memset(buf, 0x1, sizeof(buf));
3457 len = Local<String>::Cast(name)->WriteAscii(buf);
3458 CHECK_EQ(4, len);
3459
3460 uint16_t buf2[100];
3461
3462 memset(buf, 0x1, sizeof(buf));
3463 len = Local<String>::Cast(name)->Write(buf2);
3464 CHECK_EQ(4, len);
3465
3466 return true;
3467}
3468
3469
3470static bool IndexedAccessFlatten(Local<v8::Object> global,
3471 uint32_t key,
3472 v8::AccessType type,
3473 Local<Value> data) {
3474 return true;
3475}
3476
3477
3478// Regression test. In access checks, operations that may cause
3479// garbage collection are not allowed. It used to be the case that
3480// using the Write operation on a string could cause a garbage
3481// collection due to flattening of the string. This is no longer the
3482// case.
3483THREADED_TEST(AccessControlFlatten) {
3484 named_access_count = 0;
3485 indexed_access_count = 0;
3486
3487 v8::HandleScope handle_scope;
3488
3489 // Create an environment.
3490 v8::Persistent<Context> context0 = Context::New();
3491 context0->Enter();
3492
3493 // Create an object that requires access-check functions to be
3494 // called for cross-domain access.
3495 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3496 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
3497 IndexedAccessFlatten);
3498 Local<v8::Object> object = object_template->NewInstance();
3499
3500 v8::HandleScope scope1;
3501
3502 // Create another environment.
3503 v8::Persistent<Context> context1 = Context::New();
3504 context1->Enter();
3505
3506 // Make easy access to the object from the other environment.
3507 v8::Handle<v8::Object> global1 = context1->Global();
3508 global1->Set(v8_str("obj"), object);
3509
3510 v8::Handle<Value> value;
3511
3512 value = v8_compile("var p = 'as' + 'df';")->Run();
3513 value = v8_compile("obj[p];")->Run();
3514
3515 context1->Exit();
3516 context0->Exit();
3517 context1.Dispose();
3518 context0.Dispose();
3519}
3520
3521
3522static v8::Handle<Value> AccessControlNamedGetter(Local<String> name,
3523 const AccessorInfo& info) {
3524 return v8::Integer::New(42);
3525}
3526
3527
3528static v8::Handle<Value> AccessControlNamedSetter(Local<String> key,
3529 Local<Value> value,
3530 const AccessorInfo&) {
3531 return value;
3532}
3533
3534
3535static v8::Handle<Value> AccessControlIndexedGetter(
3536 uint32_t index,
3537 const AccessorInfo& info) {
3538 return v8_num(42);
3539}
3540
3541
3542static v8::Handle<Value> AccessControlIndexedSetter(uint32_t index,
3543 Local<Value> value,
3544 const AccessorInfo&) {
3545 return value;
3546}
3547
3548
3549THREADED_TEST(AccessControlInterceptorIC) {
3550 named_access_count = 0;
3551 indexed_access_count = 0;
3552
3553 v8::HandleScope handle_scope;
3554
3555 // Create an environment.
3556 v8::Persistent<Context> context0 = Context::New();
3557 context0->Enter();
3558
3559 // Create an object that requires access-check functions to be
3560 // called for cross-domain access. The object also has interceptors
3561 // interceptor.
3562 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3563 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
3564 IndexedAccessCounter);
3565 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
3566 AccessControlNamedSetter);
3567 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
3568 AccessControlIndexedSetter);
3569 Local<v8::Object> object = object_template->NewInstance();
3570
3571 v8::HandleScope scope1;
3572
3573 // Create another environment.
3574 v8::Persistent<Context> context1 = Context::New();
3575 context1->Enter();
3576
3577 // Make easy access to the object from the other environment.
3578 v8::Handle<v8::Object> global1 = context1->Global();
3579 global1->Set(v8_str("obj"), object);
3580
3581 v8::Handle<Value> value;
3582
3583 // Check that the named access-control function is called every time
3584 // eventhough there is an interceptor on the object.
3585 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
3586 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
3587 "obj.x")->Run();
3588 CHECK(value->IsNumber());
3589 CHECK_EQ(42, value->Int32Value());
3590 CHECK_EQ(21, named_access_count);
3591
3592 value = v8_compile("var p = 'x';")->Run();
3593 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
3594 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
3595 "obj[p]")->Run();
3596 CHECK(value->IsNumber());
3597 CHECK_EQ(42, value->Int32Value());
3598 CHECK_EQ(42, named_access_count);
3599
3600 // Check that the indexed access-control function is called every
3601 // time eventhough there is an interceptor on the object.
3602 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
3603 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
3604 "obj[0]")->Run();
3605 CHECK(value->IsNumber());
3606 CHECK_EQ(42, value->Int32Value());
3607 CHECK_EQ(21, indexed_access_count);
3608
3609 context1->Exit();
3610 context0->Exit();
3611 context1.Dispose();
3612 context0.Dispose();
3613}
3614
3615
3616THREADED_TEST(Version) {
3617 v8::V8::GetVersion();
3618}
3619
3620
3621static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
3622 ApiTestFuzzer::Fuzz();
3623 return v8_num(12);
3624}
3625
3626
3627THREADED_TEST(InstanceProperties) {
3628 v8::HandleScope handle_scope;
3629 LocalContext context;
3630
3631 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3632 Local<ObjectTemplate> instance = t->InstanceTemplate();
3633
3634 instance->Set(v8_str("x"), v8_num(42));
3635 instance->Set(v8_str("f"),
3636 v8::FunctionTemplate::New(InstanceFunctionCallback));
3637
3638 Local<Value> o = t->GetFunction()->NewInstance();
3639
3640 context->Global()->Set(v8_str("i"), o);
3641 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
3642 CHECK_EQ(42, value->Int32Value());
3643
3644 value = Script::Compile(v8_str("i.f()"))->Run();
3645 CHECK_EQ(12, value->Int32Value());
3646}
3647
3648
3649static v8::Handle<Value>
3650GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
3651 ApiTestFuzzer::Fuzz();
3652 return v8::Handle<Value>();
3653}
3654
3655
3656THREADED_TEST(GlobalObjectInstanceProperties) {
3657 v8::HandleScope handle_scope;
3658
3659 Local<Value> global_object;
3660
3661 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3662 t->InstanceTemplate()->SetNamedPropertyHandler(
3663 GlobalObjectInstancePropertiesGet);
3664 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
3665 instance_template->Set(v8_str("x"), v8_num(42));
3666 instance_template->Set(v8_str("f"),
3667 v8::FunctionTemplate::New(InstanceFunctionCallback));
3668
3669 {
3670 LocalContext env(NULL, instance_template);
3671 // Hold on to the global object so it can be used again in another
3672 // environment initialization.
3673 global_object = env->Global();
3674
3675 Local<Value> value = Script::Compile(v8_str("x"))->Run();
3676 CHECK_EQ(42, value->Int32Value());
3677 value = Script::Compile(v8_str("f()"))->Run();
3678 CHECK_EQ(12, value->Int32Value());
3679 }
3680
3681 {
3682 // Create new environment reusing the global object.
3683 LocalContext env(NULL, instance_template, global_object);
3684 Local<Value> value = Script::Compile(v8_str("x"))->Run();
3685 CHECK_EQ(42, value->Int32Value());
3686 value = Script::Compile(v8_str("f()"))->Run();
3687 CHECK_EQ(12, value->Int32Value());
3688 }
3689}
3690
3691
3692static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
3693 ApiTestFuzzer::Fuzz();
3694 return v8_num(42);
3695}
3696
3697
3698static int shadow_y;
3699static int shadow_y_setter_call_count;
3700static int shadow_y_getter_call_count;
3701
3702
3703static void ShadowYSetter(Local<String> name,
3704 Local<Value> value,
3705 const AccessorInfo& info) {
3706 shadow_y_setter_call_count++;
3707 shadow_y = 42;
3708}
3709
3710
3711static v8::Handle<Value> ShadowYGetter(Local<String> name,
3712 const AccessorInfo& info) {
3713 ApiTestFuzzer::Fuzz();
3714 shadow_y_getter_call_count++;
3715 return v8_num(shadow_y);
3716}
3717
3718
3719static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
3720 const AccessorInfo& info) {
3721 return v8::Handle<Value>();
3722}
3723
3724
3725static v8::Handle<Value> ShadowNamedGet(Local<String> key,
3726 const AccessorInfo&) {
3727 return v8::Handle<Value>();
3728}
3729
3730
3731THREADED_TEST(ShadowObject) {
3732 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
3733 v8::HandleScope handle_scope;
3734
3735 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
3736 LocalContext context(NULL, global_template);
3737
3738 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3739 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
3740 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
3741 Local<ObjectTemplate> proto = t->PrototypeTemplate();
3742 Local<ObjectTemplate> instance = t->InstanceTemplate();
3743
3744 // Only allow calls of f on instances of t.
3745 Local<v8::Signature> signature = v8::Signature::New(t);
3746 proto->Set(v8_str("f"),
3747 v8::FunctionTemplate::New(ShadowFunctionCallback,
3748 Local<Value>(),
3749 signature));
3750 proto->Set(v8_str("x"), v8_num(12));
3751
3752 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
3753
3754 Local<Value> o = t->GetFunction()->NewInstance();
3755 context->Global()->Set(v8_str("__proto__"), o);
3756
3757 Local<Value> value =
3758 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
3759 CHECK(value->IsBoolean());
3760 CHECK(!value->BooleanValue());
3761
3762 value = Script::Compile(v8_str("x"))->Run();
3763 CHECK_EQ(12, value->Int32Value());
3764
3765 value = Script::Compile(v8_str("f()"))->Run();
3766 CHECK_EQ(42, value->Int32Value());
3767
3768 Script::Compile(v8_str("y = 42"))->Run();
3769 CHECK_EQ(1, shadow_y_setter_call_count);
3770 value = Script::Compile(v8_str("y"))->Run();
3771 CHECK_EQ(1, shadow_y_getter_call_count);
3772 CHECK_EQ(42, value->Int32Value());
3773}
3774
3775
3776THREADED_TEST(HiddenPrototype) {
3777 v8::HandleScope handle_scope;
3778 LocalContext context;
3779
3780 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
3781 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
3782 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
3783 t1->SetHiddenPrototype(true);
3784 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
3785 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
3786 t2->SetHiddenPrototype(true);
3787 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
3788 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
3789 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
3790
3791 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
3792 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
3793 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
3794 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
3795
3796 // Setting the prototype on an object skips hidden prototypes.
3797 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3798 o0->Set(v8_str("__proto__"), o1);
3799 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3800 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3801 o0->Set(v8_str("__proto__"), o2);
3802 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3803 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3804 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
3805 o0->Set(v8_str("__proto__"), o3);
3806 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3807 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3808 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
3809 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
3810
3811 // Getting the prototype of o0 should get the first visible one
3812 // which is o3. Therefore, z should not be defined on the prototype
3813 // object.
3814 Local<Value> proto = o0->Get(v8_str("__proto__"));
3815 CHECK(proto->IsObject());
3816 CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
3817}
3818
3819
3820THREADED_TEST(GetterSetterExceptions) {
3821 v8::HandleScope handle_scope;
3822 LocalContext context;
3823 CompileRun(
3824 "function Foo() { };"
3825 "function Throw() { throw 5; };"
3826 "var x = { };"
3827 "x.__defineSetter__('set', Throw);"
3828 "x.__defineGetter__('get', Throw);");
3829 Local<v8::Object> x =
3830 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
3831 v8::TryCatch try_catch;
3832 x->Set(v8_str("set"), v8::Integer::New(8));
3833 x->Get(v8_str("get"));
3834 x->Set(v8_str("set"), v8::Integer::New(8));
3835 x->Get(v8_str("get"));
3836 x->Set(v8_str("set"), v8::Integer::New(8));
3837 x->Get(v8_str("get"));
3838 x->Set(v8_str("set"), v8::Integer::New(8));
3839 x->Get(v8_str("get"));
3840}
3841
3842
3843THREADED_TEST(Constructor) {
3844 v8::HandleScope handle_scope;
3845 LocalContext context;
3846 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
3847 templ->SetClassName(v8_str("Fun"));
3848 Local<Function> cons = templ->GetFunction();
3849 context->Global()->Set(v8_str("Fun"), cons);
3850 Local<v8::Object> inst = cons->NewInstance();
3851 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
3852 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
3853 CHECK(value->BooleanValue());
3854}
3855
3856THREADED_TEST(FunctionDescriptorException) {
3857 v8::HandleScope handle_scope;
3858 LocalContext context;
3859 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
3860 templ->SetClassName(v8_str("Fun"));
3861 Local<Function> cons = templ->GetFunction();
3862 context->Global()->Set(v8_str("Fun"), cons);
3863 Local<Value> value = CompileRun(
3864 "function test() {"
3865 " try {"
3866 " (new Fun()).blah()"
3867 " } catch (e) {"
3868 " var str = String(e);"
3869 " if (str.indexOf('TypeError') == -1) return 1;"
3870 " if (str.indexOf('[object Fun]') != -1) return 2;"
3871 " if (str.indexOf('#<a Fun>') == -1) return 3;"
3872 " return 0;"
3873 " }"
3874 " return 4;"
3875 "}"
3876 "test();");
3877 CHECK_EQ(0, value->Int32Value());
3878}
3879
3880
3881THREADED_TEST(CrossEval) {
3882 v8::HandleScope scope;
3883 LocalContext other;
3884 LocalContext current;
3885
3886 Local<String> token = v8_str("<security token>");
3887 other->SetSecurityToken(token);
3888 current->SetSecurityToken(token);
3889
3890 // Setup reference from current to other.
3891 current->Global()->Set(v8_str("other"), other->Global());
3892
3893 // Check that new variables are introduced in other context.
3894 Local<Script> script =
3895 Script::Compile(v8_str("other.eval('var foo = 1234')"));
3896 script->Run();
3897 Local<Value> foo = other->Global()->Get(v8_str("foo"));
3898 CHECK_EQ(1234, foo->Int32Value());
3899 CHECK(!current->Global()->Has(v8_str("foo")));
3900
3901 // Check that writing to non-existing properties introduces them in
3902 // the current context.
3903 script =
3904 Script::Compile(v8_str("other.eval('na = 1234')"));
3905 script->Run();
3906 CHECK_EQ(1234, current->Global()->Get(v8_str("na"))->Int32Value());
3907 CHECK(!other->Global()->Has(v8_str("na")));
3908
3909 // Check that variables in current context are visible in other
3910 // context. This must include local variables.
3911 script =
3912 Script::Compile(v8_str("var bar = 42;"
3913 "(function() { "
3914 " var baz = 87;"
3915 " return other.eval('bar + baz');"
3916 "})();"));
3917 Local<Value> result = script->Run();
3918 CHECK_EQ(42 + 87, result->Int32Value());
3919
3920 // Check that global variables in the other environment are visible
3921 // when evaluting code.
3922 other->Global()->Set(v8_str("bis"), v8_num(1234));
3923 script = Script::Compile(v8_str("other.eval('bis')"));
3924 CHECK_EQ(1234, script->Run()->Int32Value());
3925
3926 // Check that the 'this' pointer isn't touched as a result of
3927 // calling eval across environments.
3928 script =
3929 Script::Compile(v8_str("var t = this; other.eval('this == t')"));
3930 result = script->Run();
3931 CHECK(result->IsBoolean());
3932 CHECK(result->BooleanValue());
3933
3934 // Check that doing a cross eval works from within a global
3935 // with-statement.
3936 script =
3937 Script::Compile(v8_str("other.y = 1;"
3938 "with({x:2}){other.eval('x+y')}"));
3939 result = script->Run();
3940 CHECK_EQ(3, result->Int32Value());
3941}
3942
3943
3944THREADED_TEST(CrossLazyLoad) {
3945 v8::HandleScope scope;
3946 LocalContext other;
3947 LocalContext current;
3948
3949 Local<String> token = v8_str("<security token>");
3950 other->SetSecurityToken(token);
3951 current->SetSecurityToken(token);
3952
3953 // Setup reference from current to other.
3954 current->Global()->Set(v8_str("other"), other->Global());
3955
3956 // Trigger lazy loading in other context.
3957 Local<Script> script =
3958 Script::Compile(v8_str("other.eval('new Date(42)')"));
3959 Local<Value> value = script->Run();
3960 CHECK_EQ(42.0, value->NumberValue());
3961}
3962
3963
3964static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
3965 ApiTestFuzzer::Fuzz();
3966 return args[0];
3967}
3968
3969
3970// Test that a call handler can be set for objects which will allow
3971// non-function objects created through the API to be called as
3972// functions.
3973THREADED_TEST(CallAsFunction) {
3974 v8::HandleScope scope;
3975 LocalContext context;
3976
3977 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3978 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
3979 instance_template->SetCallAsFunctionHandler(call_as_function);
3980 Local<v8::Object> instance = t->GetFunction()->NewInstance();
3981 context->Global()->Set(v8_str("obj"), instance);
3982 v8::TryCatch try_catch;
3983 Local<Value> value;
3984 CHECK(!try_catch.HasCaught());
3985
3986 value = Script::Compile(v8_str("obj(42)"))->Run();
3987 CHECK(!try_catch.HasCaught());
3988 CHECK_EQ(42, value->Int32Value());
3989
3990 value = Script::Compile(v8_str("(function(o){return o(49)})(obj)"))->Run();
3991 CHECK(!try_catch.HasCaught());
3992 CHECK_EQ(49, value->Int32Value());
3993
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003994 // test special case of call as function
3995 value = Script::Compile(v8_str("[obj]['0'](45)"))->Run();
3996 CHECK(!try_catch.HasCaught());
3997 CHECK_EQ(45, value->Int32Value());
3998
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003999 value = Script::Compile(v8_str("obj.call = Function.prototype.call;"
4000 "obj.call(null, 87)"))->Run();
4001 CHECK(!try_catch.HasCaught());
4002 CHECK_EQ(87, value->Int32Value());
4003
4004 // Regression tests for bug #1116356: Calling call through call/apply
4005 // must work for non-function receivers.
4006 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
4007 value = Script::Compile(v8_str(apply_99))->Run();
4008 CHECK(!try_catch.HasCaught());
4009 CHECK_EQ(99, value->Int32Value());
4010
4011 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
4012 value = Script::Compile(v8_str(call_17))->Run();
4013 CHECK(!try_catch.HasCaught());
4014 CHECK_EQ(17, value->Int32Value());
4015
4016 // Try something that will cause an exception: Call the object as a
4017 // constructor. This should be the last test.
4018 value = Script::Compile(v8_str("new obj(42)"))->Run();
4019 CHECK(try_catch.HasCaught());
4020}
4021
4022
4023static int CountHandles() {
4024 return v8::HandleScope::NumberOfHandles();
4025}
4026
4027
4028static int Recurse(int depth, int iterations) {
4029 v8::HandleScope scope;
4030 if (depth == 0) return CountHandles();
4031 for (int i = 0; i < iterations; i++) {
4032 Local<v8::Number> n = v8::Integer::New(42);
4033 }
4034 return Recurse(depth - 1, iterations);
4035}
4036
4037
4038THREADED_TEST(HandleIteration) {
4039 static const int kIterations = 500;
4040 static const int kNesting = 200;
4041 CHECK_EQ(0, CountHandles());
4042 {
4043 v8::HandleScope scope1;
4044 CHECK_EQ(0, CountHandles());
4045 for (int i = 0; i < kIterations; i++) {
4046 Local<v8::Number> n = v8::Integer::New(42);
4047 CHECK_EQ(i + 1, CountHandles());
4048 }
4049
4050 CHECK_EQ(kIterations, CountHandles());
4051 {
4052 v8::HandleScope scope2;
4053 for (int j = 0; j < kIterations; j++) {
4054 Local<v8::Number> n = v8::Integer::New(42);
4055 CHECK_EQ(j + 1 + kIterations, CountHandles());
4056 }
4057 }
4058 CHECK_EQ(kIterations, CountHandles());
4059 }
4060 CHECK_EQ(0, CountHandles());
4061 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
4062}
4063
4064
4065static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
4066 Local<String> name,
4067 const AccessorInfo& info) {
4068 ApiTestFuzzer::Fuzz();
4069 return v8::Handle<Value>();
4070}
4071
4072
4073THREADED_TEST(InterceptorHasOwnProperty) {
4074 v8::HandleScope scope;
4075 LocalContext context;
4076 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4077 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
4078 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
4079 Local<Function> function = fun_templ->GetFunction();
4080 context->Global()->Set(v8_str("constructor"), function);
4081 v8::Handle<Value> value = CompileRun(
4082 "var o = new constructor();"
4083 "o.hasOwnProperty('ostehaps');");
4084 CHECK_EQ(false, value->BooleanValue());
4085 value = CompileRun(
4086 "o.ostehaps = 42;"
4087 "o.hasOwnProperty('ostehaps');");
4088 CHECK_EQ(true, value->BooleanValue());
4089 value = CompileRun(
4090 "var p = new constructor();"
4091 "p.hasOwnProperty('ostehaps');");
4092 CHECK_EQ(false, value->BooleanValue());
4093}
4094
4095
4096static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
4097 const AccessorInfo& info) {
4098 ApiTestFuzzer::Fuzz();
4099 CHECK(v8_str("x")->Equals(name));
4100 return v8::Integer::New(42);
4101}
4102
4103
4104// This test should hit the load IC for the interceptor case.
4105THREADED_TEST(InterceptorLoadIC) {
4106 v8::HandleScope scope;
4107 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4108 templ->SetNamedPropertyHandler(InterceptorLoadICGetter);
4109 LocalContext context;
4110 context->Global()->Set(v8_str("o"), templ->NewInstance());
4111 v8::Handle<Value> value = CompileRun(
4112 "var result = 0;"
4113 "for (var i = 0; i < 1000; i++) {"
4114 " result = o.x;"
4115 "}");
4116 CHECK_EQ(42, value->Int32Value());
4117}
4118
4119
4120static v8::Handle<Value> InterceptorStoreICSetter(
4121 Local<String> key,
4122 Local<Value> value,
4123 const AccessorInfo&) {
4124 CHECK(v8_str("x")->Equals(key));
4125 CHECK_EQ(42, value->Int32Value());
4126 return value;
4127}
4128
4129
4130// This test should hit the store IC for the interceptor case.
4131THREADED_TEST(InterceptorStoreIC) {
4132 v8::HandleScope scope;
4133 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4134 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
4135 InterceptorStoreICSetter);
4136 LocalContext context;
4137 context->Global()->Set(v8_str("o"), templ->NewInstance());
4138 v8::Handle<Value> value = CompileRun(
4139 "for (var i = 0; i < 1000; i++) {"
4140 " o.x = 42;"
4141 "}");
4142}
4143
4144
4145
4146v8::Handle<Value> call_ic_function;
4147v8::Handle<Value> call_ic_function2;
4148v8::Handle<Value> call_ic_function3;
4149
4150static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
4151 const AccessorInfo& info) {
4152 ApiTestFuzzer::Fuzz();
4153 CHECK(v8_str("x")->Equals(name));
4154 return call_ic_function;
4155}
4156
4157
4158// This test should hit the call IC for the interceptor case.
4159THREADED_TEST(InterceptorCallIC) {
4160 v8::HandleScope scope;
4161 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4162 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
4163 LocalContext context;
4164 context->Global()->Set(v8_str("o"), templ->NewInstance());
4165 call_ic_function =
4166 v8_compile("function f(x) { return x + 1; }; f")->Run();
4167 v8::Handle<Value> value = CompileRun(
4168 "var result = 0;"
4169 "for (var i = 0; i < 1000; i++) {"
4170 " result = o.x(41);"
4171 "}");
4172 CHECK_EQ(42, value->Int32Value());
4173}
4174
4175static int interceptor_call_count = 0;
4176
4177static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
4178 const AccessorInfo& info) {
4179 ApiTestFuzzer::Fuzz();
4180 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
4181 return call_ic_function2;
4182 }
4183 return v8::Handle<Value>();
4184}
4185
4186
4187// This test should hit load and call ICs for the interceptor case.
4188// Once in a while, the interceptor will reply that a property was not
4189// found in which case we should get a reference error.
4190THREADED_TEST(InterceptorICReferenceErrors) {
4191 v8::HandleScope scope;
4192 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4193 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
4194 LocalContext context(0, templ, v8::Handle<Value>());
4195 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
4196 v8::Handle<Value> value = CompileRun(
4197 "function f() {"
4198 " for (var i = 0; i < 1000; i++) {"
4199 " try { x; } catch(e) { return true; }"
4200 " }"
4201 " return false;"
4202 "};"
4203 "f();");
4204 CHECK_EQ(true, value->BooleanValue());
4205 interceptor_call_count = 0;
4206 value = CompileRun(
4207 "function g() {"
4208 " for (var i = 0; i < 1000; i++) {"
4209 " try { x(42); } catch(e) { return true; }"
4210 " }"
4211 " return false;"
4212 "};"
4213 "g();");
4214 CHECK_EQ(true, value->BooleanValue());
4215}
4216
4217
4218static int interceptor_ic_exception_get_count = 0;
4219
4220static v8::Handle<Value> InterceptorICExceptionGetter(
4221 Local<String> name,
4222 const AccessorInfo& info) {
4223 ApiTestFuzzer::Fuzz();
4224 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
4225 return call_ic_function3;
4226 }
4227 if (interceptor_ic_exception_get_count == 20) {
4228 return v8::ThrowException(v8_num(42));
4229 }
4230 // Do not handle get for properties other than x.
4231 return v8::Handle<Value>();
4232}
4233
4234// Test interceptor load/call IC where the interceptor throws an
4235// exception once in a while.
4236THREADED_TEST(InterceptorICGetterExceptions) {
4237 interceptor_ic_exception_get_count = 0;
4238 v8::HandleScope scope;
4239 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4240 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
4241 LocalContext context(0, templ, v8::Handle<Value>());
4242 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
4243 v8::Handle<Value> value = CompileRun(
4244 "function f() {"
4245 " for (var i = 0; i < 100; i++) {"
4246 " try { x; } catch(e) { return true; }"
4247 " }"
4248 " return false;"
4249 "};"
4250 "f();");
4251 CHECK_EQ(true, value->BooleanValue());
4252 interceptor_ic_exception_get_count = 0;
4253 value = CompileRun(
4254 "function f() {"
4255 " for (var i = 0; i < 100; i++) {"
4256 " try { x(42); } catch(e) { return true; }"
4257 " }"
4258 " return false;"
4259 "};"
4260 "f();");
4261 CHECK_EQ(true, value->BooleanValue());
4262}
4263
4264
4265static int interceptor_ic_exception_set_count = 0;
4266
4267static v8::Handle<Value> InterceptorICExceptionSetter(
4268 Local<String> key,
4269 Local<Value> value,
4270 const AccessorInfo&) {
4271 ApiTestFuzzer::Fuzz();
4272 if (++interceptor_ic_exception_set_count > 20) {
4273 return v8::ThrowException(v8_num(42));
4274 }
4275 // Do not actually handle setting.
4276 return v8::Handle<Value>();
4277}
4278
4279// Test interceptor store IC where the interceptor throws an exception
4280// once in a while.
4281THREADED_TEST(InterceptorICSetterExceptions) {
4282 interceptor_ic_exception_set_count = 0;
4283 v8::HandleScope scope;
4284 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4285 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
4286 LocalContext context(0, templ, v8::Handle<Value>());
4287 v8::Handle<Value> value = CompileRun(
4288 "function f() {"
4289 " for (var i = 0; i < 100; i++) {"
4290 " try { x = 42; } catch(e) { return true; }"
4291 " }"
4292 " return false;"
4293 "};"
4294 "f();");
4295 CHECK_EQ(true, value->BooleanValue());
4296}
4297
4298
4299// Test that we ignore null interceptors.
4300THREADED_TEST(NullNamedInterceptor) {
4301 v8::HandleScope scope;
4302 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4303 templ->SetNamedPropertyHandler(0);
4304 LocalContext context;
4305 templ->Set("x", v8_num(42));
4306 v8::Handle<v8::Object> obj = templ->NewInstance();
4307 context->Global()->Set(v8_str("obj"), obj);
4308 v8::Handle<Value> value = CompileRun("obj.x");
4309 CHECK(value->IsInt32());
4310 CHECK_EQ(42, value->Int32Value());
4311}
4312
4313
4314// Test that we ignore null interceptors.
4315THREADED_TEST(NullIndexedInterceptor) {
4316 v8::HandleScope scope;
4317 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4318 templ->SetIndexedPropertyHandler(0);
4319 LocalContext context;
4320 templ->Set("42", v8_num(42));
4321 v8::Handle<v8::Object> obj = templ->NewInstance();
4322 context->Global()->Set(v8_str("obj"), obj);
4323 v8::Handle<Value> value = CompileRun("obj[42]");
4324 CHECK(value->IsInt32());
4325 CHECK_EQ(42, value->Int32Value());
4326}
4327
4328
4329static v8::Handle<Value> ParentGetter(Local<String> name,
4330 const AccessorInfo& info) {
4331 ApiTestFuzzer::Fuzz();
4332 return v8_num(1);
4333}
4334
4335
4336static v8::Handle<Value> ChildGetter(Local<String> name,
4337 const AccessorInfo& info) {
4338 ApiTestFuzzer::Fuzz();
4339 return v8_num(42);
4340}
4341
4342
4343THREADED_TEST(Overriding) {
4344 v8::HandleScope scope;
4345 LocalContext context;
4346
4347 // Parent template.
4348 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
4349 Local<ObjectTemplate> parent_instance_templ =
4350 parent_templ->InstanceTemplate();
4351 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
4352
4353 // Template that inherits from the parent template.
4354 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
4355 Local<ObjectTemplate> child_instance_templ =
4356 child_templ->InstanceTemplate();
4357 child_templ->Inherit(parent_templ);
4358 // Override 'f'. The child version of 'f' should get called for child
4359 // instances.
4360 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
4361 // Add 'g' twice. The 'g' added last should get called for instances.
4362 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
4363 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
4364
4365 // Add 'h' as an accessor to the proto template with ReadOnly attributes
4366 // so 'h' can be shadowed on the instance object.
4367 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
4368 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
4369 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
4370
4371 // Add 'i' as an accessor to the instance template with ReadOnly attributes
4372 // but the attribute does not have effect because it is duplicated with
4373 // NULL setter.
4374 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
4375 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
4376
4377
4378
4379 // Instantiate the child template.
4380 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
4381
4382 // Check that the child function overrides the parent one.
4383 context->Global()->Set(v8_str("o"), instance);
4384 Local<Value> value = v8_compile("o.f")->Run();
4385 // Check that the 'g' that was added last is hit.
4386 CHECK_EQ(42, value->Int32Value());
4387 value = v8_compile("o.g")->Run();
4388 CHECK_EQ(42, value->Int32Value());
4389
4390 // Check 'h' can be shadowed.
4391 value = v8_compile("o.h = 3; o.h")->Run();
4392 CHECK_EQ(3, value->Int32Value());
4393
4394 // Check 'i' is cannot be shadowed or changed.
4395 value = v8_compile("o.i = 3; o.i")->Run();
4396 CHECK_EQ(42, value->Int32Value());
4397}
4398
4399
4400static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
4401 ApiTestFuzzer::Fuzz();
4402 if (args.IsConstructCall()) {
4403 return v8::Boolean::New(true);
4404 }
4405 return v8::Boolean::New(false);
4406}
4407
4408
4409THREADED_TEST(IsConstructCall) {
4410 v8::HandleScope scope;
4411
4412 // Function template with call handler.
4413 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4414 templ->SetCallHandler(IsConstructHandler);
4415
4416 LocalContext context;
4417
4418 context->Global()->Set(v8_str("f"), templ->GetFunction());
4419 Local<Value> value = v8_compile("f()")->Run();
4420 CHECK(!value->BooleanValue());
4421 value = v8_compile("new f()")->Run();
4422 CHECK(value->BooleanValue());
4423}
4424
4425
4426THREADED_TEST(ObjectProtoToString) {
4427 v8::HandleScope scope;
4428 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4429 templ->SetClassName(v8_str("MyClass"));
4430
4431 LocalContext context;
4432
4433 Local<String> customized_tostring = v8_str("customized toString");
4434
4435 // Replace Object.prototype.toString
4436 v8_compile("Object.prototype.toString = function() {"
4437 " return 'customized toString';"
4438 "}")->Run();
4439
4440 // Normal ToString call should call replaced Object.prototype.toString
4441 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
4442 Local<String> value = instance->ToString();
4443 CHECK(value->IsString() && value->Equals(customized_tostring));
4444
4445 // ObjectProtoToString should not call replace toString function.
4446 value = instance->ObjectProtoToString();
4447 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
4448
4449 // Check global
4450 value = context->Global()->ObjectProtoToString();
4451 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
4452
4453 // Check ordinary object
4454 Local<Value> object = v8_compile("new Object()")->Run();
4455 value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
4456 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
4457}
4458
4459
4460bool ApiTestFuzzer::fuzzing_ = false;
4461v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
4462 v8::internal::OS::CreateSemaphore(0);
4463int ApiTestFuzzer::active_tests_;
4464int ApiTestFuzzer::tests_being_run_;
4465int ApiTestFuzzer::current_;
4466
4467
4468// We are in a callback and want to switch to another thread (if we
4469// are currently running the thread fuzzing test).
4470void ApiTestFuzzer::Fuzz() {
4471 if (!fuzzing_) return;
4472 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
4473 test->ContextSwitch();
4474}
4475
4476
4477// Let the next thread go. Since it is also waiting on the V8 lock it may
4478// not start immediately.
4479bool ApiTestFuzzer::NextThread() {
4480 int test_position = GetNextTestNumber();
4481 int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
4482 if (test_position == current_) {
4483 printf("Stay with %d\n", test_number);
4484 return false;
4485 }
4486 printf("Switch from %d to %d\n",
4487 current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
4488 current_ = test_position;
4489 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
4490 return true;
4491}
4492
4493
4494void ApiTestFuzzer::Run() {
4495 // When it is our turn...
4496 gate_->Wait();
4497 {
4498 // ... get the V8 lock and start running the test.
4499 v8::Locker locker;
4500 CallTest();
4501 }
4502 // This test finished.
4503 active_ = false;
4504 active_tests_--;
4505 // If it was the last then signal that fact.
4506 if (active_tests_ == 0) {
4507 all_tests_done_->Signal();
4508 } else {
4509 // Otherwise select a new test and start that.
4510 NextThread();
4511 }
4512}
4513
4514
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004515static unsigned linear_congruential_generator;
4516
4517
4518void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004519 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 fuzzing_ = true;
4521 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
4522 int end = (part == FIRST_PART)
4523 ? (RegisterThreadedTest::count() >> 1)
4524 : RegisterThreadedTest::count();
4525 active_tests_ = tests_being_run_ = end - start;
4526 for (int i = 0; i < tests_being_run_; i++) {
4527 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
4528 }
4529 for (int i = 0; i < active_tests_; i++) {
4530 RegisterThreadedTest::nth(i)->fuzzer_->Start();
4531 }
4532}
4533
4534
4535static void CallTestNumber(int test_number) {
4536 (RegisterThreadedTest::nth(test_number)->callback())();
4537}
4538
4539
4540void ApiTestFuzzer::RunAllTests() {
4541 // Set off the first test.
4542 current_ = -1;
4543 NextThread();
4544 // Wait till they are all done.
4545 all_tests_done_->Wait();
4546}
4547
4548
4549int ApiTestFuzzer::GetNextTestNumber() {
4550 int next_test;
4551 do {
4552 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
4553 linear_congruential_generator *= 1664525u;
4554 linear_congruential_generator += 1013904223u;
4555 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
4556 return next_test;
4557}
4558
4559
4560void ApiTestFuzzer::ContextSwitch() {
4561 // If the new thread is the same as the current thread there is nothing to do.
4562 if (NextThread()) {
4563 // Now it can start.
4564 v8::Unlocker unlocker;
4565 // Wait till someone starts us again.
4566 gate_->Wait();
4567 // And we're off.
4568 }
4569}
4570
4571
4572void ApiTestFuzzer::TearDown() {
4573 fuzzing_ = false;
4574}
4575
4576
4577// Lets not be needlessly self-referential.
4578TEST(Threading) {
4579 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
4580 ApiTestFuzzer::RunAllTests();
4581 ApiTestFuzzer::TearDown();
4582}
4583
4584TEST(Threading2) {
4585 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
4586 ApiTestFuzzer::RunAllTests();
4587 ApiTestFuzzer::TearDown();
4588}
4589
4590
4591void ApiTestFuzzer::CallTest() {
4592 printf("Start test %d\n", test_number_);
4593 CallTestNumber(test_number_);
4594 printf("End test %d\n", test_number_);
4595}
4596
4597
4598static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004599 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004600 ApiTestFuzzer::Fuzz();
4601 v8::Unlocker unlocker;
4602 const char* code = "throw 7;";
4603 {
4604 v8::Locker nested_locker;
4605 v8::HandleScope scope;
4606 v8::Handle<Value> exception;
4607 { v8::TryCatch try_catch;
4608 v8::Handle<Value> value = CompileRun(code);
4609 CHECK(value.IsEmpty());
4610 CHECK(try_catch.HasCaught());
4611 // Make sure to wrap the exception in a new handle because
4612 // the handle returned from the TryCatch is destroyed
4613 // when the TryCatch is destroyed.
4614 exception = Local<Value>::New(try_catch.Exception());
4615 }
4616 return v8::ThrowException(exception);
4617 }
4618}
4619
4620
4621static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004622 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004623 ApiTestFuzzer::Fuzz();
4624 v8::Unlocker unlocker;
4625 const char* code = "throw 7;";
4626 {
4627 v8::Locker nested_locker;
4628 v8::HandleScope scope;
4629 v8::Handle<Value> value = CompileRun(code);
4630 CHECK(value.IsEmpty());
4631 return v8_str("foo");
4632 }
4633}
4634
4635
4636// These are locking tests that don't need to be run again
4637// as part of the locking aggregation tests.
4638TEST(NestedLockers) {
4639 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004640 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004641 v8::HandleScope scope;
4642 LocalContext env;
4643 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
4644 Local<Function> fun = fun_templ->GetFunction();
4645 env->Global()->Set(v8_str("throw_in_js"), fun);
4646 Local<Script> script = v8_compile("(function () {"
4647 " try {"
4648 " throw_in_js();"
4649 " return 42;"
4650 " } catch (e) {"
4651 " return e * 13;"
4652 " }"
4653 "})();");
4654 CHECK_EQ(91, script->Run()->Int32Value());
4655}
4656
4657
4658// These are locking tests that don't need to be run again
4659// as part of the locking aggregation tests.
4660TEST(NestedLockersNoTryCatch) {
4661 v8::Locker locker;
4662 v8::HandleScope scope;
4663 LocalContext env;
4664 Local<v8::FunctionTemplate> fun_templ =
4665 v8::FunctionTemplate::New(ThrowInJSNoCatch);
4666 Local<Function> fun = fun_templ->GetFunction();
4667 env->Global()->Set(v8_str("throw_in_js"), fun);
4668 Local<Script> script = v8_compile("(function () {"
4669 " try {"
4670 " throw_in_js();"
4671 " return 42;"
4672 " } catch (e) {"
4673 " return e * 13;"
4674 " }"
4675 "})();");
4676 CHECK_EQ(91, script->Run()->Int32Value());
4677}
4678
4679
4680THREADED_TEST(RecursiveLocking) {
4681 v8::Locker locker;
4682 {
4683 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004684 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004685 }
4686}
4687
4688
4689static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
4690 ApiTestFuzzer::Fuzz();
4691 v8::Unlocker unlocker;
4692 return v8::Undefined();
4693}
4694
4695
4696THREADED_TEST(LockUnlockLock) {
4697 {
4698 v8::Locker locker;
4699 v8::HandleScope scope;
4700 LocalContext env;
4701 Local<v8::FunctionTemplate> fun_templ =
4702 v8::FunctionTemplate::New(UnlockForAMoment);
4703 Local<Function> fun = fun_templ->GetFunction();
4704 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
4705 Local<Script> script = v8_compile("(function () {"
4706 " unlock_for_a_moment();"
4707 " return 42;"
4708 "})();");
4709 CHECK_EQ(42, script->Run()->Int32Value());
4710 }
4711 {
4712 v8::Locker locker;
4713 v8::HandleScope scope;
4714 LocalContext env;
4715 Local<v8::FunctionTemplate> fun_templ =
4716 v8::FunctionTemplate::New(UnlockForAMoment);
4717 Local<Function> fun = fun_templ->GetFunction();
4718 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
4719 Local<Script> script = v8_compile("(function () {"
4720 " unlock_for_a_moment();"
4721 " return 42;"
4722 "})();");
4723 CHECK_EQ(42, script->Run()->Int32Value());
4724 }
4725}
4726
4727
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004728static int GetSurvivingGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004729 int count = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004730 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004731 v8::internal::HeapIterator it;
4732 while (it.has_next()) {
4733 v8::internal::HeapObject* object = it.next();
4734 if (object->IsJSGlobalObject()) {
4735 count++;
4736 }
4737 }
4738#ifdef DEBUG
4739 if (count > 0) v8::internal::Heap::TracePathToGlobal();
4740#endif
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004741 return count;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004742}
4743
4744
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004745TEST(DontLeakGlobalObjects) {
4746 // Regression test for issues 1139850 and 1174891.
4747
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004748 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004749
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004750 int count = GetSurvivingGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004751
4752 for (int i = 0; i < 5; i++) {
4753 { v8::HandleScope scope;
4754 LocalContext context;
4755 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004756 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004757
4758 { v8::HandleScope scope;
4759 LocalContext context;
4760 v8_compile("Date")->Run();
4761 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004762 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004763
4764 { v8::HandleScope scope;
4765 LocalContext context;
4766 v8_compile("/aaa/")->Run();
4767 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004768 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004769
4770 { v8::HandleScope scope;
4771 const char* extension_list[] = { "v8/gc" };
4772 v8::ExtensionConfiguration extensions(1, extension_list);
4773 LocalContext context(&extensions);
4774 v8_compile("gc();")->Run();
4775 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004776 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004777 }
4778}
4779
4780
4781THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004782 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004783
4784 const int nof = 2;
4785 const char* sources[nof] = {
4786 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
4787 "Object()"
4788 };
4789
4790 for (int i = 0; i < nof; i++) {
4791 const char* source = sources[i];
4792 { v8::HandleScope scope;
4793 LocalContext context;
4794 CompileRun(source);
4795 }
4796 { v8::HandleScope scope;
4797 LocalContext context;
4798 CompileRun(source);
4799 }
4800 }
4801}
4802
4803
4804static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
4805 v8::HandleScope inner;
4806 env->Enter();
4807 v8::Handle<Value> three = v8_num(3);
4808 v8::Handle<Value> value = inner.Close(three);
4809 env->Exit();
4810 return value;
4811}
4812
4813
4814THREADED_TEST(NestedHandleScopeAndContexts) {
4815 v8::HandleScope outer;
4816 v8::Persistent<Context> env = Context::New();
4817 env->Enter();
4818 v8::Handle<Value> value = NestedScope(env);
4819 v8::Handle<String> str = value->ToString();
4820 env->Exit();
4821 env.Dispose();
4822}
4823
4824
4825THREADED_TEST(ExternalAllocatedMemory) {
4826 v8::HandleScope outer;
4827 const int kSize = 1024*1024;
4828 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
4829 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
4830}
4831
4832
4833THREADED_TEST(DisposeEnteredContext) {
4834 v8::HandleScope scope;
4835 LocalContext outer;
4836 { v8::Persistent<v8::Context> inner = v8::Context::New();
4837 inner->Enter();
4838 inner.Dispose();
4839 inner.Clear();
4840 inner->Exit();
4841 }
4842}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004843
4844
4845// Regression test for issue 54, object templates with internal fields
4846// but no accessors or interceptors did not get their internal field
4847// count set on instances.
4848THREADED_TEST(Regress54) {
4849 v8::HandleScope outer;
4850 LocalContext context;
4851 static v8::Persistent<v8::ObjectTemplate> templ;
4852 if (templ.IsEmpty()) {
4853 v8::HandleScope inner;
4854 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
4855 local->SetInternalFieldCount(1);
4856 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
4857 }
4858 v8::Handle<v8::Object> result = templ->NewInstance();
4859 CHECK_EQ(1, result->InternalFieldCount());
4860}
4861
4862
4863// If part of the threaded tests, this test makes ThreadingTest fail
4864// on mac.
4865TEST(CatchStackOverflow) {
4866 v8::HandleScope scope;
4867 LocalContext context;
4868 v8::TryCatch try_catch;
4869 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
4870 "function f() {"
4871 " return f();"
4872 "}"
4873 ""
4874 "f();"));
4875 v8::Handle<v8::Value> result = script->Run();
4876 CHECK(result.IsEmpty());
4877}
4878
4879
4880THREADED_TEST(TryCatchSourceInfo) {
4881 v8::HandleScope scope;
4882 LocalContext context;
4883 v8::Handle<v8::String> source = v8::String::New(
4884 "function Foo() {\n"
4885 " return Bar();\n"
4886 "}\n"
4887 "\n"
4888 "function Bar() {\n"
4889 " return Baz();\n"
4890 "}\n"
4891 "\n"
4892 "function Baz() {\n"
4893 " throw 'nirk';\n"
4894 "}\n"
4895 "\n"
4896 "Foo();\n");
4897 v8::Handle<v8::Script> script =
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004898 v8::Script::Compile(source, v8::String::New("test.js"));
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004899 v8::TryCatch try_catch;
4900 v8::Handle<v8::Value> result = script->Run();
4901 CHECK(result.IsEmpty());
4902 CHECK(try_catch.HasCaught());
4903 v8::Handle<v8::Message> message = try_catch.Message();
4904 CHECK(!message.IsEmpty());
4905 CHECK_EQ(10, message->GetLineNumber());
4906 CHECK_EQ(91, message->GetStartPosition());
4907 CHECK_EQ(92, message->GetEndPosition());
4908 CHECK_EQ(2, message->GetStartColumn());
4909 CHECK_EQ(3, message->GetEndColumn());
4910 v8::String::AsciiValue line(message->GetSourceLine());
4911 CHECK_EQ(" throw 'nirk';", *line);
4912 v8::String::AsciiValue name(message->GetScriptResourceName());
4913 CHECK_EQ("test.js", *name);
4914}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004915
4916
4917THREADED_TEST(CompilationCache) {
4918 v8::HandleScope scope;
4919 LocalContext context;
4920 v8::Handle<v8::String> source0 = v8::String::New("1234");
4921 v8::Handle<v8::String> source1 = v8::String::New("1234");
4922 v8::Handle<v8::Script> script0 =
4923 v8::Script::Compile(source0, v8::String::New("test.js"));
4924 v8::Handle<v8::Script> script1 =
4925 v8::Script::Compile(source1, v8::String::New("test.js"));
4926 v8::Handle<v8::Script> script2 =
4927 v8::Script::Compile(source0); // different origin
4928 CHECK_EQ(1234, script0->Run()->Int32Value());
4929 CHECK_EQ(1234, script1->Run()->Int32Value());
4930 CHECK_EQ(1234, script2->Run()->Int32Value());
4931}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004932
4933
4934static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
4935 ApiTestFuzzer::Fuzz();
4936 return v8_num(42);
4937}
4938
4939
4940THREADED_TEST(CallbackFunctionName) {
4941 v8::HandleScope scope;
4942 LocalContext context;
4943 Local<ObjectTemplate> t = ObjectTemplate::New();
4944 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
4945 context->Global()->Set(v8_str("obj"), t->NewInstance());
4946 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
4947 CHECK(value->IsString());
4948 v8::String::AsciiValue name(value);
4949 CHECK_EQ("asdf", *name);
4950}