blob: ea9e6e122a24e811ea71874e1fb138c3b03a714e [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2007-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Steve Block3ce2e202009-11-05 08:53:23 +000028#include <limits.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000029
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
Steve Block3ce2e202009-11-05 08:53:23 +000038#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "cctest.h"
40
Andrei Popescu31002712010-02-23 13:46:05 +000041static const bool kLogThreading = true;
Steve Blockd0582a62009-12-15 09:54:21 +000042
Steve Blocka7e24c12009-10-30 11:49:00 +000043static bool IsNaN(double x) {
44#ifdef WIN32
45 return _isnan(x);
46#else
47 return isnan(x);
48#endif
49}
50
51using ::v8::ObjectTemplate;
52using ::v8::Value;
53using ::v8::Context;
54using ::v8::Local;
55using ::v8::String;
56using ::v8::Script;
57using ::v8::Function;
58using ::v8::AccessorInfo;
59using ::v8::Extension;
60
61namespace i = ::v8::internal;
62
Steve Blocka7e24c12009-10-30 11:49:00 +000063
Leon Clarked91b9f72010-01-27 17:25:45 +000064static void ExpectString(const char* code, const char* expected) {
65 Local<Value> result = CompileRun(code);
66 CHECK(result->IsString());
67 String::AsciiValue ascii(result);
68 CHECK_EQ(expected, *ascii);
69}
70
71
72static void ExpectBoolean(const char* code, bool expected) {
73 Local<Value> result = CompileRun(code);
74 CHECK(result->IsBoolean());
75 CHECK_EQ(expected, result->BooleanValue());
76}
77
78
79static void ExpectObject(const char* code, Local<Value> expected) {
80 Local<Value> result = CompileRun(code);
81 CHECK(result->Equals(expected));
82}
83
84
Steve Blocka7e24c12009-10-30 11:49:00 +000085static int signature_callback_count;
86static v8::Handle<Value> IncrementingSignatureCallback(
87 const v8::Arguments& args) {
88 ApiTestFuzzer::Fuzz();
89 signature_callback_count++;
90 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
91 for (int i = 0; i < args.Length(); i++)
92 result->Set(v8::Integer::New(i), args[i]);
93 return result;
94}
95
96
97static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
98 ApiTestFuzzer::Fuzz();
99 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
100 for (int i = 0; i < args.Length(); i++) {
101 result->Set(v8::Integer::New(i), args[i]);
102 }
103 return result;
104}
105
106
107THREADED_TEST(Handles) {
108 v8::HandleScope scope;
109 Local<Context> local_env;
110 {
111 LocalContext env;
112 local_env = env.local();
113 }
114
115 // Local context should still be live.
116 CHECK(!local_env.IsEmpty());
117 local_env->Enter();
118
119 v8::Handle<v8::Primitive> undef = v8::Undefined();
120 CHECK(!undef.IsEmpty());
121 CHECK(undef->IsUndefined());
122
123 const char* c_source = "1 + 2 + 3";
124 Local<String> source = String::New(c_source);
125 Local<Script> script = Script::Compile(source);
126 CHECK_EQ(6, script->Run()->Int32Value());
127
128 local_env->Exit();
129}
130
131
Steve Blocka7e24c12009-10-30 11:49:00 +0000132THREADED_TEST(ReceiverSignature) {
133 v8::HandleScope scope;
134 LocalContext env;
135 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
136 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
137 fun->PrototypeTemplate()->Set(
138 v8_str("m"),
139 v8::FunctionTemplate::New(IncrementingSignatureCallback,
140 v8::Handle<Value>(),
141 sig));
142 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
143 signature_callback_count = 0;
144 CompileRun(
145 "var o = new Fun();"
146 "o.m();");
147 CHECK_EQ(1, signature_callback_count);
148 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
149 sub_fun->Inherit(fun);
150 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
151 CompileRun(
152 "var o = new SubFun();"
153 "o.m();");
154 CHECK_EQ(2, signature_callback_count);
155
156 v8::TryCatch try_catch;
157 CompileRun(
158 "var o = { };"
159 "o.m = Fun.prototype.m;"
160 "o.m();");
161 CHECK_EQ(2, signature_callback_count);
162 CHECK(try_catch.HasCaught());
163 try_catch.Reset();
164 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
165 sub_fun->Inherit(fun);
166 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
167 CompileRun(
168 "var o = new UnrelFun();"
169 "o.m = Fun.prototype.m;"
170 "o.m();");
171 CHECK_EQ(2, signature_callback_count);
172 CHECK(try_catch.HasCaught());
173}
174
175
176
177
178THREADED_TEST(ArgumentSignature) {
179 v8::HandleScope scope;
180 LocalContext env;
181 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
182 cons->SetClassName(v8_str("Cons"));
183 v8::Handle<v8::Signature> sig =
184 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
185 v8::Handle<v8::FunctionTemplate> fun =
186 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
187 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
188 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
189
190 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
191 CHECK(value1->IsTrue());
192
193 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
194 CHECK(value2->IsTrue());
195
196 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
197 CHECK(value3->IsTrue());
198
199 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
200 cons1->SetClassName(v8_str("Cons1"));
201 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
202 cons2->SetClassName(v8_str("Cons2"));
203 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
204 cons3->SetClassName(v8_str("Cons3"));
205
206 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
207 v8::Handle<v8::Signature> wsig =
208 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
209 v8::Handle<v8::FunctionTemplate> fun2 =
210 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
211
212 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
213 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
214 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
215 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
216 v8::Handle<Value> value4 = CompileRun(
217 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
218 "'[object Cons1],[object Cons2],[object Cons3]'");
219 CHECK(value4->IsTrue());
220
221 v8::Handle<Value> value5 = CompileRun(
222 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
223 CHECK(value5->IsTrue());
224
225 v8::Handle<Value> value6 = CompileRun(
226 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
227 CHECK(value6->IsTrue());
228
229 v8::Handle<Value> value7 = CompileRun(
230 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
231 "'[object Cons1],[object Cons2],[object Cons3],d';");
232 CHECK(value7->IsTrue());
233
234 v8::Handle<Value> value8 = CompileRun(
235 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
236 CHECK(value8->IsTrue());
237}
238
239
240THREADED_TEST(HulIgennem) {
241 v8::HandleScope scope;
242 LocalContext env;
243 v8::Handle<v8::Primitive> undef = v8::Undefined();
244 Local<String> undef_str = undef->ToString();
245 char* value = i::NewArray<char>(undef_str->Length() + 1);
246 undef_str->WriteAscii(value);
247 CHECK_EQ(0, strcmp(value, "undefined"));
248 i::DeleteArray(value);
249}
250
251
252THREADED_TEST(Access) {
253 v8::HandleScope scope;
254 LocalContext env;
255 Local<v8::Object> obj = v8::Object::New();
256 Local<Value> foo_before = obj->Get(v8_str("foo"));
257 CHECK(foo_before->IsUndefined());
258 Local<String> bar_str = v8_str("bar");
259 obj->Set(v8_str("foo"), bar_str);
260 Local<Value> foo_after = obj->Get(v8_str("foo"));
261 CHECK(!foo_after->IsUndefined());
262 CHECK(foo_after->IsString());
263 CHECK_EQ(bar_str, foo_after);
264}
265
266
Steve Block6ded16b2010-05-10 14:33:55 +0100267THREADED_TEST(AccessElement) {
268 v8::HandleScope scope;
269 LocalContext env;
270 Local<v8::Object> obj = v8::Object::New();
271 Local<Value> before = obj->Get(1);
272 CHECK(before->IsUndefined());
273 Local<String> bar_str = v8_str("bar");
274 obj->Set(1, bar_str);
275 Local<Value> after = obj->Get(1);
276 CHECK(!after->IsUndefined());
277 CHECK(after->IsString());
278 CHECK_EQ(bar_str, after);
279
280 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
281 CHECK_EQ(v8_str("a"), value->Get(0));
282 CHECK_EQ(v8_str("b"), value->Get(1));
283}
284
285
Steve Blocka7e24c12009-10-30 11:49:00 +0000286THREADED_TEST(Script) {
287 v8::HandleScope scope;
288 LocalContext env;
289 const char* c_source = "1 + 2 + 3";
290 Local<String> source = String::New(c_source);
291 Local<Script> script = Script::Compile(source);
292 CHECK_EQ(6, script->Run()->Int32Value());
293}
294
295
296static uint16_t* AsciiToTwoByteString(const char* source) {
Steve Blockd0582a62009-12-15 09:54:21 +0000297 int array_length = i::StrLength(source) + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 uint16_t* converted = i::NewArray<uint16_t>(array_length);
Steve Blockd0582a62009-12-15 09:54:21 +0000299 for (int i = 0; i < array_length; i++) converted[i] = source[i];
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 return converted;
301}
302
303
304class TestResource: public String::ExternalStringResource {
305 public:
306 static int dispose_count;
307
308 explicit TestResource(uint16_t* data)
309 : data_(data), length_(0) {
310 while (data[length_]) ++length_;
311 }
312
313 ~TestResource() {
314 i::DeleteArray(data_);
315 ++dispose_count;
316 }
317
318 const uint16_t* data() const {
319 return data_;
320 }
321
322 size_t length() const {
323 return length_;
324 }
325 private:
326 uint16_t* data_;
327 size_t length_;
328};
329
330
331int TestResource::dispose_count = 0;
332
333
334class TestAsciiResource: public String::ExternalAsciiStringResource {
335 public:
336 static int dispose_count;
337
338 explicit TestAsciiResource(const char* data)
339 : data_(data),
340 length_(strlen(data)) { }
341
342 ~TestAsciiResource() {
343 i::DeleteArray(data_);
344 ++dispose_count;
345 }
346
347 const char* data() const {
348 return data_;
349 }
350
351 size_t length() const {
352 return length_;
353 }
354 private:
355 const char* data_;
356 size_t length_;
357};
358
359
360int TestAsciiResource::dispose_count = 0;
361
362
363THREADED_TEST(ScriptUsingStringResource) {
364 TestResource::dispose_count = 0;
365 const char* c_source = "1 + 2 * 3";
366 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
367 {
368 v8::HandleScope scope;
369 LocalContext env;
370 TestResource* resource = new TestResource(two_byte_source);
371 Local<String> source = String::NewExternal(resource);
372 Local<Script> script = Script::Compile(source);
373 Local<Value> value = script->Run();
374 CHECK(value->IsNumber());
375 CHECK_EQ(7, value->Int32Value());
376 CHECK(source->IsExternal());
377 CHECK_EQ(resource,
378 static_cast<TestResource*>(source->GetExternalStringResource()));
379 v8::internal::Heap::CollectAllGarbage(false);
380 CHECK_EQ(0, TestResource::dispose_count);
381 }
382 v8::internal::CompilationCache::Clear();
383 v8::internal::Heap::CollectAllGarbage(false);
384 CHECK_EQ(1, TestResource::dispose_count);
385}
386
387
388THREADED_TEST(ScriptUsingAsciiStringResource) {
389 TestAsciiResource::dispose_count = 0;
390 const char* c_source = "1 + 2 * 3";
391 {
392 v8::HandleScope scope;
393 LocalContext env;
394 Local<String> source =
395 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
396 Local<Script> script = Script::Compile(source);
397 Local<Value> value = script->Run();
398 CHECK(value->IsNumber());
399 CHECK_EQ(7, value->Int32Value());
400 v8::internal::Heap::CollectAllGarbage(false);
401 CHECK_EQ(0, TestAsciiResource::dispose_count);
402 }
403 v8::internal::CompilationCache::Clear();
404 v8::internal::Heap::CollectAllGarbage(false);
405 CHECK_EQ(1, TestAsciiResource::dispose_count);
406}
407
408
409THREADED_TEST(ScriptMakingExternalString) {
410 TestResource::dispose_count = 0;
411 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
412 {
413 v8::HandleScope scope;
414 LocalContext env;
415 Local<String> source = String::New(two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000416 // Trigger GCs so that the newly allocated string moves to old gen.
417 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
418 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 bool success = source->MakeExternal(new TestResource(two_byte_source));
420 CHECK(success);
421 Local<Script> script = Script::Compile(source);
422 Local<Value> value = script->Run();
423 CHECK(value->IsNumber());
424 CHECK_EQ(7, value->Int32Value());
425 v8::internal::Heap::CollectAllGarbage(false);
426 CHECK_EQ(0, TestResource::dispose_count);
427 }
428 v8::internal::CompilationCache::Clear();
429 v8::internal::Heap::CollectAllGarbage(false);
430 CHECK_EQ(1, TestResource::dispose_count);
431}
432
433
434THREADED_TEST(ScriptMakingExternalAsciiString) {
435 TestAsciiResource::dispose_count = 0;
436 const char* c_source = "1 + 2 * 3";
437 {
438 v8::HandleScope scope;
439 LocalContext env;
440 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000441 // Trigger GCs so that the newly allocated string moves to old gen.
442 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
443 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 bool success = source->MakeExternal(
445 new TestAsciiResource(i::StrDup(c_source)));
446 CHECK(success);
447 Local<Script> script = Script::Compile(source);
448 Local<Value> value = script->Run();
449 CHECK(value->IsNumber());
450 CHECK_EQ(7, value->Int32Value());
451 v8::internal::Heap::CollectAllGarbage(false);
452 CHECK_EQ(0, TestAsciiResource::dispose_count);
453 }
454 v8::internal::CompilationCache::Clear();
455 v8::internal::Heap::CollectAllGarbage(false);
456 CHECK_EQ(1, TestAsciiResource::dispose_count);
457}
458
459
Andrei Popescu402d9372010-02-26 13:31:12 +0000460TEST(MakingExternalStringConditions) {
461 v8::HandleScope scope;
462 LocalContext env;
463
464 // Free some space in the new space so that we can check freshness.
465 i::Heap::CollectGarbage(0, i::NEW_SPACE);
466 i::Heap::CollectGarbage(0, i::NEW_SPACE);
467
468 Local<String> small_string = String::New(AsciiToTwoByteString("small"));
469 // We should refuse to externalize newly created small string.
470 CHECK(!small_string->CanMakeExternal());
471 // Trigger GCs so that the newly allocated string moves to old gen.
472 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
473 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
474 // Old space strings should be accepted.
475 CHECK(small_string->CanMakeExternal());
476
477 small_string = String::New(AsciiToTwoByteString("small 2"));
478 // We should refuse externalizing newly created small string.
479 CHECK(!small_string->CanMakeExternal());
480 for (int i = 0; i < 100; i++) {
481 String::Value value(small_string);
482 }
483 // Frequently used strings should be accepted.
484 CHECK(small_string->CanMakeExternal());
485
486 const int buf_size = 10 * 1024;
487 char* buf = i::NewArray<char>(buf_size);
488 memset(buf, 'a', buf_size);
489 buf[buf_size - 1] = '\0';
490 Local<String> large_string = String::New(AsciiToTwoByteString(buf));
491 i::DeleteArray(buf);
492 // Large strings should be immediately accepted.
493 CHECK(large_string->CanMakeExternal());
494}
495
496
497TEST(MakingExternalAsciiStringConditions) {
498 v8::HandleScope scope;
499 LocalContext env;
500
501 // Free some space in the new space so that we can check freshness.
502 i::Heap::CollectGarbage(0, i::NEW_SPACE);
503 i::Heap::CollectGarbage(0, i::NEW_SPACE);
504
505 Local<String> small_string = String::New("small");
506 // We should refuse to externalize newly created small string.
507 CHECK(!small_string->CanMakeExternal());
508 // Trigger GCs so that the newly allocated string moves to old gen.
509 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
510 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
511 // Old space strings should be accepted.
512 CHECK(small_string->CanMakeExternal());
513
514 small_string = String::New("small 2");
515 // We should refuse externalizing newly created small string.
516 CHECK(!small_string->CanMakeExternal());
517 for (int i = 0; i < 100; i++) {
518 String::Value value(small_string);
519 }
520 // Frequently used strings should be accepted.
521 CHECK(small_string->CanMakeExternal());
522
523 const int buf_size = 10 * 1024;
524 char* buf = i::NewArray<char>(buf_size);
525 memset(buf, 'a', buf_size);
526 buf[buf_size - 1] = '\0';
527 Local<String> large_string = String::New(buf);
528 i::DeleteArray(buf);
529 // Large strings should be immediately accepted.
530 CHECK(large_string->CanMakeExternal());
531}
532
533
Steve Blocka7e24c12009-10-30 11:49:00 +0000534THREADED_TEST(UsingExternalString) {
535 {
536 v8::HandleScope scope;
537 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
538 Local<String> string =
539 String::NewExternal(new TestResource(two_byte_string));
540 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
541 // Trigger GCs so that the newly allocated string moves to old gen.
542 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
543 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
544 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
545 CHECK(isymbol->IsSymbol());
546 }
547 i::Heap::CollectAllGarbage(false);
548 i::Heap::CollectAllGarbage(false);
549}
550
551
552THREADED_TEST(UsingExternalAsciiString) {
553 {
554 v8::HandleScope scope;
555 const char* one_byte_string = "test string";
556 Local<String> string = String::NewExternal(
557 new TestAsciiResource(i::StrDup(one_byte_string)));
558 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
559 // Trigger GCs so that the newly allocated string moves to old gen.
560 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
561 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
562 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
563 CHECK(isymbol->IsSymbol());
564 }
565 i::Heap::CollectAllGarbage(false);
566 i::Heap::CollectAllGarbage(false);
567}
568
569
Leon Clarkee46be812010-01-19 14:06:41 +0000570THREADED_TEST(ScavengeExternalString) {
571 TestResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100572 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000573 {
574 v8::HandleScope scope;
575 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
576 Local<String> string =
577 String::NewExternal(new TestResource(two_byte_string));
578 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
579 i::Heap::CollectGarbage(0, i::NEW_SPACE);
Steve Block6ded16b2010-05-10 14:33:55 +0100580 in_new_space = i::Heap::InNewSpace(*istring);
581 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000582 CHECK_EQ(0, TestResource::dispose_count);
583 }
Steve Block6ded16b2010-05-10 14:33:55 +0100584 i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000585 CHECK_EQ(1, TestResource::dispose_count);
586}
587
588
589THREADED_TEST(ScavengeExternalAsciiString) {
590 TestAsciiResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100591 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000592 {
593 v8::HandleScope scope;
594 const char* one_byte_string = "test string";
595 Local<String> string = String::NewExternal(
596 new TestAsciiResource(i::StrDup(one_byte_string)));
597 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
598 i::Heap::CollectGarbage(0, i::NEW_SPACE);
Steve Block6ded16b2010-05-10 14:33:55 +0100599 in_new_space = i::Heap::InNewSpace(*istring);
600 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000601 CHECK_EQ(0, TestAsciiResource::dispose_count);
602 }
Steve Block6ded16b2010-05-10 14:33:55 +0100603 i::Heap::CollectGarbage(0, in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000604 CHECK_EQ(1, TestAsciiResource::dispose_count);
605}
606
607
Steve Block3ce2e202009-11-05 08:53:23 +0000608THREADED_TEST(StringConcat) {
609 {
610 v8::HandleScope scope;
611 LocalContext env;
612 const char* one_byte_string_1 = "function a_times_t";
613 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
614 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
615 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
616 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
617 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
618 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
619 Local<String> left = v8_str(one_byte_string_1);
620 Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
621 Local<String> source = String::Concat(left, right);
622 right = String::NewExternal(
623 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
624 source = String::Concat(source, right);
625 right = String::NewExternal(
626 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
627 source = String::Concat(source, right);
628 right = v8_str(one_byte_string_2);
629 source = String::Concat(source, right);
630 right = String::New(AsciiToTwoByteString(two_byte_string_2));
631 source = String::Concat(source, right);
632 right = String::NewExternal(
633 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
634 source = String::Concat(source, right);
635 Local<Script> script = Script::Compile(source);
636 Local<Value> value = script->Run();
637 CHECK(value->IsNumber());
638 CHECK_EQ(68, value->Int32Value());
639 }
640 v8::internal::CompilationCache::Clear();
641 i::Heap::CollectAllGarbage(false);
642 i::Heap::CollectAllGarbage(false);
643}
644
645
Steve Blocka7e24c12009-10-30 11:49:00 +0000646THREADED_TEST(GlobalProperties) {
647 v8::HandleScope scope;
648 LocalContext env;
649 v8::Handle<v8::Object> global = env->Global();
650 global->Set(v8_str("pi"), v8_num(3.1415926));
651 Local<Value> pi = global->Get(v8_str("pi"));
652 CHECK_EQ(3.1415926, pi->NumberValue());
653}
654
655
656static v8::Handle<Value> handle_call(const v8::Arguments& args) {
657 ApiTestFuzzer::Fuzz();
658 return v8_num(102);
659}
660
661
662static v8::Handle<Value> construct_call(const v8::Arguments& args) {
663 ApiTestFuzzer::Fuzz();
664 args.This()->Set(v8_str("x"), v8_num(1));
665 args.This()->Set(v8_str("y"), v8_num(2));
666 return args.This();
667}
668
669THREADED_TEST(FunctionTemplate) {
670 v8::HandleScope scope;
671 LocalContext env;
672 {
673 Local<v8::FunctionTemplate> fun_templ =
674 v8::FunctionTemplate::New(handle_call);
675 Local<Function> fun = fun_templ->GetFunction();
676 env->Global()->Set(v8_str("obj"), fun);
677 Local<Script> script = v8_compile("obj()");
678 CHECK_EQ(102, script->Run()->Int32Value());
679 }
680 // Use SetCallHandler to initialize a function template, should work like the
681 // previous one.
682 {
683 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
684 fun_templ->SetCallHandler(handle_call);
685 Local<Function> fun = fun_templ->GetFunction();
686 env->Global()->Set(v8_str("obj"), fun);
687 Local<Script> script = v8_compile("obj()");
688 CHECK_EQ(102, script->Run()->Int32Value());
689 }
690 // Test constructor calls.
691 {
692 Local<v8::FunctionTemplate> fun_templ =
693 v8::FunctionTemplate::New(construct_call);
694 fun_templ->SetClassName(v8_str("funky"));
695 Local<Function> fun = fun_templ->GetFunction();
696 env->Global()->Set(v8_str("obj"), fun);
697 Local<Script> script = v8_compile("var s = new obj(); s.x");
698 CHECK_EQ(1, script->Run()->Int32Value());
699
700 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
701 CHECK_EQ(v8_str("[object funky]"), result);
702 }
703}
704
705
706THREADED_TEST(FindInstanceInPrototypeChain) {
707 v8::HandleScope scope;
708 LocalContext env;
709
710 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
711 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
712 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
713 derived->Inherit(base);
714
715 Local<v8::Function> base_function = base->GetFunction();
716 Local<v8::Function> derived_function = derived->GetFunction();
717 Local<v8::Function> other_function = other->GetFunction();
718
719 Local<v8::Object> base_instance = base_function->NewInstance();
720 Local<v8::Object> derived_instance = derived_function->NewInstance();
721 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
722 Local<v8::Object> other_instance = other_function->NewInstance();
723 derived_instance2->Set(v8_str("__proto__"), derived_instance);
724 other_instance->Set(v8_str("__proto__"), derived_instance2);
725
726 // base_instance is only an instance of base.
727 CHECK_EQ(base_instance,
728 base_instance->FindInstanceInPrototypeChain(base));
729 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
730 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
731
732 // derived_instance is an instance of base and derived.
733 CHECK_EQ(derived_instance,
734 derived_instance->FindInstanceInPrototypeChain(base));
735 CHECK_EQ(derived_instance,
736 derived_instance->FindInstanceInPrototypeChain(derived));
737 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
738
739 // other_instance is an instance of other and its immediate
740 // prototype derived_instance2 is an instance of base and derived.
741 // Note, derived_instance is an instance of base and derived too,
742 // but it comes after derived_instance2 in the prototype chain of
743 // other_instance.
744 CHECK_EQ(derived_instance2,
745 other_instance->FindInstanceInPrototypeChain(base));
746 CHECK_EQ(derived_instance2,
747 other_instance->FindInstanceInPrototypeChain(derived));
748 CHECK_EQ(other_instance,
749 other_instance->FindInstanceInPrototypeChain(other));
750}
751
752
Steve Block3ce2e202009-11-05 08:53:23 +0000753THREADED_TEST(TinyInteger) {
754 v8::HandleScope scope;
755 LocalContext env;
756 int32_t value = 239;
757 Local<v8::Integer> value_obj = v8::Integer::New(value);
758 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
759}
760
761
762THREADED_TEST(BigSmiInteger) {
763 v8::HandleScope scope;
764 LocalContext env;
765 int32_t value = i::Smi::kMaxValue;
766 // We cannot add one to a Smi::kMaxValue without wrapping.
767 if (i::kSmiValueSize < 32) {
768 CHECK(i::Smi::IsValid(value));
769 CHECK(!i::Smi::IsValid(value + 1));
770 Local<v8::Integer> value_obj = v8::Integer::New(value);
771 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
772 }
773}
774
775
776THREADED_TEST(BigInteger) {
777 v8::HandleScope scope;
778 LocalContext env;
779 // We cannot add one to a Smi::kMaxValue without wrapping.
780 if (i::kSmiValueSize < 32) {
781 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
782 // The code will not be run in that case, due to the "if" guard.
783 int32_t value =
784 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
785 CHECK(value > i::Smi::kMaxValue);
786 CHECK(!i::Smi::IsValid(value));
787 Local<v8::Integer> value_obj = v8::Integer::New(value);
788 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
789 }
790}
791
792
793THREADED_TEST(TinyUnsignedInteger) {
794 v8::HandleScope scope;
795 LocalContext env;
796 uint32_t value = 239;
797 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
798 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
799}
800
801
802THREADED_TEST(BigUnsignedSmiInteger) {
803 v8::HandleScope scope;
804 LocalContext env;
805 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
806 CHECK(i::Smi::IsValid(value));
807 CHECK(!i::Smi::IsValid(value + 1));
808 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
809 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
810}
811
812
813THREADED_TEST(BigUnsignedInteger) {
814 v8::HandleScope scope;
815 LocalContext env;
816 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
817 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
818 CHECK(!i::Smi::IsValid(value));
819 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
820 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
821}
822
823
824THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
825 v8::HandleScope scope;
826 LocalContext env;
827 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
828 uint32_t value = INT32_MAX_AS_UINT + 1;
829 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
830 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
831 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
832}
833
834
Steve Blocka7e24c12009-10-30 11:49:00 +0000835THREADED_TEST(Number) {
836 v8::HandleScope scope;
837 LocalContext env;
838 double PI = 3.1415926;
839 Local<v8::Number> pi_obj = v8::Number::New(PI);
840 CHECK_EQ(PI, pi_obj->NumberValue());
841}
842
843
844THREADED_TEST(ToNumber) {
845 v8::HandleScope scope;
846 LocalContext env;
847 Local<String> str = v8_str("3.1415926");
848 CHECK_EQ(3.1415926, str->NumberValue());
849 v8::Handle<v8::Boolean> t = v8::True();
850 CHECK_EQ(1.0, t->NumberValue());
851 v8::Handle<v8::Boolean> f = v8::False();
852 CHECK_EQ(0.0, f->NumberValue());
853}
854
855
856THREADED_TEST(Date) {
857 v8::HandleScope scope;
858 LocalContext env;
859 double PI = 3.1415926;
860 Local<Value> date_obj = v8::Date::New(PI);
861 CHECK_EQ(3.0, date_obj->NumberValue());
862}
863
864
865THREADED_TEST(Boolean) {
866 v8::HandleScope scope;
867 LocalContext env;
868 v8::Handle<v8::Boolean> t = v8::True();
869 CHECK(t->Value());
870 v8::Handle<v8::Boolean> f = v8::False();
871 CHECK(!f->Value());
872 v8::Handle<v8::Primitive> u = v8::Undefined();
873 CHECK(!u->BooleanValue());
874 v8::Handle<v8::Primitive> n = v8::Null();
875 CHECK(!n->BooleanValue());
876 v8::Handle<String> str1 = v8_str("");
877 CHECK(!str1->BooleanValue());
878 v8::Handle<String> str2 = v8_str("x");
879 CHECK(str2->BooleanValue());
880 CHECK(!v8::Number::New(0)->BooleanValue());
881 CHECK(v8::Number::New(-1)->BooleanValue());
882 CHECK(v8::Number::New(1)->BooleanValue());
883 CHECK(v8::Number::New(42)->BooleanValue());
884 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
885}
886
887
888static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
889 ApiTestFuzzer::Fuzz();
890 return v8_num(13.4);
891}
892
893
894static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
895 ApiTestFuzzer::Fuzz();
896 return v8_num(876);
897}
898
899
900THREADED_TEST(GlobalPrototype) {
901 v8::HandleScope scope;
902 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
903 func_templ->PrototypeTemplate()->Set(
904 "dummy",
905 v8::FunctionTemplate::New(DummyCallHandler));
906 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
907 templ->Set("x", v8_num(200));
908 templ->SetAccessor(v8_str("m"), GetM);
909 LocalContext env(0, templ);
910 v8::Handle<v8::Object> obj = env->Global();
911 v8::Handle<Script> script = v8_compile("dummy()");
912 v8::Handle<Value> result = script->Run();
913 CHECK_EQ(13.4, result->NumberValue());
914 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
915 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
916}
917
918
Steve Blocka7e24c12009-10-30 11:49:00 +0000919THREADED_TEST(ObjectTemplate) {
920 v8::HandleScope scope;
921 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
922 templ1->Set("x", v8_num(10));
923 templ1->Set("y", v8_num(13));
924 LocalContext env;
925 Local<v8::Object> instance1 = templ1->NewInstance();
926 env->Global()->Set(v8_str("p"), instance1);
927 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
928 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
929 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
930 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
931 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
932 templ2->Set("a", v8_num(12));
933 templ2->Set("b", templ1);
934 Local<v8::Object> instance2 = templ2->NewInstance();
935 env->Global()->Set(v8_str("q"), instance2);
936 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
937 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
938 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
939 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
940}
941
942
943static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
944 ApiTestFuzzer::Fuzz();
945 return v8_num(17.2);
946}
947
948
949static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
950 ApiTestFuzzer::Fuzz();
951 return v8_num(15.2);
952}
953
954
955THREADED_TEST(DescriptorInheritance) {
956 v8::HandleScope scope;
957 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
958 super->PrototypeTemplate()->Set("flabby",
959 v8::FunctionTemplate::New(GetFlabby));
960 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
961
962 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
963
964 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
965 base1->Inherit(super);
966 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
967
968 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
969 base2->Inherit(super);
970 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
971
972 LocalContext env;
973
974 env->Global()->Set(v8_str("s"), super->GetFunction());
975 env->Global()->Set(v8_str("base1"), base1->GetFunction());
976 env->Global()->Set(v8_str("base2"), base2->GetFunction());
977
978 // Checks right __proto__ chain.
979 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
980 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
981
982 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
983
984 // Instance accessor should not be visible on function object or its prototype
985 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
986 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
987 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
988
989 env->Global()->Set(v8_str("obj"),
990 base1->GetFunction()->NewInstance());
991 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
992 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
993 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
994 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
995 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
996
997 env->Global()->Set(v8_str("obj2"),
998 base2->GetFunction()->NewInstance());
999 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1000 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1001 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1002 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1003 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1004
1005 // base1 and base2 cannot cross reference to each's prototype
1006 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1007 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1008}
1009
1010
1011int echo_named_call_count;
1012
1013
1014static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1015 const AccessorInfo& info) {
1016 ApiTestFuzzer::Fuzz();
1017 CHECK_EQ(v8_str("data"), info.Data());
1018 echo_named_call_count++;
1019 return name;
1020}
1021
1022
1023THREADED_TEST(NamedPropertyHandlerGetter) {
1024 echo_named_call_count = 0;
1025 v8::HandleScope scope;
1026 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1027 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1028 0, 0, 0, 0,
1029 v8_str("data"));
1030 LocalContext env;
1031 env->Global()->Set(v8_str("obj"),
1032 templ->GetFunction()->NewInstance());
1033 CHECK_EQ(echo_named_call_count, 0);
1034 v8_compile("obj.x")->Run();
1035 CHECK_EQ(echo_named_call_count, 1);
1036 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1037 v8::Handle<Value> str = CompileRun(code);
1038 String::AsciiValue value(str);
1039 CHECK_EQ(*value, "oddlepoddle");
1040 // Check default behavior
1041 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1042 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1043 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1044}
1045
1046
1047int echo_indexed_call_count = 0;
1048
1049
1050static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1051 const AccessorInfo& info) {
1052 ApiTestFuzzer::Fuzz();
1053 CHECK_EQ(v8_num(637), info.Data());
1054 echo_indexed_call_count++;
1055 return v8_num(index);
1056}
1057
1058
1059THREADED_TEST(IndexedPropertyHandlerGetter) {
1060 v8::HandleScope scope;
1061 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1062 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1063 0, 0, 0, 0,
1064 v8_num(637));
1065 LocalContext env;
1066 env->Global()->Set(v8_str("obj"),
1067 templ->GetFunction()->NewInstance());
1068 Local<Script> script = v8_compile("obj[900]");
1069 CHECK_EQ(script->Run()->Int32Value(), 900);
1070}
1071
1072
1073v8::Handle<v8::Object> bottom;
1074
1075static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1076 uint32_t index,
1077 const AccessorInfo& info) {
1078 ApiTestFuzzer::Fuzz();
1079 CHECK(info.This()->Equals(bottom));
1080 return v8::Handle<Value>();
1081}
1082
1083static v8::Handle<Value> CheckThisNamedPropertyHandler(
1084 Local<String> name,
1085 const AccessorInfo& info) {
1086 ApiTestFuzzer::Fuzz();
1087 CHECK(info.This()->Equals(bottom));
1088 return v8::Handle<Value>();
1089}
1090
1091
1092v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1093 Local<Value> value,
1094 const AccessorInfo& info) {
1095 ApiTestFuzzer::Fuzz();
1096 CHECK(info.This()->Equals(bottom));
1097 return v8::Handle<Value>();
1098}
1099
1100
1101v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1102 Local<Value> value,
1103 const AccessorInfo& info) {
1104 ApiTestFuzzer::Fuzz();
1105 CHECK(info.This()->Equals(bottom));
1106 return v8::Handle<Value>();
1107}
1108
1109v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1110 uint32_t index,
1111 const AccessorInfo& info) {
1112 ApiTestFuzzer::Fuzz();
1113 CHECK(info.This()->Equals(bottom));
1114 return v8::Handle<v8::Boolean>();
1115}
1116
1117
1118v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1119 const AccessorInfo& info) {
1120 ApiTestFuzzer::Fuzz();
1121 CHECK(info.This()->Equals(bottom));
1122 return v8::Handle<v8::Boolean>();
1123}
1124
1125
1126v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1127 uint32_t index,
1128 const AccessorInfo& info) {
1129 ApiTestFuzzer::Fuzz();
1130 CHECK(info.This()->Equals(bottom));
1131 return v8::Handle<v8::Boolean>();
1132}
1133
1134
1135v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1136 Local<String> property,
1137 const AccessorInfo& info) {
1138 ApiTestFuzzer::Fuzz();
1139 CHECK(info.This()->Equals(bottom));
1140 return v8::Handle<v8::Boolean>();
1141}
1142
1143
1144v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1145 const AccessorInfo& info) {
1146 ApiTestFuzzer::Fuzz();
1147 CHECK(info.This()->Equals(bottom));
1148 return v8::Handle<v8::Array>();
1149}
1150
1151
1152v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1153 const AccessorInfo& info) {
1154 ApiTestFuzzer::Fuzz();
1155 CHECK(info.This()->Equals(bottom));
1156 return v8::Handle<v8::Array>();
1157}
1158
1159
1160THREADED_TEST(PropertyHandlerInPrototype) {
1161 v8::HandleScope scope;
1162 LocalContext env;
1163
1164 // Set up a prototype chain with three interceptors.
1165 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1166 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1167 CheckThisIndexedPropertyHandler,
1168 CheckThisIndexedPropertySetter,
1169 CheckThisIndexedPropertyQuery,
1170 CheckThisIndexedPropertyDeleter,
1171 CheckThisIndexedPropertyEnumerator);
1172
1173 templ->InstanceTemplate()->SetNamedPropertyHandler(
1174 CheckThisNamedPropertyHandler,
1175 CheckThisNamedPropertySetter,
1176 CheckThisNamedPropertyQuery,
1177 CheckThisNamedPropertyDeleter,
1178 CheckThisNamedPropertyEnumerator);
1179
1180 bottom = templ->GetFunction()->NewInstance();
1181 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1182 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1183
1184 bottom->Set(v8_str("__proto__"), middle);
1185 middle->Set(v8_str("__proto__"), top);
1186 env->Global()->Set(v8_str("obj"), bottom);
1187
1188 // Indexed and named get.
1189 Script::Compile(v8_str("obj[0]"))->Run();
1190 Script::Compile(v8_str("obj.x"))->Run();
1191
1192 // Indexed and named set.
1193 Script::Compile(v8_str("obj[1] = 42"))->Run();
1194 Script::Compile(v8_str("obj.y = 42"))->Run();
1195
1196 // Indexed and named query.
1197 Script::Compile(v8_str("0 in obj"))->Run();
1198 Script::Compile(v8_str("'x' in obj"))->Run();
1199
1200 // Indexed and named deleter.
1201 Script::Compile(v8_str("delete obj[0]"))->Run();
1202 Script::Compile(v8_str("delete obj.x"))->Run();
1203
1204 // Enumerators.
1205 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1206}
1207
1208
1209static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1210 const AccessorInfo& info) {
1211 ApiTestFuzzer::Fuzz();
1212 if (v8_str("pre")->Equals(key)) {
1213 return v8_str("PrePropertyHandler: pre");
1214 }
1215 return v8::Handle<String>();
1216}
1217
1218
1219static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1220 const AccessorInfo&) {
1221 if (v8_str("pre")->Equals(key)) {
1222 return v8::True();
1223 }
1224
1225 return v8::Handle<v8::Boolean>(); // do not intercept the call
1226}
1227
1228
1229THREADED_TEST(PrePropertyHandler) {
1230 v8::HandleScope scope;
1231 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1232 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1233 0,
1234 PrePropertyHandlerHas);
1235 LocalContext env(NULL, desc->InstanceTemplate());
1236 Script::Compile(v8_str(
1237 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1238 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1239 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1240 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1241 CHECK_EQ(v8_str("Object: on"), result_on);
1242 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1243 CHECK(result_post.IsEmpty());
1244}
1245
1246
1247THREADED_TEST(UndefinedIsNotEnumerable) {
1248 v8::HandleScope scope;
1249 LocalContext env;
1250 v8::Handle<Value> result = Script::Compile(v8_str(
1251 "this.propertyIsEnumerable(undefined)"))->Run();
1252 CHECK(result->IsFalse());
1253}
1254
1255
1256v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001257static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001258
1259
1260static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1261 ApiTestFuzzer::Fuzz();
1262 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1263 if (depth == kTargetRecursionDepth) return v8::Undefined();
1264 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1265 return call_recursively_script->Run();
1266}
1267
1268
1269static v8::Handle<Value> CallFunctionRecursivelyCall(
1270 const v8::Arguments& args) {
1271 ApiTestFuzzer::Fuzz();
1272 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1273 if (depth == kTargetRecursionDepth) {
1274 printf("[depth = %d]\n", depth);
1275 return v8::Undefined();
1276 }
1277 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1278 v8::Handle<Value> function =
1279 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001280 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001281}
1282
1283
1284THREADED_TEST(DeepCrossLanguageRecursion) {
1285 v8::HandleScope scope;
1286 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1287 global->Set(v8_str("callScriptRecursively"),
1288 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1289 global->Set(v8_str("callFunctionRecursively"),
1290 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1291 LocalContext env(NULL, global);
1292
1293 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1294 call_recursively_script = v8_compile("callScriptRecursively()");
1295 v8::Handle<Value> result = call_recursively_script->Run();
1296 call_recursively_script = v8::Handle<Script>();
1297
1298 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1299 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1300}
1301
1302
1303static v8::Handle<Value>
1304 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1305 ApiTestFuzzer::Fuzz();
1306 return v8::ThrowException(key);
1307}
1308
1309
1310static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1311 Local<Value>,
1312 const AccessorInfo&) {
1313 v8::ThrowException(key);
1314 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1315}
1316
1317
1318THREADED_TEST(CallbackExceptionRegression) {
1319 v8::HandleScope scope;
1320 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1321 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1322 ThrowingPropertyHandlerSet);
1323 LocalContext env;
1324 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1325 v8::Handle<Value> otto = Script::Compile(v8_str(
1326 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1327 CHECK_EQ(v8_str("otto"), otto);
1328 v8::Handle<Value> netto = Script::Compile(v8_str(
1329 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1330 CHECK_EQ(v8_str("netto"), netto);
1331}
1332
1333
Steve Blocka7e24c12009-10-30 11:49:00 +00001334THREADED_TEST(FunctionPrototype) {
1335 v8::HandleScope scope;
1336 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1337 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1338 LocalContext env;
1339 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1340 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1341 CHECK_EQ(script->Run()->Int32Value(), 321);
1342}
1343
1344
1345THREADED_TEST(InternalFields) {
1346 v8::HandleScope scope;
1347 LocalContext env;
1348
1349 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1350 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1351 instance_templ->SetInternalFieldCount(1);
1352 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1353 CHECK_EQ(1, obj->InternalFieldCount());
1354 CHECK(obj->GetInternalField(0)->IsUndefined());
1355 obj->SetInternalField(0, v8_num(17));
1356 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1357}
1358
1359
Steve Block6ded16b2010-05-10 14:33:55 +01001360THREADED_TEST(GlobalObjectInternalFields) {
1361 v8::HandleScope scope;
1362 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1363 global_template->SetInternalFieldCount(1);
1364 LocalContext env(NULL, global_template);
1365 v8::Handle<v8::Object> global_proxy = env->Global();
1366 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1367 CHECK_EQ(1, global->InternalFieldCount());
1368 CHECK(global->GetInternalField(0)->IsUndefined());
1369 global->SetInternalField(0, v8_num(17));
1370 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1371}
1372
1373
Steve Blocka7e24c12009-10-30 11:49:00 +00001374THREADED_TEST(InternalFieldsNativePointers) {
1375 v8::HandleScope scope;
1376 LocalContext env;
1377
1378 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1379 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1380 instance_templ->SetInternalFieldCount(1);
1381 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1382 CHECK_EQ(1, obj->InternalFieldCount());
1383 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1384
1385 char* data = new char[100];
1386
1387 void* aligned = data;
1388 CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1389 void* unaligned = data + 1;
1390 CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1391
1392 // Check reading and writing aligned pointers.
1393 obj->SetPointerInInternalField(0, aligned);
1394 i::Heap::CollectAllGarbage(false);
1395 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1396
1397 // Check reading and writing unaligned pointers.
1398 obj->SetPointerInInternalField(0, unaligned);
1399 i::Heap::CollectAllGarbage(false);
1400 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1401
1402 delete[] data;
1403}
1404
1405
Steve Block3ce2e202009-11-05 08:53:23 +00001406THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1407 v8::HandleScope scope;
1408 LocalContext env;
1409
1410 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1411 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1412 instance_templ->SetInternalFieldCount(1);
1413 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1414 CHECK_EQ(1, obj->InternalFieldCount());
1415 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1416
1417 char* data = new char[100];
1418
1419 void* aligned = data;
1420 CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1421 void* unaligned = data + 1;
1422 CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1423
1424 obj->SetPointerInInternalField(0, aligned);
1425 i::Heap::CollectAllGarbage(false);
1426 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1427
1428 obj->SetPointerInInternalField(0, unaligned);
1429 i::Heap::CollectAllGarbage(false);
1430 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1431
1432 obj->SetInternalField(0, v8::External::Wrap(aligned));
1433 i::Heap::CollectAllGarbage(false);
1434 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1435
1436 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1437 i::Heap::CollectAllGarbage(false);
1438 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1439
1440 delete[] data;
1441}
1442
1443
Steve Blocka7e24c12009-10-30 11:49:00 +00001444THREADED_TEST(IdentityHash) {
1445 v8::HandleScope scope;
1446 LocalContext env;
1447
1448 // Ensure that the test starts with an fresh heap to test whether the hash
1449 // code is based on the address.
1450 i::Heap::CollectAllGarbage(false);
1451 Local<v8::Object> obj = v8::Object::New();
1452 int hash = obj->GetIdentityHash();
1453 int hash1 = obj->GetIdentityHash();
1454 CHECK_EQ(hash, hash1);
1455 int hash2 = v8::Object::New()->GetIdentityHash();
1456 // Since the identity hash is essentially a random number two consecutive
1457 // objects should not be assigned the same hash code. If the test below fails
1458 // the random number generator should be evaluated.
1459 CHECK_NE(hash, hash2);
1460 i::Heap::CollectAllGarbage(false);
1461 int hash3 = v8::Object::New()->GetIdentityHash();
1462 // Make sure that the identity hash is not based on the initial address of
1463 // the object alone. If the test below fails the random number generator
1464 // should be evaluated.
1465 CHECK_NE(hash, hash3);
1466 int hash4 = obj->GetIdentityHash();
1467 CHECK_EQ(hash, hash4);
1468}
1469
1470
1471THREADED_TEST(HiddenProperties) {
1472 v8::HandleScope scope;
1473 LocalContext env;
1474
1475 v8::Local<v8::Object> obj = v8::Object::New();
1476 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1477 v8::Local<v8::String> empty = v8_str("");
1478 v8::Local<v8::String> prop_name = v8_str("prop_name");
1479
1480 i::Heap::CollectAllGarbage(false);
1481
1482 // Make sure delete of a non-existent hidden value works
1483 CHECK(obj->DeleteHiddenValue(key));
1484
1485 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1486 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1487 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1488 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1489
1490 i::Heap::CollectAllGarbage(false);
1491
1492 // Make sure we do not find the hidden property.
1493 CHECK(!obj->Has(empty));
1494 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1495 CHECK(obj->Get(empty)->IsUndefined());
1496 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1497 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1498 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1499 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1500
1501 i::Heap::CollectAllGarbage(false);
1502
1503 // Add another property and delete it afterwards to force the object in
1504 // slow case.
1505 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1506 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1507 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1508 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1509 CHECK(obj->Delete(prop_name));
1510 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1511
1512 i::Heap::CollectAllGarbage(false);
1513
1514 CHECK(obj->DeleteHiddenValue(key));
1515 CHECK(obj->GetHiddenValue(key).IsEmpty());
1516}
1517
1518
Steve Blockd0582a62009-12-15 09:54:21 +00001519static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00001520static v8::Handle<Value> InterceptorForHiddenProperties(
1521 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00001522 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001523 return v8::Handle<Value>();
1524}
1525
1526
1527THREADED_TEST(HiddenPropertiesWithInterceptors) {
1528 v8::HandleScope scope;
1529 LocalContext context;
1530
Steve Blockd0582a62009-12-15 09:54:21 +00001531 interceptor_for_hidden_properties_called = false;
1532
Steve Blocka7e24c12009-10-30 11:49:00 +00001533 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1534
1535 // Associate an interceptor with an object and start setting hidden values.
1536 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1537 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1538 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1539 Local<v8::Function> function = fun_templ->GetFunction();
1540 Local<v8::Object> obj = function->NewInstance();
1541 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1542 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00001543 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00001544}
1545
1546
1547THREADED_TEST(External) {
1548 v8::HandleScope scope;
1549 int x = 3;
1550 Local<v8::External> ext = v8::External::New(&x);
1551 LocalContext env;
1552 env->Global()->Set(v8_str("ext"), ext);
1553 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001554 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 int* ptr = static_cast<int*>(reext->Value());
1556 CHECK_EQ(x, 3);
1557 *ptr = 10;
1558 CHECK_EQ(x, 10);
1559
1560 // Make sure unaligned pointers are wrapped properly.
1561 char* data = i::StrDup("0123456789");
1562 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1563 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1564 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1565 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1566
1567 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1568 CHECK_EQ('0', *char_ptr);
1569 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1570 CHECK_EQ('1', *char_ptr);
1571 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1572 CHECK_EQ('2', *char_ptr);
1573 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1574 CHECK_EQ('3', *char_ptr);
1575 i::DeleteArray(data);
1576}
1577
1578
1579THREADED_TEST(GlobalHandle) {
1580 v8::Persistent<String> global;
1581 {
1582 v8::HandleScope scope;
1583 Local<String> str = v8_str("str");
1584 global = v8::Persistent<String>::New(str);
1585 }
1586 CHECK_EQ(global->Length(), 3);
1587 global.Dispose();
1588}
1589
1590
1591THREADED_TEST(ScriptException) {
1592 v8::HandleScope scope;
1593 LocalContext env;
1594 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1595 v8::TryCatch try_catch;
1596 Local<Value> result = script->Run();
1597 CHECK(result.IsEmpty());
1598 CHECK(try_catch.HasCaught());
1599 String::AsciiValue exception_value(try_catch.Exception());
1600 CHECK_EQ(*exception_value, "panama!");
1601}
1602
1603
1604bool message_received;
1605
1606
1607static void check_message(v8::Handle<v8::Message> message,
1608 v8::Handle<Value> data) {
1609 CHECK_EQ(5.76, data->NumberValue());
1610 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1611 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1612 message_received = true;
1613}
1614
1615
1616THREADED_TEST(MessageHandlerData) {
1617 message_received = false;
1618 v8::HandleScope scope;
1619 CHECK(!message_received);
1620 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1621 LocalContext context;
1622 v8::ScriptOrigin origin =
1623 v8::ScriptOrigin(v8_str("6.75"));
1624 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1625 &origin);
1626 script->SetData(v8_str("7.56"));
1627 script->Run();
1628 CHECK(message_received);
1629 // clear out the message listener
1630 v8::V8::RemoveMessageListeners(check_message);
1631}
1632
1633
1634THREADED_TEST(GetSetProperty) {
1635 v8::HandleScope scope;
1636 LocalContext context;
1637 context->Global()->Set(v8_str("foo"), v8_num(14));
1638 context->Global()->Set(v8_str("12"), v8_num(92));
1639 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1640 context->Global()->Set(v8_num(13), v8_num(56));
1641 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1642 CHECK_EQ(14, foo->Int32Value());
1643 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1644 CHECK_EQ(92, twelve->Int32Value());
1645 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1646 CHECK_EQ(32, sixteen->Int32Value());
1647 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1648 CHECK_EQ(56, thirteen->Int32Value());
1649 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1650 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1651 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1652 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1653 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1654 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1655 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1656 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1657 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1658}
1659
1660
1661THREADED_TEST(PropertyAttributes) {
1662 v8::HandleScope scope;
1663 LocalContext context;
1664 // read-only
1665 Local<String> prop = v8_str("read_only");
1666 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1667 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1668 Script::Compile(v8_str("read_only = 9"))->Run();
1669 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1670 context->Global()->Set(prop, v8_num(10));
1671 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1672 // dont-delete
1673 prop = v8_str("dont_delete");
1674 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1675 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1676 Script::Compile(v8_str("delete dont_delete"))->Run();
1677 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1678}
1679
1680
1681THREADED_TEST(Array) {
1682 v8::HandleScope scope;
1683 LocalContext context;
1684 Local<v8::Array> array = v8::Array::New();
1685 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001686 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001687 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01001688 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001689 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01001690 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00001691 CHECK_EQ(3, array->Length());
1692 CHECK(!array->Has(0));
1693 CHECK(!array->Has(1));
1694 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01001695 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001696 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001697 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001698 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001699 CHECK_EQ(1, arr->Get(0)->Int32Value());
1700 CHECK_EQ(2, arr->Get(1)->Int32Value());
1701 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001702}
1703
1704
1705v8::Handle<Value> HandleF(const v8::Arguments& args) {
1706 v8::HandleScope scope;
1707 ApiTestFuzzer::Fuzz();
1708 Local<v8::Array> result = v8::Array::New(args.Length());
1709 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01001710 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001711 return scope.Close(result);
1712}
1713
1714
1715THREADED_TEST(Vector) {
1716 v8::HandleScope scope;
1717 Local<ObjectTemplate> global = ObjectTemplate::New();
1718 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1719 LocalContext context(0, global);
1720
1721 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01001722 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 CHECK_EQ(0, a0->Length());
1724
1725 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01001726 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001727 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001728 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001729
1730 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01001731 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001732 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001733 CHECK_EQ(12, a2->Get(0)->Int32Value());
1734 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001735
1736 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01001737 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001738 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001739 CHECK_EQ(14, a3->Get(0)->Int32Value());
1740 CHECK_EQ(15, a3->Get(1)->Int32Value());
1741 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001742
1743 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01001744 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001746 CHECK_EQ(17, a4->Get(0)->Int32Value());
1747 CHECK_EQ(18, a4->Get(1)->Int32Value());
1748 CHECK_EQ(19, a4->Get(2)->Int32Value());
1749 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001750}
1751
1752
1753THREADED_TEST(FunctionCall) {
1754 v8::HandleScope scope;
1755 LocalContext context;
1756 CompileRun(
1757 "function Foo() {"
1758 " var result = [];"
1759 " for (var i = 0; i < arguments.length; i++) {"
1760 " result.push(arguments[i]);"
1761 " }"
1762 " return result;"
1763 "}");
1764 Local<Function> Foo =
1765 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1766
1767 v8::Handle<Value>* args0 = NULL;
1768 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1769 CHECK_EQ(0, a0->Length());
1770
1771 v8::Handle<Value> args1[] = { v8_num(1.1) };
1772 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1773 CHECK_EQ(1, a1->Length());
1774 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1775
1776 v8::Handle<Value> args2[] = { v8_num(2.2),
1777 v8_num(3.3) };
1778 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1779 CHECK_EQ(2, a2->Length());
1780 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1781 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1782
1783 v8::Handle<Value> args3[] = { v8_num(4.4),
1784 v8_num(5.5),
1785 v8_num(6.6) };
1786 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1787 CHECK_EQ(3, a3->Length());
1788 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1789 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1790 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1791
1792 v8::Handle<Value> args4[] = { v8_num(7.7),
1793 v8_num(8.8),
1794 v8_num(9.9),
1795 v8_num(10.11) };
1796 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1797 CHECK_EQ(4, a4->Length());
1798 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1799 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1800 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1801 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1802}
1803
1804
1805static const char* js_code_causing_out_of_memory =
1806 "var a = new Array(); while(true) a.push(a);";
1807
1808
1809// These tests run for a long time and prevent us from running tests
1810// that come after them so they cannot run in parallel.
1811TEST(OutOfMemory) {
1812 // It's not possible to read a snapshot into a heap with different dimensions.
1813 if (v8::internal::Snapshot::IsEnabled()) return;
1814 // Set heap limits.
1815 static const int K = 1024;
1816 v8::ResourceConstraints constraints;
1817 constraints.set_max_young_space_size(256 * K);
1818 constraints.set_max_old_space_size(4 * K * K);
1819 v8::SetResourceConstraints(&constraints);
1820
1821 // Execute a script that causes out of memory.
1822 v8::HandleScope scope;
1823 LocalContext context;
1824 v8::V8::IgnoreOutOfMemoryException();
1825 Local<Script> script =
1826 Script::Compile(String::New(js_code_causing_out_of_memory));
1827 Local<Value> result = script->Run();
1828
1829 // Check for out of memory state.
1830 CHECK(result.IsEmpty());
1831 CHECK(context->HasOutOfMemoryException());
1832}
1833
1834
1835v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1836 ApiTestFuzzer::Fuzz();
1837
1838 v8::HandleScope scope;
1839 LocalContext context;
1840 Local<Script> script =
1841 Script::Compile(String::New(js_code_causing_out_of_memory));
1842 Local<Value> result = script->Run();
1843
1844 // Check for out of memory state.
1845 CHECK(result.IsEmpty());
1846 CHECK(context->HasOutOfMemoryException());
1847
1848 return result;
1849}
1850
1851
1852TEST(OutOfMemoryNested) {
1853 // It's not possible to read a snapshot into a heap with different dimensions.
1854 if (v8::internal::Snapshot::IsEnabled()) return;
1855 // Set heap limits.
1856 static const int K = 1024;
1857 v8::ResourceConstraints constraints;
1858 constraints.set_max_young_space_size(256 * K);
1859 constraints.set_max_old_space_size(4 * K * K);
1860 v8::SetResourceConstraints(&constraints);
1861
1862 v8::HandleScope scope;
1863 Local<ObjectTemplate> templ = ObjectTemplate::New();
1864 templ->Set(v8_str("ProvokeOutOfMemory"),
1865 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1866 LocalContext context(0, templ);
1867 v8::V8::IgnoreOutOfMemoryException();
1868 Local<Value> result = CompileRun(
1869 "var thrown = false;"
1870 "try {"
1871 " ProvokeOutOfMemory();"
1872 "} catch (e) {"
1873 " thrown = true;"
1874 "}");
1875 // Check for out of memory state.
1876 CHECK(result.IsEmpty());
1877 CHECK(context->HasOutOfMemoryException());
1878}
1879
1880
1881TEST(HugeConsStringOutOfMemory) {
1882 // It's not possible to read a snapshot into a heap with different dimensions.
1883 if (v8::internal::Snapshot::IsEnabled()) return;
1884 v8::HandleScope scope;
1885 LocalContext context;
1886 // Set heap limits.
1887 static const int K = 1024;
1888 v8::ResourceConstraints constraints;
1889 constraints.set_max_young_space_size(256 * K);
1890 constraints.set_max_old_space_size(2 * K * K);
1891 v8::SetResourceConstraints(&constraints);
1892
1893 // Execute a script that causes out of memory.
1894 v8::V8::IgnoreOutOfMemoryException();
1895
1896 // Build huge string. This should fail with out of memory exception.
1897 Local<Value> result = CompileRun(
1898 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00001899 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00001900
1901 // Check for out of memory state.
1902 CHECK(result.IsEmpty());
1903 CHECK(context->HasOutOfMemoryException());
1904}
1905
1906
1907THREADED_TEST(ConstructCall) {
1908 v8::HandleScope scope;
1909 LocalContext context;
1910 CompileRun(
1911 "function Foo() {"
1912 " var result = [];"
1913 " for (var i = 0; i < arguments.length; i++) {"
1914 " result.push(arguments[i]);"
1915 " }"
1916 " return result;"
1917 "}");
1918 Local<Function> Foo =
1919 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1920
1921 v8::Handle<Value>* args0 = NULL;
1922 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1923 CHECK_EQ(0, a0->Length());
1924
1925 v8::Handle<Value> args1[] = { v8_num(1.1) };
1926 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1927 CHECK_EQ(1, a1->Length());
1928 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1929
1930 v8::Handle<Value> args2[] = { v8_num(2.2),
1931 v8_num(3.3) };
1932 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1933 CHECK_EQ(2, a2->Length());
1934 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1935 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1936
1937 v8::Handle<Value> args3[] = { v8_num(4.4),
1938 v8_num(5.5),
1939 v8_num(6.6) };
1940 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1941 CHECK_EQ(3, a3->Length());
1942 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1943 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1944 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1945
1946 v8::Handle<Value> args4[] = { v8_num(7.7),
1947 v8_num(8.8),
1948 v8_num(9.9),
1949 v8_num(10.11) };
1950 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1951 CHECK_EQ(4, a4->Length());
1952 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1953 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1954 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1955 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1956}
1957
1958
1959static void CheckUncle(v8::TryCatch* try_catch) {
1960 CHECK(try_catch->HasCaught());
1961 String::AsciiValue str_value(try_catch->Exception());
1962 CHECK_EQ(*str_value, "uncle?");
1963 try_catch->Reset();
1964}
1965
1966
Steve Block6ded16b2010-05-10 14:33:55 +01001967THREADED_TEST(ConversionNumber) {
1968 v8::HandleScope scope;
1969 LocalContext env;
1970 // Very large number.
1971 CompileRun("var obj = Math.pow(2,32) * 1237;");
1972 Local<Value> obj = env->Global()->Get(v8_str("obj"));
1973 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
1974 CHECK_EQ(0, obj->ToInt32()->Value());
1975 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
1976 // Large number.
1977 CompileRun("var obj = -1234567890123;");
1978 obj = env->Global()->Get(v8_str("obj"));
1979 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
1980 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
1981 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
1982 // Small positive integer.
1983 CompileRun("var obj = 42;");
1984 obj = env->Global()->Get(v8_str("obj"));
1985 CHECK_EQ(42.0, obj->ToNumber()->Value());
1986 CHECK_EQ(42, obj->ToInt32()->Value());
1987 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
1988 // Negative integer.
1989 CompileRun("var obj = -37;");
1990 obj = env->Global()->Get(v8_str("obj"));
1991 CHECK_EQ(-37.0, obj->ToNumber()->Value());
1992 CHECK_EQ(-37, obj->ToInt32()->Value());
1993 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
1994 // Positive non-int32 integer.
1995 CompileRun("var obj = 0x81234567;");
1996 obj = env->Global()->Get(v8_str("obj"));
1997 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
1998 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
1999 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2000 // Fraction.
2001 CompileRun("var obj = 42.3;");
2002 obj = env->Global()->Get(v8_str("obj"));
2003 CHECK_EQ(42.3, obj->ToNumber()->Value());
2004 CHECK_EQ(42, obj->ToInt32()->Value());
2005 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2006 // Large negative fraction.
2007 CompileRun("var obj = -5726623061.75;");
2008 obj = env->Global()->Get(v8_str("obj"));
2009 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2010 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2011 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2012}
2013
2014
2015THREADED_TEST(isNumberType) {
2016 v8::HandleScope scope;
2017 LocalContext env;
2018 // Very large number.
2019 CompileRun("var obj = Math.pow(2,32) * 1237;");
2020 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2021 CHECK(!obj->IsInt32());
2022 CHECK(!obj->IsUint32());
2023 // Large negative number.
2024 CompileRun("var obj = -1234567890123;");
2025 obj = env->Global()->Get(v8_str("obj"));
2026 CHECK(!obj->IsInt32());
2027 CHECK(!obj->IsUint32());
2028 // Small positive integer.
2029 CompileRun("var obj = 42;");
2030 obj = env->Global()->Get(v8_str("obj"));
2031 CHECK(obj->IsInt32());
2032 CHECK(obj->IsUint32());
2033 // Negative integer.
2034 CompileRun("var obj = -37;");
2035 obj = env->Global()->Get(v8_str("obj"));
2036 CHECK(obj->IsInt32());
2037 CHECK(!obj->IsUint32());
2038 // Positive non-int32 integer.
2039 CompileRun("var obj = 0x81234567;");
2040 obj = env->Global()->Get(v8_str("obj"));
2041 CHECK(!obj->IsInt32());
2042 CHECK(obj->IsUint32());
2043 // Fraction.
2044 CompileRun("var obj = 42.3;");
2045 obj = env->Global()->Get(v8_str("obj"));
2046 CHECK(!obj->IsInt32());
2047 CHECK(!obj->IsUint32());
2048 // Large negative fraction.
2049 CompileRun("var obj = -5726623061.75;");
2050 obj = env->Global()->Get(v8_str("obj"));
2051 CHECK(!obj->IsInt32());
2052 CHECK(!obj->IsUint32());
2053}
2054
2055
Steve Blocka7e24c12009-10-30 11:49:00 +00002056THREADED_TEST(ConversionException) {
2057 v8::HandleScope scope;
2058 LocalContext env;
2059 CompileRun(
2060 "function TestClass() { };"
2061 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2062 "var obj = new TestClass();");
2063 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2064
2065 v8::TryCatch try_catch;
2066
2067 Local<Value> to_string_result = obj->ToString();
2068 CHECK(to_string_result.IsEmpty());
2069 CheckUncle(&try_catch);
2070
2071 Local<Value> to_number_result = obj->ToNumber();
2072 CHECK(to_number_result.IsEmpty());
2073 CheckUncle(&try_catch);
2074
2075 Local<Value> to_integer_result = obj->ToInteger();
2076 CHECK(to_integer_result.IsEmpty());
2077 CheckUncle(&try_catch);
2078
2079 Local<Value> to_uint32_result = obj->ToUint32();
2080 CHECK(to_uint32_result.IsEmpty());
2081 CheckUncle(&try_catch);
2082
2083 Local<Value> to_int32_result = obj->ToInt32();
2084 CHECK(to_int32_result.IsEmpty());
2085 CheckUncle(&try_catch);
2086
2087 Local<Value> to_object_result = v8::Undefined()->ToObject();
2088 CHECK(to_object_result.IsEmpty());
2089 CHECK(try_catch.HasCaught());
2090 try_catch.Reset();
2091
2092 int32_t int32_value = obj->Int32Value();
2093 CHECK_EQ(0, int32_value);
2094 CheckUncle(&try_catch);
2095
2096 uint32_t uint32_value = obj->Uint32Value();
2097 CHECK_EQ(0, uint32_value);
2098 CheckUncle(&try_catch);
2099
2100 double number_value = obj->NumberValue();
2101 CHECK_NE(0, IsNaN(number_value));
2102 CheckUncle(&try_catch);
2103
2104 int64_t integer_value = obj->IntegerValue();
2105 CHECK_EQ(0.0, static_cast<double>(integer_value));
2106 CheckUncle(&try_catch);
2107}
2108
2109
2110v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2111 ApiTestFuzzer::Fuzz();
2112 return v8::ThrowException(v8_str("konto"));
2113}
2114
2115
2116v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2117 if (args.Length() < 1) return v8::Boolean::New(false);
2118 v8::HandleScope scope;
2119 v8::TryCatch try_catch;
2120 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2121 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2122 return v8::Boolean::New(try_catch.HasCaught());
2123}
2124
2125
2126THREADED_TEST(APICatch) {
2127 v8::HandleScope scope;
2128 Local<ObjectTemplate> templ = ObjectTemplate::New();
2129 templ->Set(v8_str("ThrowFromC"),
2130 v8::FunctionTemplate::New(ThrowFromC));
2131 LocalContext context(0, templ);
2132 CompileRun(
2133 "var thrown = false;"
2134 "try {"
2135 " ThrowFromC();"
2136 "} catch (e) {"
2137 " thrown = true;"
2138 "}");
2139 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2140 CHECK(thrown->BooleanValue());
2141}
2142
2143
2144THREADED_TEST(APIThrowTryCatch) {
2145 v8::HandleScope scope;
2146 Local<ObjectTemplate> templ = ObjectTemplate::New();
2147 templ->Set(v8_str("ThrowFromC"),
2148 v8::FunctionTemplate::New(ThrowFromC));
2149 LocalContext context(0, templ);
2150 v8::TryCatch try_catch;
2151 CompileRun("ThrowFromC();");
2152 CHECK(try_catch.HasCaught());
2153}
2154
2155
2156// Test that a try-finally block doesn't shadow a try-catch block
2157// when setting up an external handler.
2158//
2159// BUG(271): Some of the exception propagation does not work on the
2160// ARM simulator because the simulator separates the C++ stack and the
2161// JS stack. This test therefore fails on the simulator. The test is
2162// not threaded to allow the threading tests to run on the simulator.
2163TEST(TryCatchInTryFinally) {
2164 v8::HandleScope scope;
2165 Local<ObjectTemplate> templ = ObjectTemplate::New();
2166 templ->Set(v8_str("CCatcher"),
2167 v8::FunctionTemplate::New(CCatcher));
2168 LocalContext context(0, templ);
2169 Local<Value> result = CompileRun("try {"
2170 " try {"
2171 " CCatcher('throw 7;');"
2172 " } finally {"
2173 " }"
2174 "} catch (e) {"
2175 "}");
2176 CHECK(result->IsTrue());
2177}
2178
2179
2180static void receive_message(v8::Handle<v8::Message> message,
2181 v8::Handle<v8::Value> data) {
2182 message->Get();
2183 message_received = true;
2184}
2185
2186
2187TEST(APIThrowMessage) {
2188 message_received = false;
2189 v8::HandleScope scope;
2190 v8::V8::AddMessageListener(receive_message);
2191 Local<ObjectTemplate> templ = ObjectTemplate::New();
2192 templ->Set(v8_str("ThrowFromC"),
2193 v8::FunctionTemplate::New(ThrowFromC));
2194 LocalContext context(0, templ);
2195 CompileRun("ThrowFromC();");
2196 CHECK(message_received);
2197 v8::V8::RemoveMessageListeners(check_message);
2198}
2199
2200
2201TEST(APIThrowMessageAndVerboseTryCatch) {
2202 message_received = false;
2203 v8::HandleScope scope;
2204 v8::V8::AddMessageListener(receive_message);
2205 Local<ObjectTemplate> templ = ObjectTemplate::New();
2206 templ->Set(v8_str("ThrowFromC"),
2207 v8::FunctionTemplate::New(ThrowFromC));
2208 LocalContext context(0, templ);
2209 v8::TryCatch try_catch;
2210 try_catch.SetVerbose(true);
2211 Local<Value> result = CompileRun("ThrowFromC();");
2212 CHECK(try_catch.HasCaught());
2213 CHECK(result.IsEmpty());
2214 CHECK(message_received);
2215 v8::V8::RemoveMessageListeners(check_message);
2216}
2217
2218
2219THREADED_TEST(ExternalScriptException) {
2220 v8::HandleScope scope;
2221 Local<ObjectTemplate> templ = ObjectTemplate::New();
2222 templ->Set(v8_str("ThrowFromC"),
2223 v8::FunctionTemplate::New(ThrowFromC));
2224 LocalContext context(0, templ);
2225
2226 v8::TryCatch try_catch;
2227 Local<Script> script
2228 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2229 Local<Value> result = script->Run();
2230 CHECK(result.IsEmpty());
2231 CHECK(try_catch.HasCaught());
2232 String::AsciiValue exception_value(try_catch.Exception());
2233 CHECK_EQ("konto", *exception_value);
2234}
2235
2236
2237
2238v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2239 ApiTestFuzzer::Fuzz();
2240 CHECK_EQ(4, args.Length());
2241 int count = args[0]->Int32Value();
2242 int cInterval = args[2]->Int32Value();
2243 if (count == 0) {
2244 return v8::ThrowException(v8_str("FromC"));
2245 } else {
2246 Local<v8::Object> global = Context::GetCurrent()->Global();
2247 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2248 v8::Handle<Value> argv[] = { v8_num(count - 1),
2249 args[1],
2250 args[2],
2251 args[3] };
2252 if (count % cInterval == 0) {
2253 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01002254 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002255 int expected = args[3]->Int32Value();
2256 if (try_catch.HasCaught()) {
2257 CHECK_EQ(expected, count);
2258 CHECK(result.IsEmpty());
2259 CHECK(!i::Top::has_scheduled_exception());
2260 } else {
2261 CHECK_NE(expected, count);
2262 }
2263 return result;
2264 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002265 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 }
2267 }
2268}
2269
2270
2271v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2272 ApiTestFuzzer::Fuzz();
2273 CHECK_EQ(3, args.Length());
2274 bool equality = args[0]->BooleanValue();
2275 int count = args[1]->Int32Value();
2276 int expected = args[2]->Int32Value();
2277 if (equality) {
2278 CHECK_EQ(count, expected);
2279 } else {
2280 CHECK_NE(count, expected);
2281 }
2282 return v8::Undefined();
2283}
2284
2285
2286THREADED_TEST(EvalInTryFinally) {
2287 v8::HandleScope scope;
2288 LocalContext context;
2289 v8::TryCatch try_catch;
2290 CompileRun("(function() {"
2291 " try {"
2292 " eval('asldkf (*&^&*^');"
2293 " } finally {"
2294 " return;"
2295 " }"
2296 "})()");
2297 CHECK(!try_catch.HasCaught());
2298}
2299
2300
2301// This test works by making a stack of alternating JavaScript and C
2302// activations. These activations set up exception handlers with regular
2303// intervals, one interval for C activations and another for JavaScript
2304// activations. When enough activations have been created an exception is
2305// thrown and we check that the right activation catches the exception and that
2306// no other activations do. The right activation is always the topmost one with
2307// a handler, regardless of whether it is in JavaScript or C.
2308//
2309// The notation used to describe a test case looks like this:
2310//
2311// *JS[4] *C[3] @JS[2] C[1] JS[0]
2312//
2313// Each entry is an activation, either JS or C. The index is the count at that
2314// level. Stars identify activations with exception handlers, the @ identifies
2315// the exception handler that should catch the exception.
2316//
2317// BUG(271): Some of the exception propagation does not work on the
2318// ARM simulator because the simulator separates the C++ stack and the
2319// JS stack. This test therefore fails on the simulator. The test is
2320// not threaded to allow the threading tests to run on the simulator.
2321TEST(ExceptionOrder) {
2322 v8::HandleScope scope;
2323 Local<ObjectTemplate> templ = ObjectTemplate::New();
2324 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2325 templ->Set(v8_str("CThrowCountDown"),
2326 v8::FunctionTemplate::New(CThrowCountDown));
2327 LocalContext context(0, templ);
2328 CompileRun(
2329 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2330 " if (count == 0) throw 'FromJS';"
2331 " if (count % jsInterval == 0) {"
2332 " try {"
2333 " var value = CThrowCountDown(count - 1,"
2334 " jsInterval,"
2335 " cInterval,"
2336 " expected);"
2337 " check(false, count, expected);"
2338 " return value;"
2339 " } catch (e) {"
2340 " check(true, count, expected);"
2341 " }"
2342 " } else {"
2343 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2344 " }"
2345 "}");
2346 Local<Function> fun =
2347 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2348
2349 const int argc = 4;
2350 // count jsInterval cInterval expected
2351
2352 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2353 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2354 fun->Call(fun, argc, a0);
2355
2356 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2357 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2358 fun->Call(fun, argc, a1);
2359
2360 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2361 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2362 fun->Call(fun, argc, a2);
2363
2364 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2365 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2366 fun->Call(fun, argc, a3);
2367
2368 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2369 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2370 fun->Call(fun, argc, a4);
2371
2372 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2373 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2374 fun->Call(fun, argc, a5);
2375}
2376
2377
2378v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2379 ApiTestFuzzer::Fuzz();
2380 CHECK_EQ(1, args.Length());
2381 return v8::ThrowException(args[0]);
2382}
2383
2384
2385THREADED_TEST(ThrowValues) {
2386 v8::HandleScope scope;
2387 Local<ObjectTemplate> templ = ObjectTemplate::New();
2388 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2389 LocalContext context(0, templ);
2390 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2391 "function Run(obj) {"
2392 " try {"
2393 " Throw(obj);"
2394 " } catch (e) {"
2395 " return e;"
2396 " }"
2397 " return 'no exception';"
2398 "}"
2399 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2400 CHECK_EQ(5, result->Length());
2401 CHECK(result->Get(v8::Integer::New(0))->IsString());
2402 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2403 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2404 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2405 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2406 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2407 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2408}
2409
2410
2411THREADED_TEST(CatchZero) {
2412 v8::HandleScope scope;
2413 LocalContext context;
2414 v8::TryCatch try_catch;
2415 CHECK(!try_catch.HasCaught());
2416 Script::Compile(v8_str("throw 10"))->Run();
2417 CHECK(try_catch.HasCaught());
2418 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2419 try_catch.Reset();
2420 CHECK(!try_catch.HasCaught());
2421 Script::Compile(v8_str("throw 0"))->Run();
2422 CHECK(try_catch.HasCaught());
2423 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2424}
2425
2426
2427THREADED_TEST(CatchExceptionFromWith) {
2428 v8::HandleScope scope;
2429 LocalContext context;
2430 v8::TryCatch try_catch;
2431 CHECK(!try_catch.HasCaught());
2432 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2433 CHECK(try_catch.HasCaught());
2434}
2435
2436
2437THREADED_TEST(Equality) {
2438 v8::HandleScope scope;
2439 LocalContext context;
2440 // Check that equality works at all before relying on CHECK_EQ
2441 CHECK(v8_str("a")->Equals(v8_str("a")));
2442 CHECK(!v8_str("a")->Equals(v8_str("b")));
2443
2444 CHECK_EQ(v8_str("a"), v8_str("a"));
2445 CHECK_NE(v8_str("a"), v8_str("b"));
2446 CHECK_EQ(v8_num(1), v8_num(1));
2447 CHECK_EQ(v8_num(1.00), v8_num(1));
2448 CHECK_NE(v8_num(1), v8_num(2));
2449
2450 // Assume String is not symbol.
2451 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2452 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2453 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2454 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2455 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2456 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2457 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2458 CHECK(!not_a_number->StrictEquals(not_a_number));
2459 CHECK(v8::False()->StrictEquals(v8::False()));
2460 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2461
2462 v8::Handle<v8::Object> obj = v8::Object::New();
2463 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2464 CHECK(alias->StrictEquals(obj));
2465 alias.Dispose();
2466}
2467
2468
2469THREADED_TEST(MultiRun) {
2470 v8::HandleScope scope;
2471 LocalContext context;
2472 Local<Script> script = Script::Compile(v8_str("x"));
2473 for (int i = 0; i < 10; i++)
2474 script->Run();
2475}
2476
2477
2478static v8::Handle<Value> GetXValue(Local<String> name,
2479 const AccessorInfo& info) {
2480 ApiTestFuzzer::Fuzz();
2481 CHECK_EQ(info.Data(), v8_str("donut"));
2482 CHECK_EQ(name, v8_str("x"));
2483 return name;
2484}
2485
2486
2487THREADED_TEST(SimplePropertyRead) {
2488 v8::HandleScope scope;
2489 Local<ObjectTemplate> templ = ObjectTemplate::New();
2490 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2491 LocalContext context;
2492 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2493 Local<Script> script = Script::Compile(v8_str("obj.x"));
2494 for (int i = 0; i < 10; i++) {
2495 Local<Value> result = script->Run();
2496 CHECK_EQ(result, v8_str("x"));
2497 }
2498}
2499
Andrei Popescu31002712010-02-23 13:46:05 +00002500THREADED_TEST(DefinePropertyOnAPIAccessor) {
2501 v8::HandleScope scope;
2502 Local<ObjectTemplate> templ = ObjectTemplate::New();
2503 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2504 LocalContext context;
2505 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2506
2507 // Uses getOwnPropertyDescriptor to check the configurable status
2508 Local<Script> script_desc
2509 = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
2510 "obj, 'x');"
2511 "prop.configurable;"));
2512 Local<Value> result = script_desc->Run();
2513 CHECK_EQ(result->BooleanValue(), true);
2514
2515 // Redefine get - but still configurable
2516 Local<Script> script_define
2517 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2518 " configurable: true };"
2519 "Object.defineProperty(obj, 'x', desc);"
2520 "obj.x"));
2521 result = script_define->Run();
2522 CHECK_EQ(result, v8_num(42));
2523
2524 // Check that the accessor is still configurable
2525 result = script_desc->Run();
2526 CHECK_EQ(result->BooleanValue(), true);
2527
2528 // Redefine to a non-configurable
2529 script_define
2530 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2531 " configurable: false };"
2532 "Object.defineProperty(obj, 'x', desc);"
2533 "obj.x"));
2534 result = script_define->Run();
2535 CHECK_EQ(result, v8_num(43));
2536 result = script_desc->Run();
2537 CHECK_EQ(result->BooleanValue(), false);
2538
2539 // Make sure that it is not possible to redefine again
2540 v8::TryCatch try_catch;
2541 result = script_define->Run();
2542 CHECK(try_catch.HasCaught());
2543 String::AsciiValue exception_value(try_catch.Exception());
2544 CHECK_EQ(*exception_value,
2545 "TypeError: Cannot redefine property: defineProperty");
2546}
2547
2548THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2549 v8::HandleScope scope;
2550 Local<ObjectTemplate> templ = ObjectTemplate::New();
2551 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2552 LocalContext context;
2553 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2554
2555 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2556 "Object.getOwnPropertyDescriptor( "
2557 "obj, 'x');"
2558 "prop.configurable;"));
2559 Local<Value> result = script_desc->Run();
2560 CHECK_EQ(result->BooleanValue(), true);
2561
2562 Local<Script> script_define =
2563 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2564 " configurable: true };"
2565 "Object.defineProperty(obj, 'x', desc);"
2566 "obj.x"));
2567 result = script_define->Run();
2568 CHECK_EQ(result, v8_num(42));
2569
2570
2571 result = script_desc->Run();
2572 CHECK_EQ(result->BooleanValue(), true);
2573
2574
2575 script_define =
2576 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2577 " configurable: false };"
2578 "Object.defineProperty(obj, 'x', desc);"
2579 "obj.x"));
2580 result = script_define->Run();
2581 CHECK_EQ(result, v8_num(43));
2582 result = script_desc->Run();
2583
2584 CHECK_EQ(result->BooleanValue(), false);
2585
2586 v8::TryCatch try_catch;
2587 result = script_define->Run();
2588 CHECK(try_catch.HasCaught());
2589 String::AsciiValue exception_value(try_catch.Exception());
2590 CHECK_EQ(*exception_value,
2591 "TypeError: Cannot redefine property: defineProperty");
2592}
2593
2594
2595
2596
Steve Blocka7e24c12009-10-30 11:49:00 +00002597
2598v8::Persistent<Value> xValue;
2599
2600
2601static void SetXValue(Local<String> name,
2602 Local<Value> value,
2603 const AccessorInfo& info) {
2604 CHECK_EQ(value, v8_num(4));
2605 CHECK_EQ(info.Data(), v8_str("donut"));
2606 CHECK_EQ(name, v8_str("x"));
2607 CHECK(xValue.IsEmpty());
2608 xValue = v8::Persistent<Value>::New(value);
2609}
2610
2611
2612THREADED_TEST(SimplePropertyWrite) {
2613 v8::HandleScope scope;
2614 Local<ObjectTemplate> templ = ObjectTemplate::New();
2615 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2616 LocalContext context;
2617 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2618 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2619 for (int i = 0; i < 10; i++) {
2620 CHECK(xValue.IsEmpty());
2621 script->Run();
2622 CHECK_EQ(v8_num(4), xValue);
2623 xValue.Dispose();
2624 xValue = v8::Persistent<Value>();
2625 }
2626}
2627
2628
2629static v8::Handle<Value> XPropertyGetter(Local<String> property,
2630 const AccessorInfo& info) {
2631 ApiTestFuzzer::Fuzz();
2632 CHECK(info.Data()->IsUndefined());
2633 return property;
2634}
2635
2636
2637THREADED_TEST(NamedInterceptorPropertyRead) {
2638 v8::HandleScope scope;
2639 Local<ObjectTemplate> templ = ObjectTemplate::New();
2640 templ->SetNamedPropertyHandler(XPropertyGetter);
2641 LocalContext context;
2642 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2643 Local<Script> script = Script::Compile(v8_str("obj.x"));
2644 for (int i = 0; i < 10; i++) {
2645 Local<Value> result = script->Run();
2646 CHECK_EQ(result, v8_str("x"));
2647 }
2648}
2649
2650
Steve Block6ded16b2010-05-10 14:33:55 +01002651THREADED_TEST(NamedInterceptorDictionaryIC) {
2652 v8::HandleScope scope;
2653 Local<ObjectTemplate> templ = ObjectTemplate::New();
2654 templ->SetNamedPropertyHandler(XPropertyGetter);
2655 LocalContext context;
2656 // Create an object with a named interceptor.
2657 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2658 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2659 for (int i = 0; i < 10; i++) {
2660 Local<Value> result = script->Run();
2661 CHECK_EQ(result, v8_str("x"));
2662 }
2663 // Create a slow case object and a function accessing a property in
2664 // that slow case object (with dictionary probing in generated
2665 // code). Then force object with a named interceptor into slow-case,
2666 // pass it to the function, and check that the interceptor is called
2667 // instead of accessing the local property.
2668 Local<Value> result =
2669 CompileRun("function get_x(o) { return o.x; };"
2670 "var obj = { x : 42, y : 0 };"
2671 "delete obj.y;"
2672 "for (var i = 0; i < 10; i++) get_x(obj);"
2673 "interceptor_obj.x = 42;"
2674 "interceptor_obj.y = 10;"
2675 "delete interceptor_obj.y;"
2676 "get_x(interceptor_obj)");
2677 CHECK_EQ(result, v8_str("x"));
2678}
2679
2680
Andrei Popescu402d9372010-02-26 13:31:12 +00002681static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2682 const AccessorInfo& info) {
2683 // Set x on the prototype object and do not handle the get request.
2684 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01002685 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00002686 return v8::Handle<Value>();
2687}
2688
2689
2690// This is a regression test for http://crbug.com/20104. Map
2691// transitions should not interfere with post interceptor lookup.
2692THREADED_TEST(NamedInterceptorMapTransitionRead) {
2693 v8::HandleScope scope;
2694 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2695 Local<v8::ObjectTemplate> instance_template
2696 = function_template->InstanceTemplate();
2697 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2698 LocalContext context;
2699 context->Global()->Set(v8_str("F"), function_template->GetFunction());
2700 // Create an instance of F and introduce a map transition for x.
2701 CompileRun("var o = new F(); o.x = 23;");
2702 // Create an instance of F and invoke the getter. The result should be 23.
2703 Local<Value> result = CompileRun("o = new F(); o.x");
2704 CHECK_EQ(result->Int32Value(), 23);
2705}
2706
2707
Steve Blocka7e24c12009-10-30 11:49:00 +00002708static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2709 const AccessorInfo& info) {
2710 ApiTestFuzzer::Fuzz();
2711 if (index == 37) {
2712 return v8::Handle<Value>(v8_num(625));
2713 }
2714 return v8::Handle<Value>();
2715}
2716
2717
2718static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2719 Local<Value> value,
2720 const AccessorInfo& info) {
2721 ApiTestFuzzer::Fuzz();
2722 if (index == 39) {
2723 return value;
2724 }
2725 return v8::Handle<Value>();
2726}
2727
2728
2729THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2730 v8::HandleScope scope;
2731 Local<ObjectTemplate> templ = ObjectTemplate::New();
2732 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2733 IndexedPropertySetter);
2734 LocalContext context;
2735 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2736 Local<Script> getter_script = Script::Compile(v8_str(
2737 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2738 Local<Script> setter_script = Script::Compile(v8_str(
2739 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2740 "obj[17] = 23;"
2741 "obj.foo;"));
2742 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2743 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2744 "obj[39] = 47;"
2745 "obj.foo;")); // This setter should not run, due to the interceptor.
2746 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2747 "obj[37];"));
2748 Local<Value> result = getter_script->Run();
2749 CHECK_EQ(v8_num(5), result);
2750 result = setter_script->Run();
2751 CHECK_EQ(v8_num(23), result);
2752 result = interceptor_setter_script->Run();
2753 CHECK_EQ(v8_num(23), result);
2754 result = interceptor_getter_script->Run();
2755 CHECK_EQ(v8_num(625), result);
2756}
2757
2758
Leon Clarked91b9f72010-01-27 17:25:45 +00002759static v8::Handle<Value> IdentityIndexedPropertyGetter(
2760 uint32_t index,
2761 const AccessorInfo& info) {
2762 return v8::Integer::New(index);
2763}
2764
2765
2766THREADED_TEST(IndexedInterceptorWithNoSetter) {
2767 v8::HandleScope scope;
2768 Local<ObjectTemplate> templ = ObjectTemplate::New();
2769 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2770
2771 LocalContext context;
2772 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2773
2774 const char* code =
2775 "try {"
2776 " obj[0] = 239;"
2777 " for (var i = 0; i < 100; i++) {"
2778 " var v = obj[0];"
2779 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
2780 " }"
2781 " 'PASSED'"
2782 "} catch(e) {"
2783 " e"
2784 "}";
2785 ExpectString(code, "PASSED");
2786}
2787
2788
Andrei Popescu402d9372010-02-26 13:31:12 +00002789THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
2790 v8::HandleScope scope;
2791 Local<ObjectTemplate> templ = ObjectTemplate::New();
2792 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2793
2794 LocalContext context;
2795 Local<v8::Object> obj = templ->NewInstance();
2796 obj->TurnOnAccessCheck();
2797 context->Global()->Set(v8_str("obj"), obj);
2798
2799 const char* code =
2800 "try {"
2801 " for (var i = 0; i < 100; i++) {"
2802 " var v = obj[0];"
2803 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
2804 " }"
2805 " 'PASSED'"
2806 "} catch(e) {"
2807 " e"
2808 "}";
2809 ExpectString(code, "PASSED");
2810}
2811
2812
2813THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
2814 i::FLAG_allow_natives_syntax = true;
2815 v8::HandleScope scope;
2816 Local<ObjectTemplate> templ = ObjectTemplate::New();
2817 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2818
2819 LocalContext context;
2820 Local<v8::Object> obj = templ->NewInstance();
2821 context->Global()->Set(v8_str("obj"), obj);
2822
2823 const char* code =
2824 "try {"
2825 " for (var i = 0; i < 100; i++) {"
2826 " var expected = i;"
2827 " if (i == 5) {"
2828 " %EnableAccessChecks(obj);"
2829 " expected = undefined;"
2830 " }"
2831 " var v = obj[i];"
2832 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2833 " if (i == 5) %DisableAccessChecks(obj);"
2834 " }"
2835 " 'PASSED'"
2836 "} catch(e) {"
2837 " e"
2838 "}";
2839 ExpectString(code, "PASSED");
2840}
2841
2842
2843THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
2844 v8::HandleScope scope;
2845 Local<ObjectTemplate> templ = ObjectTemplate::New();
2846 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2847
2848 LocalContext context;
2849 Local<v8::Object> obj = templ->NewInstance();
2850 context->Global()->Set(v8_str("obj"), obj);
2851
2852 const char* code =
2853 "try {"
2854 " for (var i = 0; i < 100; i++) {"
2855 " var v = obj[i];"
2856 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2857 " }"
2858 " 'PASSED'"
2859 "} catch(e) {"
2860 " e"
2861 "}";
2862 ExpectString(code, "PASSED");
2863}
2864
2865
2866THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
2867 v8::HandleScope scope;
2868 Local<ObjectTemplate> templ = ObjectTemplate::New();
2869 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2870
2871 LocalContext context;
2872 Local<v8::Object> obj = templ->NewInstance();
2873 context->Global()->Set(v8_str("obj"), obj);
2874
2875 const char* code =
2876 "try {"
2877 " for (var i = 0; i < 100; i++) {"
2878 " var expected = i;"
2879 " if (i == 50) {"
2880 " i = 'foobar';"
2881 " expected = undefined;"
2882 " }"
2883 " var v = obj[i];"
2884 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2885 " }"
2886 " 'PASSED'"
2887 "} catch(e) {"
2888 " e"
2889 "}";
2890 ExpectString(code, "PASSED");
2891}
2892
2893
2894THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
2895 v8::HandleScope scope;
2896 Local<ObjectTemplate> templ = ObjectTemplate::New();
2897 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2898
2899 LocalContext context;
2900 Local<v8::Object> obj = templ->NewInstance();
2901 context->Global()->Set(v8_str("obj"), obj);
2902
2903 const char* code =
2904 "var original = obj;"
2905 "try {"
2906 " for (var i = 0; i < 100; i++) {"
2907 " var expected = i;"
2908 " if (i == 50) {"
2909 " obj = {50: 'foobar'};"
2910 " expected = 'foobar';"
2911 " }"
2912 " var v = obj[i];"
2913 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2914 " if (i == 50) obj = original;"
2915 " }"
2916 " 'PASSED'"
2917 "} catch(e) {"
2918 " e"
2919 "}";
2920 ExpectString(code, "PASSED");
2921}
2922
2923
2924THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
2925 v8::HandleScope scope;
2926 Local<ObjectTemplate> templ = ObjectTemplate::New();
2927 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2928
2929 LocalContext context;
2930 Local<v8::Object> obj = templ->NewInstance();
2931 context->Global()->Set(v8_str("obj"), obj);
2932
2933 const char* code =
2934 "var original = obj;"
2935 "try {"
2936 " for (var i = 0; i < 100; i++) {"
2937 " var expected = i;"
2938 " if (i == 5) {"
2939 " obj = 239;"
2940 " expected = undefined;"
2941 " }"
2942 " var v = obj[i];"
2943 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2944 " if (i == 5) obj = original;"
2945 " }"
2946 " 'PASSED'"
2947 "} catch(e) {"
2948 " e"
2949 "}";
2950 ExpectString(code, "PASSED");
2951}
2952
2953
2954THREADED_TEST(IndexedInterceptorOnProto) {
2955 v8::HandleScope scope;
2956 Local<ObjectTemplate> templ = ObjectTemplate::New();
2957 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2958
2959 LocalContext context;
2960 Local<v8::Object> obj = templ->NewInstance();
2961 context->Global()->Set(v8_str("obj"), obj);
2962
2963 const char* code =
2964 "var o = {__proto__: obj};"
2965 "try {"
2966 " for (var i = 0; i < 100; i++) {"
2967 " var v = o[i];"
2968 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2969 " }"
2970 " 'PASSED'"
2971 "} catch(e) {"
2972 " e"
2973 "}";
2974 ExpectString(code, "PASSED");
2975}
2976
2977
Steve Blocka7e24c12009-10-30 11:49:00 +00002978THREADED_TEST(MultiContexts) {
2979 v8::HandleScope scope;
2980 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2981 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2982
2983 Local<String> password = v8_str("Password");
2984
2985 // Create an environment
2986 LocalContext context0(0, templ);
2987 context0->SetSecurityToken(password);
2988 v8::Handle<v8::Object> global0 = context0->Global();
2989 global0->Set(v8_str("custom"), v8_num(1234));
2990 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2991
2992 // Create an independent environment
2993 LocalContext context1(0, templ);
2994 context1->SetSecurityToken(password);
2995 v8::Handle<v8::Object> global1 = context1->Global();
2996 global1->Set(v8_str("custom"), v8_num(1234));
2997 CHECK_NE(global0, global1);
2998 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2999 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3000
3001 // Now create a new context with the old global
3002 LocalContext context2(0, templ, global1);
3003 context2->SetSecurityToken(password);
3004 v8::Handle<v8::Object> global2 = context2->Global();
3005 CHECK_EQ(global1, global2);
3006 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3007 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3008}
3009
3010
3011THREADED_TEST(FunctionPrototypeAcrossContexts) {
3012 // Make sure that functions created by cloning boilerplates cannot
3013 // communicate through their __proto__ field.
3014
3015 v8::HandleScope scope;
3016
3017 LocalContext env0;
3018 v8::Handle<v8::Object> global0 =
3019 env0->Global();
3020 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003021 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003022 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003023 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003024 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003025 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003026 proto0->Set(v8_str("custom"), v8_num(1234));
3027
3028 LocalContext env1;
3029 v8::Handle<v8::Object> global1 =
3030 env1->Global();
3031 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003032 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003034 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003035 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003036 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003037 CHECK(!proto1->Has(v8_str("custom")));
3038}
3039
3040
3041THREADED_TEST(Regress892105) {
3042 // Make sure that object and array literals created by cloning
3043 // boilerplates cannot communicate through their __proto__
3044 // field. This is rather difficult to check, but we try to add stuff
3045 // to Object.prototype and Array.prototype and create a new
3046 // environment. This should succeed.
3047
3048 v8::HandleScope scope;
3049
3050 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3051 "Array.prototype.arr = 4567;"
3052 "8901");
3053
3054 LocalContext env0;
3055 Local<Script> script0 = Script::Compile(source);
3056 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3057
3058 LocalContext env1;
3059 Local<Script> script1 = Script::Compile(source);
3060 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3061}
3062
3063
Steve Blocka7e24c12009-10-30 11:49:00 +00003064THREADED_TEST(UndetectableObject) {
3065 v8::HandleScope scope;
3066 LocalContext env;
3067
3068 Local<v8::FunctionTemplate> desc =
3069 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3070 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3071
3072 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3073 env->Global()->Set(v8_str("undetectable"), obj);
3074
3075 ExpectString("undetectable.toString()", "[object Object]");
3076 ExpectString("typeof undetectable", "undefined");
3077 ExpectString("typeof(undetectable)", "undefined");
3078 ExpectBoolean("typeof undetectable == 'undefined'", true);
3079 ExpectBoolean("typeof undetectable == 'object'", false);
3080 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3081 ExpectBoolean("!undetectable", true);
3082
3083 ExpectObject("true&&undetectable", obj);
3084 ExpectBoolean("false&&undetectable", false);
3085 ExpectBoolean("true||undetectable", true);
3086 ExpectObject("false||undetectable", obj);
3087
3088 ExpectObject("undetectable&&true", obj);
3089 ExpectObject("undetectable&&false", obj);
3090 ExpectBoolean("undetectable||true", true);
3091 ExpectBoolean("undetectable||false", false);
3092
3093 ExpectBoolean("undetectable==null", true);
3094 ExpectBoolean("null==undetectable", true);
3095 ExpectBoolean("undetectable==undefined", true);
3096 ExpectBoolean("undefined==undetectable", true);
3097 ExpectBoolean("undetectable==undetectable", true);
3098
3099
3100 ExpectBoolean("undetectable===null", false);
3101 ExpectBoolean("null===undetectable", false);
3102 ExpectBoolean("undetectable===undefined", false);
3103 ExpectBoolean("undefined===undetectable", false);
3104 ExpectBoolean("undetectable===undetectable", true);
3105}
3106
3107
3108THREADED_TEST(UndetectableString) {
3109 v8::HandleScope scope;
3110 LocalContext env;
3111
3112 Local<String> obj = String::NewUndetectable("foo");
3113 env->Global()->Set(v8_str("undetectable"), obj);
3114
3115 ExpectString("undetectable", "foo");
3116 ExpectString("typeof undetectable", "undefined");
3117 ExpectString("typeof(undetectable)", "undefined");
3118 ExpectBoolean("typeof undetectable == 'undefined'", true);
3119 ExpectBoolean("typeof undetectable == 'string'", false);
3120 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3121 ExpectBoolean("!undetectable", true);
3122
3123 ExpectObject("true&&undetectable", obj);
3124 ExpectBoolean("false&&undetectable", false);
3125 ExpectBoolean("true||undetectable", true);
3126 ExpectObject("false||undetectable", obj);
3127
3128 ExpectObject("undetectable&&true", obj);
3129 ExpectObject("undetectable&&false", obj);
3130 ExpectBoolean("undetectable||true", true);
3131 ExpectBoolean("undetectable||false", false);
3132
3133 ExpectBoolean("undetectable==null", true);
3134 ExpectBoolean("null==undetectable", true);
3135 ExpectBoolean("undetectable==undefined", true);
3136 ExpectBoolean("undefined==undetectable", true);
3137 ExpectBoolean("undetectable==undetectable", true);
3138
3139
3140 ExpectBoolean("undetectable===null", false);
3141 ExpectBoolean("null===undetectable", false);
3142 ExpectBoolean("undetectable===undefined", false);
3143 ExpectBoolean("undefined===undetectable", false);
3144 ExpectBoolean("undetectable===undetectable", true);
3145}
3146
3147
3148template <typename T> static void USE(T) { }
3149
3150
3151// This test is not intended to be run, just type checked.
3152static void PersistentHandles() {
3153 USE(PersistentHandles);
3154 Local<String> str = v8_str("foo");
3155 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3156 USE(p_str);
3157 Local<Script> scr = Script::Compile(v8_str(""));
3158 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3159 USE(p_scr);
3160 Local<ObjectTemplate> templ = ObjectTemplate::New();
3161 v8::Persistent<ObjectTemplate> p_templ =
3162 v8::Persistent<ObjectTemplate>::New(templ);
3163 USE(p_templ);
3164}
3165
3166
3167static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3168 ApiTestFuzzer::Fuzz();
3169 return v8::Undefined();
3170}
3171
3172
3173THREADED_TEST(GlobalObjectTemplate) {
3174 v8::HandleScope handle_scope;
3175 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3176 global_template->Set(v8_str("JSNI_Log"),
3177 v8::FunctionTemplate::New(HandleLogDelegator));
3178 v8::Persistent<Context> context = Context::New(0, global_template);
3179 Context::Scope context_scope(context);
3180 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3181 context.Dispose();
3182}
3183
3184
3185static const char* kSimpleExtensionSource =
3186 "function Foo() {"
3187 " return 4;"
3188 "}";
3189
3190
3191THREADED_TEST(SimpleExtensions) {
3192 v8::HandleScope handle_scope;
3193 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3194 const char* extension_names[] = { "simpletest" };
3195 v8::ExtensionConfiguration extensions(1, extension_names);
3196 v8::Handle<Context> context = Context::New(&extensions);
3197 Context::Scope lock(context);
3198 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3199 CHECK_EQ(result, v8::Integer::New(4));
3200}
3201
3202
3203static const char* kEvalExtensionSource1 =
3204 "function UseEval1() {"
3205 " var x = 42;"
3206 " return eval('x');"
3207 "}";
3208
3209
3210static const char* kEvalExtensionSource2 =
3211 "(function() {"
3212 " var x = 42;"
3213 " function e() {"
3214 " return eval('x');"
3215 " }"
3216 " this.UseEval2 = e;"
3217 "})()";
3218
3219
3220THREADED_TEST(UseEvalFromExtension) {
3221 v8::HandleScope handle_scope;
3222 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3223 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3224 const char* extension_names[] = { "evaltest1", "evaltest2" };
3225 v8::ExtensionConfiguration extensions(2, extension_names);
3226 v8::Handle<Context> context = Context::New(&extensions);
3227 Context::Scope lock(context);
3228 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3229 CHECK_EQ(result, v8::Integer::New(42));
3230 result = Script::Compile(v8_str("UseEval2()"))->Run();
3231 CHECK_EQ(result, v8::Integer::New(42));
3232}
3233
3234
3235static const char* kWithExtensionSource1 =
3236 "function UseWith1() {"
3237 " var x = 42;"
3238 " with({x:87}) { return x; }"
3239 "}";
3240
3241
3242
3243static const char* kWithExtensionSource2 =
3244 "(function() {"
3245 " var x = 42;"
3246 " function e() {"
3247 " with ({x:87}) { return x; }"
3248 " }"
3249 " this.UseWith2 = e;"
3250 "})()";
3251
3252
3253THREADED_TEST(UseWithFromExtension) {
3254 v8::HandleScope handle_scope;
3255 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3256 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3257 const char* extension_names[] = { "withtest1", "withtest2" };
3258 v8::ExtensionConfiguration extensions(2, extension_names);
3259 v8::Handle<Context> context = Context::New(&extensions);
3260 Context::Scope lock(context);
3261 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3262 CHECK_EQ(result, v8::Integer::New(87));
3263 result = Script::Compile(v8_str("UseWith2()"))->Run();
3264 CHECK_EQ(result, v8::Integer::New(87));
3265}
3266
3267
3268THREADED_TEST(AutoExtensions) {
3269 v8::HandleScope handle_scope;
3270 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3271 extension->set_auto_enable(true);
3272 v8::RegisterExtension(extension);
3273 v8::Handle<Context> context = Context::New();
3274 Context::Scope lock(context);
3275 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3276 CHECK_EQ(result, v8::Integer::New(4));
3277}
3278
3279
Steve Blockd0582a62009-12-15 09:54:21 +00003280static const char* kSyntaxErrorInExtensionSource =
3281 "[";
3282
3283
3284// Test that a syntax error in an extension does not cause a fatal
3285// error but results in an empty context.
3286THREADED_TEST(SyntaxErrorExtensions) {
3287 v8::HandleScope handle_scope;
3288 v8::RegisterExtension(new Extension("syntaxerror",
3289 kSyntaxErrorInExtensionSource));
3290 const char* extension_names[] = { "syntaxerror" };
3291 v8::ExtensionConfiguration extensions(1, extension_names);
3292 v8::Handle<Context> context = Context::New(&extensions);
3293 CHECK(context.IsEmpty());
3294}
3295
3296
3297static const char* kExceptionInExtensionSource =
3298 "throw 42";
3299
3300
3301// Test that an exception when installing an extension does not cause
3302// a fatal error but results in an empty context.
3303THREADED_TEST(ExceptionExtensions) {
3304 v8::HandleScope handle_scope;
3305 v8::RegisterExtension(new Extension("exception",
3306 kExceptionInExtensionSource));
3307 const char* extension_names[] = { "exception" };
3308 v8::ExtensionConfiguration extensions(1, extension_names);
3309 v8::Handle<Context> context = Context::New(&extensions);
3310 CHECK(context.IsEmpty());
3311}
3312
3313
Steve Blocka7e24c12009-10-30 11:49:00 +00003314static void CheckDependencies(const char* name, const char* expected) {
3315 v8::HandleScope handle_scope;
3316 v8::ExtensionConfiguration config(1, &name);
3317 LocalContext context(&config);
3318 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3319}
3320
3321
3322/*
3323 * Configuration:
3324 *
3325 * /-- B <--\
3326 * A <- -- D <-- E
3327 * \-- C <--/
3328 */
3329THREADED_TEST(ExtensionDependency) {
3330 static const char* kEDeps[] = { "D" };
3331 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3332 static const char* kDDeps[] = { "B", "C" };
3333 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3334 static const char* kBCDeps[] = { "A" };
3335 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3336 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3337 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3338 CheckDependencies("A", "undefinedA");
3339 CheckDependencies("B", "undefinedAB");
3340 CheckDependencies("C", "undefinedAC");
3341 CheckDependencies("D", "undefinedABCD");
3342 CheckDependencies("E", "undefinedABCDE");
3343 v8::HandleScope handle_scope;
3344 static const char* exts[2] = { "C", "E" };
3345 v8::ExtensionConfiguration config(2, exts);
3346 LocalContext context(&config);
3347 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3348}
3349
3350
3351static const char* kExtensionTestScript =
3352 "native function A();"
3353 "native function B();"
3354 "native function C();"
3355 "function Foo(i) {"
3356 " if (i == 0) return A();"
3357 " if (i == 1) return B();"
3358 " if (i == 2) return C();"
3359 "}";
3360
3361
3362static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3363 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00003364 if (args.IsConstructCall()) {
3365 args.This()->Set(v8_str("data"), args.Data());
3366 return v8::Null();
3367 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003368 return args.Data();
3369}
3370
3371
3372class FunctionExtension : public Extension {
3373 public:
3374 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3375 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3376 v8::Handle<String> name);
3377};
3378
3379
3380static int lookup_count = 0;
3381v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3382 v8::Handle<String> name) {
3383 lookup_count++;
3384 if (name->Equals(v8_str("A"))) {
3385 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3386 } else if (name->Equals(v8_str("B"))) {
3387 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3388 } else if (name->Equals(v8_str("C"))) {
3389 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3390 } else {
3391 return v8::Handle<v8::FunctionTemplate>();
3392 }
3393}
3394
3395
3396THREADED_TEST(FunctionLookup) {
3397 v8::RegisterExtension(new FunctionExtension());
3398 v8::HandleScope handle_scope;
3399 static const char* exts[1] = { "functiontest" };
3400 v8::ExtensionConfiguration config(1, exts);
3401 LocalContext context(&config);
3402 CHECK_EQ(3, lookup_count);
3403 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3404 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3405 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3406}
3407
3408
Leon Clarkee46be812010-01-19 14:06:41 +00003409THREADED_TEST(NativeFunctionConstructCall) {
3410 v8::RegisterExtension(new FunctionExtension());
3411 v8::HandleScope handle_scope;
3412 static const char* exts[1] = { "functiontest" };
3413 v8::ExtensionConfiguration config(1, exts);
3414 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00003415 for (int i = 0; i < 10; i++) {
3416 // Run a few times to ensure that allocation of objects doesn't
3417 // change behavior of a constructor function.
3418 CHECK_EQ(v8::Integer::New(8),
3419 Script::Compile(v8_str("(new A()).data"))->Run());
3420 CHECK_EQ(v8::Integer::New(7),
3421 Script::Compile(v8_str("(new B()).data"))->Run());
3422 CHECK_EQ(v8::Integer::New(6),
3423 Script::Compile(v8_str("(new C()).data"))->Run());
3424 }
Leon Clarkee46be812010-01-19 14:06:41 +00003425}
3426
3427
Steve Blocka7e24c12009-10-30 11:49:00 +00003428static const char* last_location;
3429static const char* last_message;
3430void StoringErrorCallback(const char* location, const char* message) {
3431 if (last_location == NULL) {
3432 last_location = location;
3433 last_message = message;
3434 }
3435}
3436
3437
3438// ErrorReporting creates a circular extensions configuration and
3439// tests that the fatal error handler gets called. This renders V8
3440// unusable and therefore this test cannot be run in parallel.
3441TEST(ErrorReporting) {
3442 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3443 static const char* aDeps[] = { "B" };
3444 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3445 static const char* bDeps[] = { "A" };
3446 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3447 last_location = NULL;
3448 v8::ExtensionConfiguration config(1, bDeps);
3449 v8::Handle<Context> context = Context::New(&config);
3450 CHECK(context.IsEmpty());
3451 CHECK_NE(last_location, NULL);
3452}
3453
3454
3455static const char* js_code_causing_huge_string_flattening =
3456 "var str = 'X';"
3457 "for (var i = 0; i < 30; i++) {"
3458 " str = str + str;"
3459 "}"
3460 "str.match(/X/);";
3461
3462
3463void OOMCallback(const char* location, const char* message) {
3464 exit(0);
3465}
3466
3467
3468TEST(RegexpOutOfMemory) {
3469 // Execute a script that causes out of memory when flattening a string.
3470 v8::HandleScope scope;
3471 v8::V8::SetFatalErrorHandler(OOMCallback);
3472 LocalContext context;
3473 Local<Script> script =
3474 Script::Compile(String::New(js_code_causing_huge_string_flattening));
3475 last_location = NULL;
3476 Local<Value> result = script->Run();
3477
3478 CHECK(false); // Should not return.
3479}
3480
3481
3482static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3483 v8::Handle<Value> data) {
3484 CHECK_EQ(v8::Undefined(), data);
3485 CHECK(message->GetScriptResourceName()->IsUndefined());
3486 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3487 message->GetLineNumber();
3488 message->GetSourceLine();
3489}
3490
3491
3492THREADED_TEST(ErrorWithMissingScriptInfo) {
3493 v8::HandleScope scope;
3494 LocalContext context;
3495 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3496 Script::Compile(v8_str("throw Error()"))->Run();
3497 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3498}
3499
3500
3501int global_index = 0;
3502
3503class Snorkel {
3504 public:
3505 Snorkel() { index_ = global_index++; }
3506 int index_;
3507};
3508
3509class Whammy {
3510 public:
3511 Whammy() {
3512 cursor_ = 0;
3513 }
3514 ~Whammy() {
3515 script_.Dispose();
3516 }
3517 v8::Handle<Script> getScript() {
3518 if (script_.IsEmpty())
3519 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3520 return Local<Script>(*script_);
3521 }
3522
3523 public:
3524 static const int kObjectCount = 256;
3525 int cursor_;
3526 v8::Persistent<v8::Object> objects_[kObjectCount];
3527 v8::Persistent<Script> script_;
3528};
3529
3530static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3531 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3532 delete snorkel;
3533 obj.ClearWeak();
3534}
3535
3536v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3537 const AccessorInfo& info) {
3538 Whammy* whammy =
3539 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3540
3541 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3542
3543 v8::Handle<v8::Object> obj = v8::Object::New();
3544 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3545 if (!prev.IsEmpty()) {
3546 prev->Set(v8_str("next"), obj);
3547 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3548 whammy->objects_[whammy->cursor_].Clear();
3549 }
3550 whammy->objects_[whammy->cursor_] = global;
3551 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3552 return whammy->getScript()->Run();
3553}
3554
3555THREADED_TEST(WeakReference) {
3556 v8::HandleScope handle_scope;
3557 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3558 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3559 0, 0, 0, 0,
3560 v8::External::New(new Whammy()));
3561 const char* extension_list[] = { "v8/gc" };
3562 v8::ExtensionConfiguration extensions(1, extension_list);
3563 v8::Persistent<Context> context = Context::New(&extensions);
3564 Context::Scope context_scope(context);
3565
3566 v8::Handle<v8::Object> interceptor = templ->NewInstance();
3567 context->Global()->Set(v8_str("whammy"), interceptor);
3568 const char* code =
3569 "var last;"
3570 "for (var i = 0; i < 10000; i++) {"
3571 " var obj = whammy.length;"
3572 " if (last) last.next = obj;"
3573 " last = obj;"
3574 "}"
3575 "gc();"
3576 "4";
3577 v8::Handle<Value> result = CompileRun(code);
3578 CHECK_EQ(4.0, result->NumberValue());
3579
3580 context.Dispose();
3581}
3582
3583
Steve Blockd0582a62009-12-15 09:54:21 +00003584static bool in_scavenge = false;
3585static int last = -1;
3586
3587static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3588 CHECK_EQ(-1, last);
3589 last = 0;
3590 obj.Dispose();
3591 obj.Clear();
3592 in_scavenge = true;
3593 i::Heap::PerformScavenge();
3594 in_scavenge = false;
3595 *(reinterpret_cast<bool*>(data)) = true;
3596}
3597
3598static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3599 void* data) {
3600 CHECK_EQ(0, last);
3601 last = 1;
3602 *(reinterpret_cast<bool*>(data)) = in_scavenge;
3603 obj.Dispose();
3604 obj.Clear();
3605}
3606
3607THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3608 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3609 // Calling callbacks from scavenges is unsafe as objects held by those
3610 // handlers might have become strongly reachable, but scavenge doesn't
3611 // check that.
3612 v8::Persistent<Context> context = Context::New();
3613 Context::Scope context_scope(context);
3614
3615 v8::Persistent<v8::Object> object_a;
3616 v8::Persistent<v8::Object> object_b;
3617
3618 {
3619 v8::HandleScope handle_scope;
3620 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3621 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3622 }
3623
3624 bool object_a_disposed = false;
3625 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3626 bool released_in_scavenge = false;
3627 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3628
3629 while (!object_a_disposed) {
3630 i::Heap::CollectAllGarbage(false);
3631 }
3632 CHECK(!released_in_scavenge);
3633}
3634
3635
Steve Blocka7e24c12009-10-30 11:49:00 +00003636v8::Handle<Function> args_fun;
3637
3638
3639static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3640 ApiTestFuzzer::Fuzz();
3641 CHECK_EQ(args_fun, args.Callee());
3642 CHECK_EQ(3, args.Length());
3643 CHECK_EQ(v8::Integer::New(1), args[0]);
3644 CHECK_EQ(v8::Integer::New(2), args[1]);
3645 CHECK_EQ(v8::Integer::New(3), args[2]);
3646 CHECK_EQ(v8::Undefined(), args[3]);
3647 v8::HandleScope scope;
3648 i::Heap::CollectAllGarbage(false);
3649 return v8::Undefined();
3650}
3651
3652
3653THREADED_TEST(Arguments) {
3654 v8::HandleScope scope;
3655 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3656 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3657 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01003658 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003659 v8_compile("f(1, 2, 3)")->Run();
3660}
3661
3662
Steve Blocka7e24c12009-10-30 11:49:00 +00003663static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3664 const AccessorInfo&) {
3665 return v8::Handle<Value>();
3666}
3667
3668
3669static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3670 const AccessorInfo&) {
3671 return v8::Handle<Value>();
3672}
3673
3674
3675static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3676 const AccessorInfo&) {
3677 if (!name->Equals(v8_str("foo"))) {
3678 return v8::Handle<v8::Boolean>(); // not intercepted
3679 }
3680
3681 return v8::False(); // intercepted, and don't delete the property
3682}
3683
3684
3685static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3686 if (index != 2) {
3687 return v8::Handle<v8::Boolean>(); // not intercepted
3688 }
3689
3690 return v8::False(); // intercepted, and don't delete the property
3691}
3692
3693
3694THREADED_TEST(Deleter) {
3695 v8::HandleScope scope;
3696 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3697 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3698 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3699 LocalContext context;
3700 context->Global()->Set(v8_str("k"), obj->NewInstance());
3701 CompileRun(
3702 "k.foo = 'foo';"
3703 "k.bar = 'bar';"
3704 "k[2] = 2;"
3705 "k[4] = 4;");
3706 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3707 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3708
3709 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3710 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3711
3712 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3713 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3714
3715 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3716 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3717}
3718
3719
3720static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3721 ApiTestFuzzer::Fuzz();
3722 if (name->Equals(v8_str("foo")) ||
3723 name->Equals(v8_str("bar")) ||
3724 name->Equals(v8_str("baz"))) {
3725 return v8::Undefined();
3726 }
3727 return v8::Handle<Value>();
3728}
3729
3730
3731static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3732 ApiTestFuzzer::Fuzz();
3733 if (index == 0 || index == 1) return v8::Undefined();
3734 return v8::Handle<Value>();
3735}
3736
3737
3738static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3739 ApiTestFuzzer::Fuzz();
3740 v8::Handle<v8::Array> result = v8::Array::New(3);
3741 result->Set(v8::Integer::New(0), v8_str("foo"));
3742 result->Set(v8::Integer::New(1), v8_str("bar"));
3743 result->Set(v8::Integer::New(2), v8_str("baz"));
3744 return result;
3745}
3746
3747
3748static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3749 ApiTestFuzzer::Fuzz();
3750 v8::Handle<v8::Array> result = v8::Array::New(2);
3751 result->Set(v8::Integer::New(0), v8_str("0"));
3752 result->Set(v8::Integer::New(1), v8_str("1"));
3753 return result;
3754}
3755
3756
3757THREADED_TEST(Enumerators) {
3758 v8::HandleScope scope;
3759 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3760 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3761 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3762 LocalContext context;
3763 context->Global()->Set(v8_str("k"), obj->NewInstance());
3764 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3765 "k[10] = 0;"
3766 "k.a = 0;"
3767 "k[5] = 0;"
3768 "k.b = 0;"
3769 "k[4294967295] = 0;"
3770 "k.c = 0;"
3771 "k[4294967296] = 0;"
3772 "k.d = 0;"
3773 "k[140000] = 0;"
3774 "k.e = 0;"
3775 "k[30000000000] = 0;"
3776 "k.f = 0;"
3777 "var result = [];"
3778 "for (var prop in k) {"
3779 " result.push(prop);"
3780 "}"
3781 "result"));
3782 // Check that we get all the property names returned including the
3783 // ones from the enumerators in the right order: indexed properties
3784 // in numerical order, indexed interceptor properties, named
3785 // properties in insertion order, named interceptor properties.
3786 // This order is not mandated by the spec, so this test is just
3787 // documenting our behavior.
3788 CHECK_EQ(17, result->Length());
3789 // Indexed properties in numerical order.
3790 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3791 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3792 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3793 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3794 // Indexed interceptor properties in the order they are returned
3795 // from the enumerator interceptor.
3796 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3797 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3798 // Named properties in insertion order.
3799 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3800 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3801 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3802 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3803 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3804 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3805 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3806 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3807 // Named interceptor properties.
3808 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3809 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3810 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
3811}
3812
3813
3814int p_getter_count;
3815int p_getter_count2;
3816
3817
3818static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3819 ApiTestFuzzer::Fuzz();
3820 p_getter_count++;
3821 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3822 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3823 if (name->Equals(v8_str("p1"))) {
3824 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3825 } else if (name->Equals(v8_str("p2"))) {
3826 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3827 } else if (name->Equals(v8_str("p3"))) {
3828 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3829 } else if (name->Equals(v8_str("p4"))) {
3830 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3831 }
3832 return v8::Undefined();
3833}
3834
3835
3836static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3837 ApiTestFuzzer::Fuzz();
3838 LocalContext context;
3839 context->Global()->Set(v8_str("o1"), obj->NewInstance());
3840 CompileRun(
3841 "o1.__proto__ = { };"
3842 "var o2 = { __proto__: o1 };"
3843 "var o3 = { __proto__: o2 };"
3844 "var o4 = { __proto__: o3 };"
3845 "for (var i = 0; i < 10; i++) o4.p4;"
3846 "for (var i = 0; i < 10; i++) o3.p3;"
3847 "for (var i = 0; i < 10; i++) o2.p2;"
3848 "for (var i = 0; i < 10; i++) o1.p1;");
3849}
3850
3851
3852static v8::Handle<Value> PGetter2(Local<String> name,
3853 const AccessorInfo& info) {
3854 ApiTestFuzzer::Fuzz();
3855 p_getter_count2++;
3856 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3857 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3858 if (name->Equals(v8_str("p1"))) {
3859 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3860 } else if (name->Equals(v8_str("p2"))) {
3861 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3862 } else if (name->Equals(v8_str("p3"))) {
3863 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3864 } else if (name->Equals(v8_str("p4"))) {
3865 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3866 }
3867 return v8::Undefined();
3868}
3869
3870
3871THREADED_TEST(GetterHolders) {
3872 v8::HandleScope scope;
3873 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3874 obj->SetAccessor(v8_str("p1"), PGetter);
3875 obj->SetAccessor(v8_str("p2"), PGetter);
3876 obj->SetAccessor(v8_str("p3"), PGetter);
3877 obj->SetAccessor(v8_str("p4"), PGetter);
3878 p_getter_count = 0;
3879 RunHolderTest(obj);
3880 CHECK_EQ(40, p_getter_count);
3881}
3882
3883
3884THREADED_TEST(PreInterceptorHolders) {
3885 v8::HandleScope scope;
3886 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3887 obj->SetNamedPropertyHandler(PGetter2);
3888 p_getter_count2 = 0;
3889 RunHolderTest(obj);
3890 CHECK_EQ(40, p_getter_count2);
3891}
3892
3893
3894THREADED_TEST(ObjectInstantiation) {
3895 v8::HandleScope scope;
3896 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3897 templ->SetAccessor(v8_str("t"), PGetter2);
3898 LocalContext context;
3899 context->Global()->Set(v8_str("o"), templ->NewInstance());
3900 for (int i = 0; i < 100; i++) {
3901 v8::HandleScope inner_scope;
3902 v8::Handle<v8::Object> obj = templ->NewInstance();
3903 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3904 context->Global()->Set(v8_str("o2"), obj);
3905 v8::Handle<Value> value =
3906 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3907 CHECK_EQ(v8::True(), value);
3908 context->Global()->Set(v8_str("o"), obj);
3909 }
3910}
3911
3912
3913THREADED_TEST(StringWrite) {
3914 v8::HandleScope scope;
3915 v8::Handle<String> str = v8_str("abcde");
3916
3917 char buf[100];
3918 int len;
3919
3920 memset(buf, 0x1, sizeof(buf));
3921 len = str->WriteAscii(buf);
3922 CHECK_EQ(len, 5);
3923 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3924
3925 memset(buf, 0x1, sizeof(buf));
3926 len = str->WriteAscii(buf, 0, 4);
3927 CHECK_EQ(len, 4);
3928 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3929
3930 memset(buf, 0x1, sizeof(buf));
3931 len = str->WriteAscii(buf, 0, 5);
3932 CHECK_EQ(len, 5);
3933 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3934
3935 memset(buf, 0x1, sizeof(buf));
3936 len = str->WriteAscii(buf, 0, 6);
3937 CHECK_EQ(len, 5);
3938 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3939
3940 memset(buf, 0x1, sizeof(buf));
3941 len = str->WriteAscii(buf, 4, -1);
3942 CHECK_EQ(len, 1);
3943 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3944
3945 memset(buf, 0x1, sizeof(buf));
3946 len = str->WriteAscii(buf, 4, 6);
3947 CHECK_EQ(len, 1);
3948 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3949
3950 memset(buf, 0x1, sizeof(buf));
3951 len = str->WriteAscii(buf, 4, 1);
3952 CHECK_EQ(len, 1);
3953 CHECK_EQ(strncmp("e\1", buf, 2), 0);
3954}
3955
3956
3957THREADED_TEST(ToArrayIndex) {
3958 v8::HandleScope scope;
3959 LocalContext context;
3960
3961 v8::Handle<String> str = v8_str("42");
3962 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3963 CHECK(!index.IsEmpty());
3964 CHECK_EQ(42.0, index->Uint32Value());
3965 str = v8_str("42asdf");
3966 index = str->ToArrayIndex();
3967 CHECK(index.IsEmpty());
3968 str = v8_str("-42");
3969 index = str->ToArrayIndex();
3970 CHECK(index.IsEmpty());
3971 str = v8_str("4294967295");
3972 index = str->ToArrayIndex();
3973 CHECK(!index.IsEmpty());
3974 CHECK_EQ(4294967295.0, index->Uint32Value());
3975 v8::Handle<v8::Number> num = v8::Number::New(1);
3976 index = num->ToArrayIndex();
3977 CHECK(!index.IsEmpty());
3978 CHECK_EQ(1.0, index->Uint32Value());
3979 num = v8::Number::New(-1);
3980 index = num->ToArrayIndex();
3981 CHECK(index.IsEmpty());
3982 v8::Handle<v8::Object> obj = v8::Object::New();
3983 index = obj->ToArrayIndex();
3984 CHECK(index.IsEmpty());
3985}
3986
3987
3988THREADED_TEST(ErrorConstruction) {
3989 v8::HandleScope scope;
3990 LocalContext context;
3991
3992 v8::Handle<String> foo = v8_str("foo");
3993 v8::Handle<String> message = v8_str("message");
3994 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3995 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01003996 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
3997 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00003998 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3999 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004000 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004001 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4002 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004003 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004004 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4005 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004006 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004007 v8::Handle<Value> error = v8::Exception::Error(foo);
4008 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004009 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004010}
4011
4012
4013static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4014 ApiTestFuzzer::Fuzz();
4015 return v8_num(10);
4016}
4017
4018
4019static void YSetter(Local<String> name,
4020 Local<Value> value,
4021 const AccessorInfo& info) {
4022 if (info.This()->Has(name)) {
4023 info.This()->Delete(name);
4024 }
4025 info.This()->Set(name, value);
4026}
4027
4028
4029THREADED_TEST(DeleteAccessor) {
4030 v8::HandleScope scope;
4031 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4032 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4033 LocalContext context;
4034 v8::Handle<v8::Object> holder = obj->NewInstance();
4035 context->Global()->Set(v8_str("holder"), holder);
4036 v8::Handle<Value> result = CompileRun(
4037 "holder.y = 11; holder.y = 12; holder.y");
4038 CHECK_EQ(12, result->Uint32Value());
4039}
4040
4041
4042THREADED_TEST(TypeSwitch) {
4043 v8::HandleScope scope;
4044 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4045 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4046 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4047 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4048 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4049 LocalContext context;
4050 v8::Handle<v8::Object> obj0 = v8::Object::New();
4051 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4052 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4053 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4054 for (int i = 0; i < 10; i++) {
4055 CHECK_EQ(0, type_switch->match(obj0));
4056 CHECK_EQ(1, type_switch->match(obj1));
4057 CHECK_EQ(2, type_switch->match(obj2));
4058 CHECK_EQ(3, type_switch->match(obj3));
4059 CHECK_EQ(3, type_switch->match(obj3));
4060 CHECK_EQ(2, type_switch->match(obj2));
4061 CHECK_EQ(1, type_switch->match(obj1));
4062 CHECK_EQ(0, type_switch->match(obj0));
4063 }
4064}
4065
4066
4067// For use within the TestSecurityHandler() test.
4068static bool g_security_callback_result = false;
4069static bool NamedSecurityTestCallback(Local<v8::Object> global,
4070 Local<Value> name,
4071 v8::AccessType type,
4072 Local<Value> data) {
4073 // Always allow read access.
4074 if (type == v8::ACCESS_GET)
4075 return true;
4076
4077 // Sometimes allow other access.
4078 return g_security_callback_result;
4079}
4080
4081
4082static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4083 uint32_t key,
4084 v8::AccessType type,
4085 Local<Value> data) {
4086 // Always allow read access.
4087 if (type == v8::ACCESS_GET)
4088 return true;
4089
4090 // Sometimes allow other access.
4091 return g_security_callback_result;
4092}
4093
4094
4095static int trouble_nesting = 0;
4096static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4097 ApiTestFuzzer::Fuzz();
4098 trouble_nesting++;
4099
4100 // Call a JS function that throws an uncaught exception.
4101 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4102 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4103 arg_this->Get(v8_str("trouble_callee")) :
4104 arg_this->Get(v8_str("trouble_caller"));
4105 CHECK(trouble_callee->IsFunction());
4106 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4107}
4108
4109
4110static int report_count = 0;
4111static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4112 v8::Handle<Value>) {
4113 report_count++;
4114}
4115
4116
4117// Counts uncaught exceptions, but other tests running in parallel
4118// also have uncaught exceptions.
4119TEST(ApiUncaughtException) {
4120 report_count = 0;
4121 v8::HandleScope scope;
4122 LocalContext env;
4123 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4124
4125 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4126 v8::Local<v8::Object> global = env->Global();
4127 global->Set(v8_str("trouble"), fun->GetFunction());
4128
4129 Script::Compile(v8_str("function trouble_callee() {"
4130 " var x = null;"
4131 " return x.foo;"
4132 "};"
4133 "function trouble_caller() {"
4134 " trouble();"
4135 "};"))->Run();
4136 Local<Value> trouble = global->Get(v8_str("trouble"));
4137 CHECK(trouble->IsFunction());
4138 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4139 CHECK(trouble_callee->IsFunction());
4140 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4141 CHECK(trouble_caller->IsFunction());
4142 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4143 CHECK_EQ(1, report_count);
4144 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4145}
4146
Leon Clarke4515c472010-02-03 11:58:03 +00004147static const char* script_resource_name = "ExceptionInNativeScript.js";
4148static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4149 v8::Handle<Value>) {
4150 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4151 CHECK(!name_val.IsEmpty() && name_val->IsString());
4152 v8::String::AsciiValue name(message->GetScriptResourceName());
4153 CHECK_EQ(script_resource_name, *name);
4154 CHECK_EQ(3, message->GetLineNumber());
4155 v8::String::AsciiValue source_line(message->GetSourceLine());
4156 CHECK_EQ(" new o.foo();", *source_line);
4157}
4158
4159TEST(ExceptionInNativeScript) {
4160 v8::HandleScope scope;
4161 LocalContext env;
4162 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4163
4164 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4165 v8::Local<v8::Object> global = env->Global();
4166 global->Set(v8_str("trouble"), fun->GetFunction());
4167
4168 Script::Compile(v8_str("function trouble() {\n"
4169 " var o = {};\n"
4170 " new o.foo();\n"
4171 "};"), v8::String::New(script_resource_name))->Run();
4172 Local<Value> trouble = global->Get(v8_str("trouble"));
4173 CHECK(trouble->IsFunction());
4174 Function::Cast(*trouble)->Call(global, 0, NULL);
4175 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4176}
4177
Steve Blocka7e24c12009-10-30 11:49:00 +00004178
4179TEST(CompilationErrorUsingTryCatchHandler) {
4180 v8::HandleScope scope;
4181 LocalContext env;
4182 v8::TryCatch try_catch;
4183 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4184 CHECK_NE(NULL, *try_catch.Exception());
4185 CHECK(try_catch.HasCaught());
4186}
4187
4188
4189TEST(TryCatchFinallyUsingTryCatchHandler) {
4190 v8::HandleScope scope;
4191 LocalContext env;
4192 v8::TryCatch try_catch;
4193 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4194 CHECK(!try_catch.HasCaught());
4195 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4196 CHECK(try_catch.HasCaught());
4197 try_catch.Reset();
4198 Script::Compile(v8_str("(function() {"
4199 "try { throw ''; } finally { return; }"
4200 "})()"))->Run();
4201 CHECK(!try_catch.HasCaught());
4202 Script::Compile(v8_str("(function()"
4203 " { try { throw ''; } finally { throw 0; }"
4204 "})()"))->Run();
4205 CHECK(try_catch.HasCaught());
4206}
4207
4208
4209// SecurityHandler can't be run twice
4210TEST(SecurityHandler) {
4211 v8::HandleScope scope0;
4212 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4213 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4214 IndexedSecurityTestCallback);
4215 // Create an environment
4216 v8::Persistent<Context> context0 =
4217 Context::New(NULL, global_template);
4218 context0->Enter();
4219
4220 v8::Handle<v8::Object> global0 = context0->Global();
4221 v8::Handle<Script> script0 = v8_compile("foo = 111");
4222 script0->Run();
4223 global0->Set(v8_str("0"), v8_num(999));
4224 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4225 CHECK_EQ(111, foo0->Int32Value());
4226 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4227 CHECK_EQ(999, z0->Int32Value());
4228
4229 // Create another environment, should fail security checks.
4230 v8::HandleScope scope1;
4231
4232 v8::Persistent<Context> context1 =
4233 Context::New(NULL, global_template);
4234 context1->Enter();
4235
4236 v8::Handle<v8::Object> global1 = context1->Global();
4237 global1->Set(v8_str("othercontext"), global0);
4238 // This set will fail the security check.
4239 v8::Handle<Script> script1 =
4240 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4241 script1->Run();
4242 // This read will pass the security check.
4243 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4244 CHECK_EQ(111, foo1->Int32Value());
4245 // This read will pass the security check.
4246 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4247 CHECK_EQ(999, z1->Int32Value());
4248
4249 // Create another environment, should pass security checks.
4250 { g_security_callback_result = true; // allow security handler to pass.
4251 v8::HandleScope scope2;
4252 LocalContext context2;
4253 v8::Handle<v8::Object> global2 = context2->Global();
4254 global2->Set(v8_str("othercontext"), global0);
4255 v8::Handle<Script> script2 =
4256 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4257 script2->Run();
4258 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4259 CHECK_EQ(333, foo2->Int32Value());
4260 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4261 CHECK_EQ(888, z2->Int32Value());
4262 }
4263
4264 context1->Exit();
4265 context1.Dispose();
4266
4267 context0->Exit();
4268 context0.Dispose();
4269}
4270
4271
4272THREADED_TEST(SecurityChecks) {
4273 v8::HandleScope handle_scope;
4274 LocalContext env1;
4275 v8::Persistent<Context> env2 = Context::New();
4276
4277 Local<Value> foo = v8_str("foo");
4278 Local<Value> bar = v8_str("bar");
4279
4280 // Set to the same domain.
4281 env1->SetSecurityToken(foo);
4282
4283 // Create a function in env1.
4284 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4285 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4286 CHECK(spy->IsFunction());
4287
4288 // Create another function accessing global objects.
4289 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4290 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4291 CHECK(spy2->IsFunction());
4292
4293 // Switch to env2 in the same domain and invoke spy on env2.
4294 {
4295 env2->SetSecurityToken(foo);
4296 // Enter env2
4297 Context::Scope scope_env2(env2);
4298 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4299 CHECK(result->IsFunction());
4300 }
4301
4302 {
4303 env2->SetSecurityToken(bar);
4304 Context::Scope scope_env2(env2);
4305
4306 // Call cross_domain_call, it should throw an exception
4307 v8::TryCatch try_catch;
4308 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4309 CHECK(try_catch.HasCaught());
4310 }
4311
4312 env2.Dispose();
4313}
4314
4315
4316// Regression test case for issue 1183439.
4317THREADED_TEST(SecurityChecksForPrototypeChain) {
4318 v8::HandleScope scope;
4319 LocalContext current;
4320 v8::Persistent<Context> other = Context::New();
4321
4322 // Change context to be able to get to the Object function in the
4323 // other context without hitting the security checks.
4324 v8::Local<Value> other_object;
4325 { Context::Scope scope(other);
4326 other_object = other->Global()->Get(v8_str("Object"));
4327 other->Global()->Set(v8_num(42), v8_num(87));
4328 }
4329
4330 current->Global()->Set(v8_str("other"), other->Global());
4331 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4332
4333 // Make sure the security check fails here and we get an undefined
4334 // result instead of getting the Object function. Repeat in a loop
4335 // to make sure to exercise the IC code.
4336 v8::Local<Script> access_other0 = v8_compile("other.Object");
4337 v8::Local<Script> access_other1 = v8_compile("other[42]");
4338 for (int i = 0; i < 5; i++) {
4339 CHECK(!access_other0->Run()->Equals(other_object));
4340 CHECK(access_other0->Run()->IsUndefined());
4341 CHECK(!access_other1->Run()->Equals(v8_num(87)));
4342 CHECK(access_other1->Run()->IsUndefined());
4343 }
4344
4345 // Create an object that has 'other' in its prototype chain and make
4346 // sure we cannot access the Object function indirectly through
4347 // that. Repeat in a loop to make sure to exercise the IC code.
4348 v8_compile("function F() { };"
4349 "F.prototype = other;"
4350 "var f = new F();")->Run();
4351 v8::Local<Script> access_f0 = v8_compile("f.Object");
4352 v8::Local<Script> access_f1 = v8_compile("f[42]");
4353 for (int j = 0; j < 5; j++) {
4354 CHECK(!access_f0->Run()->Equals(other_object));
4355 CHECK(access_f0->Run()->IsUndefined());
4356 CHECK(!access_f1->Run()->Equals(v8_num(87)));
4357 CHECK(access_f1->Run()->IsUndefined());
4358 }
4359
4360 // Now it gets hairy: Set the prototype for the other global object
4361 // to be the current global object. The prototype chain for 'f' now
4362 // goes through 'other' but ends up in the current global object.
4363 { Context::Scope scope(other);
4364 other->Global()->Set(v8_str("__proto__"), current->Global());
4365 }
4366 // Set a named and an index property on the current global
4367 // object. To force the lookup to go through the other global object,
4368 // the properties must not exist in the other global object.
4369 current->Global()->Set(v8_str("foo"), v8_num(100));
4370 current->Global()->Set(v8_num(99), v8_num(101));
4371 // Try to read the properties from f and make sure that the access
4372 // gets stopped by the security checks on the other global object.
4373 Local<Script> access_f2 = v8_compile("f.foo");
4374 Local<Script> access_f3 = v8_compile("f[99]");
4375 for (int k = 0; k < 5; k++) {
4376 CHECK(!access_f2->Run()->Equals(v8_num(100)));
4377 CHECK(access_f2->Run()->IsUndefined());
4378 CHECK(!access_f3->Run()->Equals(v8_num(101)));
4379 CHECK(access_f3->Run()->IsUndefined());
4380 }
4381 other.Dispose();
4382}
4383
4384
4385THREADED_TEST(CrossDomainDelete) {
4386 v8::HandleScope handle_scope;
4387 LocalContext env1;
4388 v8::Persistent<Context> env2 = Context::New();
4389
4390 Local<Value> foo = v8_str("foo");
4391 Local<Value> bar = v8_str("bar");
4392
4393 // Set to the same domain.
4394 env1->SetSecurityToken(foo);
4395 env2->SetSecurityToken(foo);
4396
4397 env1->Global()->Set(v8_str("prop"), v8_num(3));
4398 env2->Global()->Set(v8_str("env1"), env1->Global());
4399
4400 // Change env2 to a different domain and delete env1.prop.
4401 env2->SetSecurityToken(bar);
4402 {
4403 Context::Scope scope_env2(env2);
4404 Local<Value> result =
4405 Script::Compile(v8_str("delete env1.prop"))->Run();
4406 CHECK(result->IsFalse());
4407 }
4408
4409 // Check that env1.prop still exists.
4410 Local<Value> v = env1->Global()->Get(v8_str("prop"));
4411 CHECK(v->IsNumber());
4412 CHECK_EQ(3, v->Int32Value());
4413
4414 env2.Dispose();
4415}
4416
4417
4418THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4419 v8::HandleScope handle_scope;
4420 LocalContext env1;
4421 v8::Persistent<Context> env2 = Context::New();
4422
4423 Local<Value> foo = v8_str("foo");
4424 Local<Value> bar = v8_str("bar");
4425
4426 // Set to the same domain.
4427 env1->SetSecurityToken(foo);
4428 env2->SetSecurityToken(foo);
4429
4430 env1->Global()->Set(v8_str("prop"), v8_num(3));
4431 env2->Global()->Set(v8_str("env1"), env1->Global());
4432
4433 // env1.prop is enumerable in env2.
4434 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4435 {
4436 Context::Scope scope_env2(env2);
4437 Local<Value> result = Script::Compile(test)->Run();
4438 CHECK(result->IsTrue());
4439 }
4440
4441 // Change env2 to a different domain and test again.
4442 env2->SetSecurityToken(bar);
4443 {
4444 Context::Scope scope_env2(env2);
4445 Local<Value> result = Script::Compile(test)->Run();
4446 CHECK(result->IsFalse());
4447 }
4448
4449 env2.Dispose();
4450}
4451
4452
4453THREADED_TEST(CrossDomainForIn) {
4454 v8::HandleScope handle_scope;
4455 LocalContext env1;
4456 v8::Persistent<Context> env2 = Context::New();
4457
4458 Local<Value> foo = v8_str("foo");
4459 Local<Value> bar = v8_str("bar");
4460
4461 // Set to the same domain.
4462 env1->SetSecurityToken(foo);
4463 env2->SetSecurityToken(foo);
4464
4465 env1->Global()->Set(v8_str("prop"), v8_num(3));
4466 env2->Global()->Set(v8_str("env1"), env1->Global());
4467
4468 // Change env2 to a different domain and set env1's global object
4469 // as the __proto__ of an object in env2 and enumerate properties
4470 // in for-in. It shouldn't enumerate properties on env1's global
4471 // object.
4472 env2->SetSecurityToken(bar);
4473 {
4474 Context::Scope scope_env2(env2);
4475 Local<Value> result =
4476 CompileRun("(function(){var obj = {'__proto__':env1};"
4477 "for (var p in obj)"
4478 " if (p == 'prop') return false;"
4479 "return true;})()");
4480 CHECK(result->IsTrue());
4481 }
4482 env2.Dispose();
4483}
4484
4485
4486TEST(ContextDetachGlobal) {
4487 v8::HandleScope handle_scope;
4488 LocalContext env1;
4489 v8::Persistent<Context> env2 = Context::New();
4490
4491 Local<v8::Object> global1 = env1->Global();
4492
4493 Local<Value> foo = v8_str("foo");
4494
4495 // Set to the same domain.
4496 env1->SetSecurityToken(foo);
4497 env2->SetSecurityToken(foo);
4498
4499 // Enter env2
4500 env2->Enter();
4501
Andrei Popescu74b3c142010-03-29 12:03:09 +01004502 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00004503 Local<v8::Object> global2 = env2->Global();
4504 global2->Set(v8_str("prop"), v8::Integer::New(1));
4505 CompileRun("function getProp() {return prop;}");
4506
4507 env1->Global()->Set(v8_str("getProp"),
4508 global2->Get(v8_str("getProp")));
4509
Andrei Popescu74b3c142010-03-29 12:03:09 +01004510 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00004511 env2->Exit();
4512 env2->DetachGlobal();
4513 // env2 has a new global object.
4514 CHECK(!env2->Global()->Equals(global2));
4515
4516 v8::Persistent<Context> env3 =
4517 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4518 env3->SetSecurityToken(v8_str("bar"));
4519 env3->Enter();
4520
4521 Local<v8::Object> global3 = env3->Global();
4522 CHECK_EQ(global2, global3);
4523 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4524 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4525 global3->Set(v8_str("prop"), v8::Integer::New(-1));
4526 global3->Set(v8_str("prop2"), v8::Integer::New(2));
4527 env3->Exit();
4528
4529 // Call getProp in env1, and it should return the value 1
4530 {
4531 Local<Value> get_prop = global1->Get(v8_str("getProp"));
4532 CHECK(get_prop->IsFunction());
4533 v8::TryCatch try_catch;
4534 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4535 CHECK(!try_catch.HasCaught());
4536 CHECK_EQ(1, r->Int32Value());
4537 }
4538
4539 // Check that env3 is not accessible from env1
4540 {
4541 Local<Value> r = global3->Get(v8_str("prop2"));
4542 CHECK(r->IsUndefined());
4543 }
4544
4545 env2.Dispose();
4546 env3.Dispose();
4547}
4548
4549
Andrei Popescu74b3c142010-03-29 12:03:09 +01004550TEST(DetachAndReattachGlobal) {
4551 v8::HandleScope scope;
4552 LocalContext env1;
4553
4554 // Create second environment.
4555 v8::Persistent<Context> env2 = Context::New();
4556
4557 Local<Value> foo = v8_str("foo");
4558
4559 // Set same security token for env1 and env2.
4560 env1->SetSecurityToken(foo);
4561 env2->SetSecurityToken(foo);
4562
4563 // Create a property on the global object in env2.
4564 {
4565 v8::Context::Scope scope(env2);
4566 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4567 }
4568
4569 // Create a reference to env2 global from env1 global.
4570 env1->Global()->Set(v8_str("other"), env2->Global());
4571
4572 // Check that we have access to other.p in env2 from env1.
4573 Local<Value> result = CompileRun("other.p");
4574 CHECK(result->IsInt32());
4575 CHECK_EQ(42, result->Int32Value());
4576
4577 // Hold on to global from env2 and detach global from env2.
4578 Local<v8::Object> global2 = env2->Global();
4579 env2->DetachGlobal();
4580
4581 // Check that the global has been detached. No other.p property can
4582 // be found.
4583 result = CompileRun("other.p");
4584 CHECK(result->IsUndefined());
4585
4586 // Reuse global2 for env3.
4587 v8::Persistent<Context> env3 =
4588 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4589 CHECK_EQ(global2, env3->Global());
4590
4591 // Start by using the same security token for env3 as for env1 and env2.
4592 env3->SetSecurityToken(foo);
4593
4594 // Create a property on the global object in env3.
4595 {
4596 v8::Context::Scope scope(env3);
4597 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4598 }
4599
4600 // Check that other.p is now the property in env3 and that we have access.
4601 result = CompileRun("other.p");
4602 CHECK(result->IsInt32());
4603 CHECK_EQ(24, result->Int32Value());
4604
4605 // Change security token for env3 to something different from env1 and env2.
4606 env3->SetSecurityToken(v8_str("bar"));
4607
4608 // Check that we do not have access to other.p in env1. |other| is now
4609 // the global object for env3 which has a different security token,
4610 // so access should be blocked.
4611 result = CompileRun("other.p");
4612 CHECK(result->IsUndefined());
4613
4614 // Detach the global for env3 and reattach it to env2.
4615 env3->DetachGlobal();
4616 env2->ReattachGlobal(global2);
4617
4618 // Check that we have access to other.p again in env1. |other| is now
4619 // the global object for env2 which has the same security token as env1.
4620 result = CompileRun("other.p");
4621 CHECK(result->IsInt32());
4622 CHECK_EQ(42, result->Int32Value());
4623
4624 env2.Dispose();
4625 env3.Dispose();
4626}
4627
4628
Steve Blocka7e24c12009-10-30 11:49:00 +00004629static bool NamedAccessBlocker(Local<v8::Object> global,
4630 Local<Value> name,
4631 v8::AccessType type,
4632 Local<Value> data) {
4633 return Context::GetCurrent()->Global()->Equals(global);
4634}
4635
4636
4637static bool IndexedAccessBlocker(Local<v8::Object> global,
4638 uint32_t key,
4639 v8::AccessType type,
4640 Local<Value> data) {
4641 return Context::GetCurrent()->Global()->Equals(global);
4642}
4643
4644
4645static int g_echo_value = -1;
4646static v8::Handle<Value> EchoGetter(Local<String> name,
4647 const AccessorInfo& info) {
4648 return v8_num(g_echo_value);
4649}
4650
4651
4652static void EchoSetter(Local<String> name,
4653 Local<Value> value,
4654 const AccessorInfo&) {
4655 if (value->IsNumber())
4656 g_echo_value = value->Int32Value();
4657}
4658
4659
4660static v8::Handle<Value> UnreachableGetter(Local<String> name,
4661 const AccessorInfo& info) {
4662 CHECK(false); // This function should not be called..
4663 return v8::Undefined();
4664}
4665
4666
4667static void UnreachableSetter(Local<String>, Local<Value>,
4668 const AccessorInfo&) {
4669 CHECK(false); // This function should nto be called.
4670}
4671
4672
4673THREADED_TEST(AccessControl) {
4674 v8::HandleScope handle_scope;
4675 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4676
4677 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4678 IndexedAccessBlocker);
4679
4680 // Add an accessor accessible by cross-domain JS code.
4681 global_template->SetAccessor(
4682 v8_str("accessible_prop"),
4683 EchoGetter, EchoSetter,
4684 v8::Handle<Value>(),
4685 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4686
4687 // Add an accessor that is not accessible by cross-domain JS code.
4688 global_template->SetAccessor(v8_str("blocked_prop"),
4689 UnreachableGetter, UnreachableSetter,
4690 v8::Handle<Value>(),
4691 v8::DEFAULT);
4692
4693 // Create an environment
4694 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4695 context0->Enter();
4696
4697 v8::Handle<v8::Object> global0 = context0->Global();
4698
4699 v8::HandleScope scope1;
4700
4701 v8::Persistent<Context> context1 = Context::New();
4702 context1->Enter();
4703
4704 v8::Handle<v8::Object> global1 = context1->Global();
4705 global1->Set(v8_str("other"), global0);
4706
4707 v8::Handle<Value> value;
4708
4709 // Access blocked property
4710 value = v8_compile("other.blocked_prop = 1")->Run();
4711 value = v8_compile("other.blocked_prop")->Run();
4712 CHECK(value->IsUndefined());
4713
4714 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4715 CHECK(value->IsFalse());
4716
4717 // Access accessible property
4718 value = v8_compile("other.accessible_prop = 3")->Run();
4719 CHECK(value->IsNumber());
4720 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00004721 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00004722
4723 value = v8_compile("other.accessible_prop")->Run();
4724 CHECK(value->IsNumber());
4725 CHECK_EQ(3, value->Int32Value());
4726
4727 value =
4728 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4729 CHECK(value->IsTrue());
4730
4731 // Enumeration doesn't enumerate accessors from inaccessible objects in
4732 // the prototype chain even if the accessors are in themselves accessible.
4733 Local<Value> result =
4734 CompileRun("(function(){var obj = {'__proto__':other};"
4735 "for (var p in obj)"
4736 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
4737 " return false;"
4738 " }"
4739 "return true;})()");
4740 CHECK(result->IsTrue());
4741
4742 context1->Exit();
4743 context0->Exit();
4744 context1.Dispose();
4745 context0.Dispose();
4746}
4747
4748
Leon Clarke4515c472010-02-03 11:58:03 +00004749static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4750 Local<Value> name,
4751 v8::AccessType type,
4752 Local<Value> data) {
4753 return false;
4754}
4755
4756
4757static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4758 uint32_t key,
4759 v8::AccessType type,
4760 Local<Value> data) {
4761 return false;
4762}
4763
4764
4765THREADED_TEST(AccessControlGetOwnPropertyNames) {
4766 v8::HandleScope handle_scope;
4767 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4768
4769 obj_template->Set(v8_str("x"), v8::Integer::New(42));
4770 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
4771 GetOwnPropertyNamesIndexedBlocker);
4772
4773 // Create an environment
4774 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
4775 context0->Enter();
4776
4777 v8::Handle<v8::Object> global0 = context0->Global();
4778
4779 v8::HandleScope scope1;
4780
4781 v8::Persistent<Context> context1 = Context::New();
4782 context1->Enter();
4783
4784 v8::Handle<v8::Object> global1 = context1->Global();
4785 global1->Set(v8_str("other"), global0);
4786 global1->Set(v8_str("object"), obj_template->NewInstance());
4787
4788 v8::Handle<Value> value;
4789
4790 // Attempt to get the property names of the other global object and
4791 // of an object that requires access checks. Accessing the other
4792 // global object should be blocked by access checks on the global
4793 // proxy object. Accessing the object that requires access checks
4794 // is blocked by the access checks on the object itself.
4795 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
4796 CHECK(value->IsTrue());
4797
4798 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
4799 CHECK(value->IsTrue());
4800
4801 context1->Exit();
4802 context0->Exit();
4803 context1.Dispose();
4804 context0.Dispose();
4805}
4806
4807
Steve Blocka7e24c12009-10-30 11:49:00 +00004808static v8::Handle<Value> ConstTenGetter(Local<String> name,
4809 const AccessorInfo& info) {
4810 return v8_num(10);
4811}
4812
4813
4814THREADED_TEST(CrossDomainAccessors) {
4815 v8::HandleScope handle_scope;
4816
4817 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4818
4819 v8::Handle<v8::ObjectTemplate> global_template =
4820 func_template->InstanceTemplate();
4821
4822 v8::Handle<v8::ObjectTemplate> proto_template =
4823 func_template->PrototypeTemplate();
4824
4825 // Add an accessor to proto that's accessible by cross-domain JS code.
4826 proto_template->SetAccessor(v8_str("accessible"),
4827 ConstTenGetter, 0,
4828 v8::Handle<Value>(),
4829 v8::ALL_CAN_READ);
4830
4831 // Add an accessor that is not accessible by cross-domain JS code.
4832 global_template->SetAccessor(v8_str("unreachable"),
4833 UnreachableGetter, 0,
4834 v8::Handle<Value>(),
4835 v8::DEFAULT);
4836
4837 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4838 context0->Enter();
4839
4840 Local<v8::Object> global = context0->Global();
4841 // Add a normal property that shadows 'accessible'
4842 global->Set(v8_str("accessible"), v8_num(11));
4843
4844 // Enter a new context.
4845 v8::HandleScope scope1;
4846 v8::Persistent<Context> context1 = Context::New();
4847 context1->Enter();
4848
4849 v8::Handle<v8::Object> global1 = context1->Global();
4850 global1->Set(v8_str("other"), global);
4851
4852 // Should return 10, instead of 11
4853 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4854 CHECK(value->IsNumber());
4855 CHECK_EQ(10, value->Int32Value());
4856
4857 value = v8_compile("other.unreachable")->Run();
4858 CHECK(value->IsUndefined());
4859
4860 context1->Exit();
4861 context0->Exit();
4862 context1.Dispose();
4863 context0.Dispose();
4864}
4865
4866
4867static int named_access_count = 0;
4868static int indexed_access_count = 0;
4869
4870static bool NamedAccessCounter(Local<v8::Object> global,
4871 Local<Value> name,
4872 v8::AccessType type,
4873 Local<Value> data) {
4874 named_access_count++;
4875 return true;
4876}
4877
4878
4879static bool IndexedAccessCounter(Local<v8::Object> global,
4880 uint32_t key,
4881 v8::AccessType type,
4882 Local<Value> data) {
4883 indexed_access_count++;
4884 return true;
4885}
4886
4887
4888// This one is too easily disturbed by other tests.
4889TEST(AccessControlIC) {
4890 named_access_count = 0;
4891 indexed_access_count = 0;
4892
4893 v8::HandleScope handle_scope;
4894
4895 // Create an environment.
4896 v8::Persistent<Context> context0 = Context::New();
4897 context0->Enter();
4898
4899 // Create an object that requires access-check functions to be
4900 // called for cross-domain access.
4901 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4902 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4903 IndexedAccessCounter);
4904 Local<v8::Object> object = object_template->NewInstance();
4905
4906 v8::HandleScope scope1;
4907
4908 // Create another environment.
4909 v8::Persistent<Context> context1 = Context::New();
4910 context1->Enter();
4911
4912 // Make easy access to the object from the other environment.
4913 v8::Handle<v8::Object> global1 = context1->Global();
4914 global1->Set(v8_str("obj"), object);
4915
4916 v8::Handle<Value> value;
4917
4918 // Check that the named access-control function is called every time.
4919 CompileRun("function testProp(obj) {"
4920 " for (var i = 0; i < 10; i++) obj.prop = 1;"
4921 " for (var j = 0; j < 10; j++) obj.prop;"
4922 " return obj.prop"
4923 "}");
4924 value = CompileRun("testProp(obj)");
4925 CHECK(value->IsNumber());
4926 CHECK_EQ(1, value->Int32Value());
4927 CHECK_EQ(21, named_access_count);
4928
4929 // Check that the named access-control function is called every time.
4930 CompileRun("var p = 'prop';"
4931 "function testKeyed(obj) {"
4932 " for (var i = 0; i < 10; i++) obj[p] = 1;"
4933 " for (var j = 0; j < 10; j++) obj[p];"
4934 " return obj[p];"
4935 "}");
4936 // Use obj which requires access checks. No inline caching is used
4937 // in that case.
4938 value = CompileRun("testKeyed(obj)");
4939 CHECK(value->IsNumber());
4940 CHECK_EQ(1, value->Int32Value());
4941 CHECK_EQ(42, named_access_count);
4942 // Force the inline caches into generic state and try again.
4943 CompileRun("testKeyed({ a: 0 })");
4944 CompileRun("testKeyed({ b: 0 })");
4945 value = CompileRun("testKeyed(obj)");
4946 CHECK(value->IsNumber());
4947 CHECK_EQ(1, value->Int32Value());
4948 CHECK_EQ(63, named_access_count);
4949
4950 // Check that the indexed access-control function is called every time.
4951 CompileRun("function testIndexed(obj) {"
4952 " for (var i = 0; i < 10; i++) obj[0] = 1;"
4953 " for (var j = 0; j < 10; j++) obj[0];"
4954 " return obj[0]"
4955 "}");
4956 value = CompileRun("testIndexed(obj)");
4957 CHECK(value->IsNumber());
4958 CHECK_EQ(1, value->Int32Value());
4959 CHECK_EQ(21, indexed_access_count);
4960 // Force the inline caches into generic state.
4961 CompileRun("testIndexed(new Array(1))");
4962 // Test that the indexed access check is called.
4963 value = CompileRun("testIndexed(obj)");
4964 CHECK(value->IsNumber());
4965 CHECK_EQ(1, value->Int32Value());
4966 CHECK_EQ(42, indexed_access_count);
4967
4968 // Check that the named access check is called when invoking
4969 // functions on an object that requires access checks.
4970 CompileRun("obj.f = function() {}");
4971 CompileRun("function testCallNormal(obj) {"
4972 " for (var i = 0; i < 10; i++) obj.f();"
4973 "}");
4974 CompileRun("testCallNormal(obj)");
4975 CHECK_EQ(74, named_access_count);
4976
4977 // Force obj into slow case.
4978 value = CompileRun("delete obj.prop");
4979 CHECK(value->BooleanValue());
4980 // Force inline caches into dictionary probing mode.
4981 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4982 // Test that the named access check is called.
4983 value = CompileRun("testProp(obj);");
4984 CHECK(value->IsNumber());
4985 CHECK_EQ(1, value->Int32Value());
4986 CHECK_EQ(96, named_access_count);
4987
4988 // Force the call inline cache into dictionary probing mode.
4989 CompileRun("o.f = function() {}; testCallNormal(o)");
4990 // Test that the named access check is still called for each
4991 // invocation of the function.
4992 value = CompileRun("testCallNormal(obj)");
4993 CHECK_EQ(106, named_access_count);
4994
4995 context1->Exit();
4996 context0->Exit();
4997 context1.Dispose();
4998 context0.Dispose();
4999}
5000
5001
5002static bool NamedAccessFlatten(Local<v8::Object> global,
5003 Local<Value> name,
5004 v8::AccessType type,
5005 Local<Value> data) {
5006 char buf[100];
5007 int len;
5008
5009 CHECK(name->IsString());
5010
5011 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005012 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00005013 CHECK_EQ(4, len);
5014
5015 uint16_t buf2[100];
5016
5017 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005018 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00005019 CHECK_EQ(4, len);
5020
5021 return true;
5022}
5023
5024
5025static bool IndexedAccessFlatten(Local<v8::Object> global,
5026 uint32_t key,
5027 v8::AccessType type,
5028 Local<Value> data) {
5029 return true;
5030}
5031
5032
5033// Regression test. In access checks, operations that may cause
5034// garbage collection are not allowed. It used to be the case that
5035// using the Write operation on a string could cause a garbage
5036// collection due to flattening of the string. This is no longer the
5037// case.
5038THREADED_TEST(AccessControlFlatten) {
5039 named_access_count = 0;
5040 indexed_access_count = 0;
5041
5042 v8::HandleScope handle_scope;
5043
5044 // Create an environment.
5045 v8::Persistent<Context> context0 = Context::New();
5046 context0->Enter();
5047
5048 // Create an object that requires access-check functions to be
5049 // called for cross-domain access.
5050 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5051 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5052 IndexedAccessFlatten);
5053 Local<v8::Object> object = object_template->NewInstance();
5054
5055 v8::HandleScope scope1;
5056
5057 // Create another environment.
5058 v8::Persistent<Context> context1 = Context::New();
5059 context1->Enter();
5060
5061 // Make easy access to the object from the other environment.
5062 v8::Handle<v8::Object> global1 = context1->Global();
5063 global1->Set(v8_str("obj"), object);
5064
5065 v8::Handle<Value> value;
5066
5067 value = v8_compile("var p = 'as' + 'df';")->Run();
5068 value = v8_compile("obj[p];")->Run();
5069
5070 context1->Exit();
5071 context0->Exit();
5072 context1.Dispose();
5073 context0.Dispose();
5074}
5075
5076
5077static v8::Handle<Value> AccessControlNamedGetter(
5078 Local<String>, const AccessorInfo&) {
5079 return v8::Integer::New(42);
5080}
5081
5082
5083static v8::Handle<Value> AccessControlNamedSetter(
5084 Local<String>, Local<Value> value, const AccessorInfo&) {
5085 return value;
5086}
5087
5088
5089static v8::Handle<Value> AccessControlIndexedGetter(
5090 uint32_t index,
5091 const AccessorInfo& info) {
5092 return v8_num(42);
5093}
5094
5095
5096static v8::Handle<Value> AccessControlIndexedSetter(
5097 uint32_t, Local<Value> value, const AccessorInfo&) {
5098 return value;
5099}
5100
5101
5102THREADED_TEST(AccessControlInterceptorIC) {
5103 named_access_count = 0;
5104 indexed_access_count = 0;
5105
5106 v8::HandleScope handle_scope;
5107
5108 // Create an environment.
5109 v8::Persistent<Context> context0 = Context::New();
5110 context0->Enter();
5111
5112 // Create an object that requires access-check functions to be
5113 // called for cross-domain access. The object also has interceptors
5114 // interceptor.
5115 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5116 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5117 IndexedAccessCounter);
5118 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5119 AccessControlNamedSetter);
5120 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5121 AccessControlIndexedSetter);
5122 Local<v8::Object> object = object_template->NewInstance();
5123
5124 v8::HandleScope scope1;
5125
5126 // Create another environment.
5127 v8::Persistent<Context> context1 = Context::New();
5128 context1->Enter();
5129
5130 // Make easy access to the object from the other environment.
5131 v8::Handle<v8::Object> global1 = context1->Global();
5132 global1->Set(v8_str("obj"), object);
5133
5134 v8::Handle<Value> value;
5135
5136 // Check that the named access-control function is called every time
5137 // eventhough there is an interceptor on the object.
5138 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5139 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5140 "obj.x")->Run();
5141 CHECK(value->IsNumber());
5142 CHECK_EQ(42, value->Int32Value());
5143 CHECK_EQ(21, named_access_count);
5144
5145 value = v8_compile("var p = 'x';")->Run();
5146 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5147 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5148 "obj[p]")->Run();
5149 CHECK(value->IsNumber());
5150 CHECK_EQ(42, value->Int32Value());
5151 CHECK_EQ(42, named_access_count);
5152
5153 // Check that the indexed access-control function is called every
5154 // time eventhough there is an interceptor on the object.
5155 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5156 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5157 "obj[0]")->Run();
5158 CHECK(value->IsNumber());
5159 CHECK_EQ(42, value->Int32Value());
5160 CHECK_EQ(21, indexed_access_count);
5161
5162 context1->Exit();
5163 context0->Exit();
5164 context1.Dispose();
5165 context0.Dispose();
5166}
5167
5168
5169THREADED_TEST(Version) {
5170 v8::V8::GetVersion();
5171}
5172
5173
5174static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5175 ApiTestFuzzer::Fuzz();
5176 return v8_num(12);
5177}
5178
5179
5180THREADED_TEST(InstanceProperties) {
5181 v8::HandleScope handle_scope;
5182 LocalContext context;
5183
5184 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5185 Local<ObjectTemplate> instance = t->InstanceTemplate();
5186
5187 instance->Set(v8_str("x"), v8_num(42));
5188 instance->Set(v8_str("f"),
5189 v8::FunctionTemplate::New(InstanceFunctionCallback));
5190
5191 Local<Value> o = t->GetFunction()->NewInstance();
5192
5193 context->Global()->Set(v8_str("i"), o);
5194 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5195 CHECK_EQ(42, value->Int32Value());
5196
5197 value = Script::Compile(v8_str("i.f()"))->Run();
5198 CHECK_EQ(12, value->Int32Value());
5199}
5200
5201
5202static v8::Handle<Value>
5203GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5204 ApiTestFuzzer::Fuzz();
5205 return v8::Handle<Value>();
5206}
5207
5208
5209THREADED_TEST(GlobalObjectInstanceProperties) {
5210 v8::HandleScope handle_scope;
5211
5212 Local<Value> global_object;
5213
5214 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5215 t->InstanceTemplate()->SetNamedPropertyHandler(
5216 GlobalObjectInstancePropertiesGet);
5217 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5218 instance_template->Set(v8_str("x"), v8_num(42));
5219 instance_template->Set(v8_str("f"),
5220 v8::FunctionTemplate::New(InstanceFunctionCallback));
5221
5222 {
5223 LocalContext env(NULL, instance_template);
5224 // Hold on to the global object so it can be used again in another
5225 // environment initialization.
5226 global_object = env->Global();
5227
5228 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5229 CHECK_EQ(42, value->Int32Value());
5230 value = Script::Compile(v8_str("f()"))->Run();
5231 CHECK_EQ(12, value->Int32Value());
5232 }
5233
5234 {
5235 // Create new environment reusing the global object.
5236 LocalContext env(NULL, instance_template, global_object);
5237 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5238 CHECK_EQ(42, value->Int32Value());
5239 value = Script::Compile(v8_str("f()"))->Run();
5240 CHECK_EQ(12, value->Int32Value());
5241 }
5242}
5243
5244
5245static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5246 ApiTestFuzzer::Fuzz();
5247 return v8_num(42);
5248}
5249
5250
5251static int shadow_y;
5252static int shadow_y_setter_call_count;
5253static int shadow_y_getter_call_count;
5254
5255
5256static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5257 shadow_y_setter_call_count++;
5258 shadow_y = 42;
5259}
5260
5261
5262static v8::Handle<Value> ShadowYGetter(Local<String> name,
5263 const AccessorInfo& info) {
5264 ApiTestFuzzer::Fuzz();
5265 shadow_y_getter_call_count++;
5266 return v8_num(shadow_y);
5267}
5268
5269
5270static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5271 const AccessorInfo& info) {
5272 return v8::Handle<Value>();
5273}
5274
5275
5276static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5277 const AccessorInfo&) {
5278 return v8::Handle<Value>();
5279}
5280
5281
5282THREADED_TEST(ShadowObject) {
5283 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5284 v8::HandleScope handle_scope;
5285
5286 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5287 LocalContext context(NULL, global_template);
5288
5289 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5290 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5291 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5292 Local<ObjectTemplate> proto = t->PrototypeTemplate();
5293 Local<ObjectTemplate> instance = t->InstanceTemplate();
5294
5295 // Only allow calls of f on instances of t.
5296 Local<v8::Signature> signature = v8::Signature::New(t);
5297 proto->Set(v8_str("f"),
5298 v8::FunctionTemplate::New(ShadowFunctionCallback,
5299 Local<Value>(),
5300 signature));
5301 proto->Set(v8_str("x"), v8_num(12));
5302
5303 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5304
5305 Local<Value> o = t->GetFunction()->NewInstance();
5306 context->Global()->Set(v8_str("__proto__"), o);
5307
5308 Local<Value> value =
5309 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5310 CHECK(value->IsBoolean());
5311 CHECK(!value->BooleanValue());
5312
5313 value = Script::Compile(v8_str("x"))->Run();
5314 CHECK_EQ(12, value->Int32Value());
5315
5316 value = Script::Compile(v8_str("f()"))->Run();
5317 CHECK_EQ(42, value->Int32Value());
5318
5319 Script::Compile(v8_str("y = 42"))->Run();
5320 CHECK_EQ(1, shadow_y_setter_call_count);
5321 value = Script::Compile(v8_str("y"))->Run();
5322 CHECK_EQ(1, shadow_y_getter_call_count);
5323 CHECK_EQ(42, value->Int32Value());
5324}
5325
5326
5327THREADED_TEST(HiddenPrototype) {
5328 v8::HandleScope handle_scope;
5329 LocalContext context;
5330
5331 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5332 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5333 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5334 t1->SetHiddenPrototype(true);
5335 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5336 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5337 t2->SetHiddenPrototype(true);
5338 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5339 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5340 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5341
5342 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5343 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5344 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5345 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5346
5347 // Setting the prototype on an object skips hidden prototypes.
5348 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5349 o0->Set(v8_str("__proto__"), o1);
5350 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5351 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5352 o0->Set(v8_str("__proto__"), o2);
5353 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5354 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5355 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5356 o0->Set(v8_str("__proto__"), o3);
5357 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5358 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5359 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5360 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5361
5362 // Getting the prototype of o0 should get the first visible one
5363 // which is o3. Therefore, z should not be defined on the prototype
5364 // object.
5365 Local<Value> proto = o0->Get(v8_str("__proto__"));
5366 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005367 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00005368}
5369
5370
Andrei Popescu402d9372010-02-26 13:31:12 +00005371THREADED_TEST(SetPrototype) {
5372 v8::HandleScope handle_scope;
5373 LocalContext context;
5374
5375 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5376 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5377 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5378 t1->SetHiddenPrototype(true);
5379 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5380 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5381 t2->SetHiddenPrototype(true);
5382 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5383 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5384 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5385
5386 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5387 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5388 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5389 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5390
5391 // Setting the prototype on an object does not skip hidden prototypes.
5392 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5393 CHECK(o0->SetPrototype(o1));
5394 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5395 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5396 CHECK(o1->SetPrototype(o2));
5397 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5398 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5399 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5400 CHECK(o2->SetPrototype(o3));
5401 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5402 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5403 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5404 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5405
5406 // Getting the prototype of o0 should get the first visible one
5407 // which is o3. Therefore, z should not be defined on the prototype
5408 // object.
5409 Local<Value> proto = o0->Get(v8_str("__proto__"));
5410 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005411 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00005412
5413 // However, Object::GetPrototype ignores hidden prototype.
5414 Local<Value> proto0 = o0->GetPrototype();
5415 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005416 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005417
5418 Local<Value> proto1 = o1->GetPrototype();
5419 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005420 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00005421
5422 Local<Value> proto2 = o2->GetPrototype();
5423 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01005424 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00005425}
5426
5427
5428THREADED_TEST(SetPrototypeThrows) {
5429 v8::HandleScope handle_scope;
5430 LocalContext context;
5431
5432 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5433
5434 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5435 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5436
5437 CHECK(o0->SetPrototype(o1));
5438 // If setting the prototype leads to the cycle, SetPrototype should
5439 // return false and keep VM in sane state.
5440 v8::TryCatch try_catch;
5441 CHECK(!o1->SetPrototype(o0));
5442 CHECK(!try_catch.HasCaught());
5443 ASSERT(!i::Top::has_pending_exception());
5444
5445 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5446}
5447
5448
Steve Blocka7e24c12009-10-30 11:49:00 +00005449THREADED_TEST(GetterSetterExceptions) {
5450 v8::HandleScope handle_scope;
5451 LocalContext context;
5452 CompileRun(
5453 "function Foo() { };"
5454 "function Throw() { throw 5; };"
5455 "var x = { };"
5456 "x.__defineSetter__('set', Throw);"
5457 "x.__defineGetter__('get', Throw);");
5458 Local<v8::Object> x =
5459 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5460 v8::TryCatch try_catch;
5461 x->Set(v8_str("set"), v8::Integer::New(8));
5462 x->Get(v8_str("get"));
5463 x->Set(v8_str("set"), v8::Integer::New(8));
5464 x->Get(v8_str("get"));
5465 x->Set(v8_str("set"), v8::Integer::New(8));
5466 x->Get(v8_str("get"));
5467 x->Set(v8_str("set"), v8::Integer::New(8));
5468 x->Get(v8_str("get"));
5469}
5470
5471
5472THREADED_TEST(Constructor) {
5473 v8::HandleScope handle_scope;
5474 LocalContext context;
5475 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5476 templ->SetClassName(v8_str("Fun"));
5477 Local<Function> cons = templ->GetFunction();
5478 context->Global()->Set(v8_str("Fun"), cons);
5479 Local<v8::Object> inst = cons->NewInstance();
5480 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5481 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5482 CHECK(value->BooleanValue());
5483}
5484
5485THREADED_TEST(FunctionDescriptorException) {
5486 v8::HandleScope handle_scope;
5487 LocalContext context;
5488 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5489 templ->SetClassName(v8_str("Fun"));
5490 Local<Function> cons = templ->GetFunction();
5491 context->Global()->Set(v8_str("Fun"), cons);
5492 Local<Value> value = CompileRun(
5493 "function test() {"
5494 " try {"
5495 " (new Fun()).blah()"
5496 " } catch (e) {"
5497 " var str = String(e);"
5498 " if (str.indexOf('TypeError') == -1) return 1;"
5499 " if (str.indexOf('[object Fun]') != -1) return 2;"
5500 " if (str.indexOf('#<a Fun>') == -1) return 3;"
5501 " return 0;"
5502 " }"
5503 " return 4;"
5504 "}"
5505 "test();");
5506 CHECK_EQ(0, value->Int32Value());
5507}
5508
5509
5510THREADED_TEST(EvalAliasedDynamic) {
5511 v8::HandleScope scope;
5512 LocalContext current;
5513
5514 // Tests where aliased eval can only be resolved dynamically.
5515 Local<Script> script =
5516 Script::Compile(v8_str("function f(x) { "
5517 " var foo = 2;"
5518 " with (x) { return eval('foo'); }"
5519 "}"
5520 "foo = 0;"
5521 "result1 = f(new Object());"
5522 "result2 = f(this);"
5523 "var x = new Object();"
5524 "x.eval = function(x) { return 1; };"
5525 "result3 = f(x);"));
5526 script->Run();
5527 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5528 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5529 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5530
5531 v8::TryCatch try_catch;
5532 script =
5533 Script::Compile(v8_str("function f(x) { "
5534 " var bar = 2;"
5535 " with (x) { return eval('bar'); }"
5536 "}"
5537 "f(this)"));
5538 script->Run();
5539 CHECK(try_catch.HasCaught());
5540 try_catch.Reset();
5541}
5542
5543
5544THREADED_TEST(CrossEval) {
5545 v8::HandleScope scope;
5546 LocalContext other;
5547 LocalContext current;
5548
5549 Local<String> token = v8_str("<security token>");
5550 other->SetSecurityToken(token);
5551 current->SetSecurityToken(token);
5552
5553 // Setup reference from current to other.
5554 current->Global()->Set(v8_str("other"), other->Global());
5555
5556 // Check that new variables are introduced in other context.
5557 Local<Script> script =
5558 Script::Compile(v8_str("other.eval('var foo = 1234')"));
5559 script->Run();
5560 Local<Value> foo = other->Global()->Get(v8_str("foo"));
5561 CHECK_EQ(1234, foo->Int32Value());
5562 CHECK(!current->Global()->Has(v8_str("foo")));
5563
5564 // Check that writing to non-existing properties introduces them in
5565 // the other context.
5566 script =
5567 Script::Compile(v8_str("other.eval('na = 1234')"));
5568 script->Run();
5569 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5570 CHECK(!current->Global()->Has(v8_str("na")));
5571
5572 // Check that global variables in current context are not visible in other
5573 // context.
5574 v8::TryCatch try_catch;
5575 script =
5576 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5577 Local<Value> result = script->Run();
5578 CHECK(try_catch.HasCaught());
5579 try_catch.Reset();
5580
5581 // Check that local variables in current context are not visible in other
5582 // context.
5583 script =
5584 Script::Compile(v8_str("(function() { "
5585 " var baz = 87;"
5586 " return other.eval('baz');"
5587 "})();"));
5588 result = script->Run();
5589 CHECK(try_catch.HasCaught());
5590 try_catch.Reset();
5591
5592 // Check that global variables in the other environment are visible
5593 // when evaluting code.
5594 other->Global()->Set(v8_str("bis"), v8_num(1234));
5595 script = Script::Compile(v8_str("other.eval('bis')"));
5596 CHECK_EQ(1234, script->Run()->Int32Value());
5597 CHECK(!try_catch.HasCaught());
5598
5599 // Check that the 'this' pointer points to the global object evaluating
5600 // code.
5601 other->Global()->Set(v8_str("t"), other->Global());
5602 script = Script::Compile(v8_str("other.eval('this == t')"));
5603 result = script->Run();
5604 CHECK(result->IsTrue());
5605 CHECK(!try_catch.HasCaught());
5606
5607 // Check that variables introduced in with-statement are not visible in
5608 // other context.
5609 script =
5610 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5611 result = script->Run();
5612 CHECK(try_catch.HasCaught());
5613 try_catch.Reset();
5614
5615 // Check that you cannot use 'eval.call' with another object than the
5616 // current global object.
5617 script =
5618 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5619 result = script->Run();
5620 CHECK(try_catch.HasCaught());
5621}
5622
5623
5624// Test that calling eval in a context which has been detached from
5625// its global throws an exception. This behavior is consistent with
5626// other JavaScript implementations.
5627THREADED_TEST(EvalInDetachedGlobal) {
5628 v8::HandleScope scope;
5629
5630 v8::Persistent<Context> context0 = Context::New();
5631 v8::Persistent<Context> context1 = Context::New();
5632
5633 // Setup function in context0 that uses eval from context0.
5634 context0->Enter();
5635 v8::Handle<v8::Value> fun =
5636 CompileRun("var x = 42;"
5637 "(function() {"
5638 " var e = eval;"
5639 " return function(s) { return e(s); }"
5640 "})()");
5641 context0->Exit();
5642
5643 // Put the function into context1 and call it before and after
5644 // detaching the global. Before detaching, the call succeeds and
5645 // after detaching and exception is thrown.
5646 context1->Enter();
5647 context1->Global()->Set(v8_str("fun"), fun);
5648 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5649 CHECK_EQ(42, x_value->Int32Value());
5650 context0->DetachGlobal();
5651 v8::TryCatch catcher;
5652 x_value = CompileRun("fun('x')");
5653 CHECK(x_value.IsEmpty());
5654 CHECK(catcher.HasCaught());
5655 context1->Exit();
5656
5657 context1.Dispose();
5658 context0.Dispose();
5659}
5660
5661
5662THREADED_TEST(CrossLazyLoad) {
5663 v8::HandleScope scope;
5664 LocalContext other;
5665 LocalContext current;
5666
5667 Local<String> token = v8_str("<security token>");
5668 other->SetSecurityToken(token);
5669 current->SetSecurityToken(token);
5670
5671 // Setup reference from current to other.
5672 current->Global()->Set(v8_str("other"), other->Global());
5673
5674 // Trigger lazy loading in other context.
5675 Local<Script> script =
5676 Script::Compile(v8_str("other.eval('new Date(42)')"));
5677 Local<Value> value = script->Run();
5678 CHECK_EQ(42.0, value->NumberValue());
5679}
5680
5681
5682static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00005683 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00005684 if (args.IsConstructCall()) {
5685 if (args[0]->IsInt32()) {
5686 return v8_num(-args[0]->Int32Value());
5687 }
5688 }
5689
5690 return args[0];
5691}
5692
5693
5694// Test that a call handler can be set for objects which will allow
5695// non-function objects created through the API to be called as
5696// functions.
5697THREADED_TEST(CallAsFunction) {
5698 v8::HandleScope scope;
5699 LocalContext context;
5700
5701 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5702 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5703 instance_template->SetCallAsFunctionHandler(call_as_function);
5704 Local<v8::Object> instance = t->GetFunction()->NewInstance();
5705 context->Global()->Set(v8_str("obj"), instance);
5706 v8::TryCatch try_catch;
5707 Local<Value> value;
5708 CHECK(!try_catch.HasCaught());
5709
5710 value = CompileRun("obj(42)");
5711 CHECK(!try_catch.HasCaught());
5712 CHECK_EQ(42, value->Int32Value());
5713
5714 value = CompileRun("(function(o){return o(49)})(obj)");
5715 CHECK(!try_catch.HasCaught());
5716 CHECK_EQ(49, value->Int32Value());
5717
5718 // test special case of call as function
5719 value = CompileRun("[obj]['0'](45)");
5720 CHECK(!try_catch.HasCaught());
5721 CHECK_EQ(45, value->Int32Value());
5722
5723 value = CompileRun("obj.call = Function.prototype.call;"
5724 "obj.call(null, 87)");
5725 CHECK(!try_catch.HasCaught());
5726 CHECK_EQ(87, value->Int32Value());
5727
5728 // Regression tests for bug #1116356: Calling call through call/apply
5729 // must work for non-function receivers.
5730 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5731 value = CompileRun(apply_99);
5732 CHECK(!try_catch.HasCaught());
5733 CHECK_EQ(99, value->Int32Value());
5734
5735 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5736 value = CompileRun(call_17);
5737 CHECK(!try_catch.HasCaught());
5738 CHECK_EQ(17, value->Int32Value());
5739
5740 // Check that the call-as-function handler can be called through
Leon Clarkee46be812010-01-19 14:06:41 +00005741 // new.
Steve Blocka7e24c12009-10-30 11:49:00 +00005742 value = CompileRun("new obj(43)");
5743 CHECK(!try_catch.HasCaught());
5744 CHECK_EQ(-43, value->Int32Value());
5745}
5746
5747
5748static int CountHandles() {
5749 return v8::HandleScope::NumberOfHandles();
5750}
5751
5752
5753static int Recurse(int depth, int iterations) {
5754 v8::HandleScope scope;
5755 if (depth == 0) return CountHandles();
5756 for (int i = 0; i < iterations; i++) {
5757 Local<v8::Number> n = v8::Integer::New(42);
5758 }
5759 return Recurse(depth - 1, iterations);
5760}
5761
5762
5763THREADED_TEST(HandleIteration) {
5764 static const int kIterations = 500;
5765 static const int kNesting = 200;
5766 CHECK_EQ(0, CountHandles());
5767 {
5768 v8::HandleScope scope1;
5769 CHECK_EQ(0, CountHandles());
5770 for (int i = 0; i < kIterations; i++) {
5771 Local<v8::Number> n = v8::Integer::New(42);
5772 CHECK_EQ(i + 1, CountHandles());
5773 }
5774
5775 CHECK_EQ(kIterations, CountHandles());
5776 {
5777 v8::HandleScope scope2;
5778 for (int j = 0; j < kIterations; j++) {
5779 Local<v8::Number> n = v8::Integer::New(42);
5780 CHECK_EQ(j + 1 + kIterations, CountHandles());
5781 }
5782 }
5783 CHECK_EQ(kIterations, CountHandles());
5784 }
5785 CHECK_EQ(0, CountHandles());
5786 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
5787}
5788
5789
5790static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5791 Local<String> name,
5792 const AccessorInfo& info) {
5793 ApiTestFuzzer::Fuzz();
5794 return v8::Handle<Value>();
5795}
5796
5797
5798THREADED_TEST(InterceptorHasOwnProperty) {
5799 v8::HandleScope scope;
5800 LocalContext context;
5801 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5802 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5803 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5804 Local<Function> function = fun_templ->GetFunction();
5805 context->Global()->Set(v8_str("constructor"), function);
5806 v8::Handle<Value> value = CompileRun(
5807 "var o = new constructor();"
5808 "o.hasOwnProperty('ostehaps');");
5809 CHECK_EQ(false, value->BooleanValue());
5810 value = CompileRun(
5811 "o.ostehaps = 42;"
5812 "o.hasOwnProperty('ostehaps');");
5813 CHECK_EQ(true, value->BooleanValue());
5814 value = CompileRun(
5815 "var p = new constructor();"
5816 "p.hasOwnProperty('ostehaps');");
5817 CHECK_EQ(false, value->BooleanValue());
5818}
5819
5820
5821static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5822 Local<String> name,
5823 const AccessorInfo& info) {
5824 ApiTestFuzzer::Fuzz();
5825 i::Heap::CollectAllGarbage(false);
5826 return v8::Handle<Value>();
5827}
5828
5829
5830THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5831 v8::HandleScope scope;
5832 LocalContext context;
5833 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5834 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5835 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5836 Local<Function> function = fun_templ->GetFunction();
5837 context->Global()->Set(v8_str("constructor"), function);
5838 // Let's first make some stuff so we can be sure to get a good GC.
5839 CompileRun(
5840 "function makestr(size) {"
5841 " switch (size) {"
5842 " case 1: return 'f';"
5843 " case 2: return 'fo';"
5844 " case 3: return 'foo';"
5845 " }"
5846 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
5847 "}"
5848 "var x = makestr(12345);"
5849 "x = makestr(31415);"
5850 "x = makestr(23456);");
5851 v8::Handle<Value> value = CompileRun(
5852 "var o = new constructor();"
5853 "o.__proto__ = new String(x);"
5854 "o.hasOwnProperty('ostehaps');");
5855 CHECK_EQ(false, value->BooleanValue());
5856}
5857
5858
5859typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5860 const AccessorInfo& info);
5861
5862
5863static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5864 const char* source,
5865 int expected) {
5866 v8::HandleScope scope;
5867 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5868 templ->SetNamedPropertyHandler(getter);
5869 LocalContext context;
5870 context->Global()->Set(v8_str("o"), templ->NewInstance());
5871 v8::Handle<Value> value = CompileRun(source);
5872 CHECK_EQ(expected, value->Int32Value());
5873}
5874
5875
5876static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5877 const AccessorInfo& info) {
5878 ApiTestFuzzer::Fuzz();
5879 CHECK(v8_str("x")->Equals(name));
5880 return v8::Integer::New(42);
5881}
5882
5883
5884// This test should hit the load IC for the interceptor case.
5885THREADED_TEST(InterceptorLoadIC) {
5886 CheckInterceptorLoadIC(InterceptorLoadICGetter,
5887 "var result = 0;"
5888 "for (var i = 0; i < 1000; i++) {"
5889 " result = o.x;"
5890 "}",
5891 42);
5892}
5893
5894
5895// Below go several tests which verify that JITing for various
5896// configurations of interceptor and explicit fields works fine
5897// (those cases are special cased to get better performance).
5898
5899static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5900 const AccessorInfo& info) {
5901 ApiTestFuzzer::Fuzz();
5902 return v8_str("x")->Equals(name)
5903 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5904}
5905
5906
5907THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5908 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5909 "var result = 0;"
5910 "o.y = 239;"
5911 "for (var i = 0; i < 1000; i++) {"
5912 " result = o.y;"
5913 "}",
5914 239);
5915}
5916
5917
5918THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5919 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5920 "var result = 0;"
5921 "o.__proto__ = { 'y': 239 };"
5922 "for (var i = 0; i < 1000; i++) {"
5923 " result = o.y + o.x;"
5924 "}",
5925 239 + 42);
5926}
5927
5928
5929THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5930 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5931 "var result = 0;"
5932 "o.__proto__.y = 239;"
5933 "for (var i = 0; i < 1000; i++) {"
5934 " result = o.y + o.x;"
5935 "}",
5936 239 + 42);
5937}
5938
5939
5940THREADED_TEST(InterceptorLoadICUndefined) {
5941 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5942 "var result = 0;"
5943 "for (var i = 0; i < 1000; i++) {"
5944 " result = (o.y == undefined) ? 239 : 42;"
5945 "}",
5946 239);
5947}
5948
5949
5950THREADED_TEST(InterceptorLoadICWithOverride) {
5951 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5952 "fst = new Object(); fst.__proto__ = o;"
5953 "snd = new Object(); snd.__proto__ = fst;"
5954 "var result1 = 0;"
5955 "for (var i = 0; i < 1000; i++) {"
5956 " result1 = snd.x;"
5957 "}"
5958 "fst.x = 239;"
5959 "var result = 0;"
5960 "for (var i = 0; i < 1000; i++) {"
5961 " result = snd.x;"
5962 "}"
5963 "result + result1",
5964 239 + 42);
5965}
5966
5967
5968// Test the case when we stored field into
5969// a stub, but interceptor produced value on its own.
5970THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5971 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5972 "proto = new Object();"
5973 "o.__proto__ = proto;"
5974 "proto.x = 239;"
5975 "for (var i = 0; i < 1000; i++) {"
5976 " o.x;"
5977 // Now it should be ICed and keep a reference to x defined on proto
5978 "}"
5979 "var result = 0;"
5980 "for (var i = 0; i < 1000; i++) {"
5981 " result += o.x;"
5982 "}"
5983 "result;",
5984 42 * 1000);
5985}
5986
5987
5988// Test the case when we stored field into
5989// a stub, but it got invalidated later on.
5990THREADED_TEST(InterceptorLoadICInvalidatedField) {
5991 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5992 "proto1 = new Object();"
5993 "proto2 = new Object();"
5994 "o.__proto__ = proto1;"
5995 "proto1.__proto__ = proto2;"
5996 "proto2.y = 239;"
5997 "for (var i = 0; i < 1000; i++) {"
5998 " o.y;"
5999 // Now it should be ICed and keep a reference to y defined on proto2
6000 "}"
6001 "proto1.y = 42;"
6002 "var result = 0;"
6003 "for (var i = 0; i < 1000; i++) {"
6004 " result += o.y;"
6005 "}"
6006 "result;",
6007 42 * 1000);
6008}
6009
6010
Steve Block6ded16b2010-05-10 14:33:55 +01006011static int interceptor_load_not_handled_calls = 0;
6012static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6013 const AccessorInfo& info) {
6014 ++interceptor_load_not_handled_calls;
6015 return v8::Handle<v8::Value>();
6016}
6017
6018
6019// Test how post-interceptor lookups are done in the non-cacheable
6020// case: the interceptor should not be invoked during this lookup.
6021THREADED_TEST(InterceptorLoadICPostInterceptor) {
6022 interceptor_load_not_handled_calls = 0;
6023 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6024 "receiver = new Object();"
6025 "receiver.__proto__ = o;"
6026 "proto = new Object();"
6027 "/* Make proto a slow-case object. */"
6028 "for (var i = 0; i < 1000; i++) {"
6029 " proto[\"xxxxxxxx\" + i] = [];"
6030 "}"
6031 "proto.x = 17;"
6032 "o.__proto__ = proto;"
6033 "var result = 0;"
6034 "for (var i = 0; i < 1000; i++) {"
6035 " result += receiver.x;"
6036 "}"
6037 "result;",
6038 17 * 1000);
6039 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6040}
6041
6042
Steve Blocka7e24c12009-10-30 11:49:00 +00006043// Test the case when we stored field into
6044// a stub, but it got invalidated later on due to override on
6045// global object which is between interceptor and fields' holders.
6046THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6047 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6048 "o.__proto__ = this;" // set a global to be a proto of o.
6049 "this.__proto__.y = 239;"
6050 "for (var i = 0; i < 10; i++) {"
6051 " if (o.y != 239) throw 'oops: ' + o.y;"
6052 // Now it should be ICed and keep a reference to y defined on field_holder.
6053 "}"
6054 "this.y = 42;" // Assign on a global.
6055 "var result = 0;"
6056 "for (var i = 0; i < 10; i++) {"
6057 " result += o.y;"
6058 "}"
6059 "result;",
6060 42 * 10);
6061}
6062
6063
6064static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6065 ApiTestFuzzer::Fuzz();
6066 return v8_num(239);
6067}
6068
6069
6070static void SetOnThis(Local<String> name,
6071 Local<Value> value,
6072 const AccessorInfo& info) {
6073 info.This()->ForceSet(name, value);
6074}
6075
6076
6077THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6078 v8::HandleScope scope;
6079 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6080 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6081 templ->SetAccessor(v8_str("y"), Return239);
6082 LocalContext context;
6083 context->Global()->Set(v8_str("o"), templ->NewInstance());
6084 v8::Handle<Value> value = CompileRun(
6085 "var result = 0;"
6086 "for (var i = 0; i < 7; i++) {"
6087 " result = o.y;"
6088 "}");
6089 CHECK_EQ(239, value->Int32Value());
6090}
6091
6092
6093THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6094 v8::HandleScope scope;
6095 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6096 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6097 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6098 templ_p->SetAccessor(v8_str("y"), Return239);
6099
6100 LocalContext context;
6101 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6102 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6103
6104 v8::Handle<Value> value = CompileRun(
6105 "o.__proto__ = p;"
6106 "var result = 0;"
6107 "for (var i = 0; i < 7; i++) {"
6108 " result = o.x + o.y;"
6109 "}");
6110 CHECK_EQ(239 + 42, value->Int32Value());
6111}
6112
6113
6114THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6115 v8::HandleScope scope;
6116 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6117 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6118 templ->SetAccessor(v8_str("y"), Return239);
6119
6120 LocalContext context;
6121 context->Global()->Set(v8_str("o"), templ->NewInstance());
6122
6123 v8::Handle<Value> value = CompileRun(
6124 "fst = new Object(); fst.__proto__ = o;"
6125 "snd = new Object(); snd.__proto__ = fst;"
6126 "var result1 = 0;"
6127 "for (var i = 0; i < 7; i++) {"
6128 " result1 = snd.x;"
6129 "}"
6130 "fst.x = 239;"
6131 "var result = 0;"
6132 "for (var i = 0; i < 7; i++) {"
6133 " result = snd.x;"
6134 "}"
6135 "result + result1");
6136 CHECK_EQ(239 + 42, value->Int32Value());
6137}
6138
6139
6140// Test the case when we stored callback into
6141// a stub, but interceptor produced value on its own.
6142THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6143 v8::HandleScope scope;
6144 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6145 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6146 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6147 templ_p->SetAccessor(v8_str("y"), Return239);
6148
6149 LocalContext context;
6150 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6151 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6152
6153 v8::Handle<Value> value = CompileRun(
6154 "o.__proto__ = p;"
6155 "for (var i = 0; i < 7; i++) {"
6156 " o.x;"
6157 // Now it should be ICed and keep a reference to x defined on p
6158 "}"
6159 "var result = 0;"
6160 "for (var i = 0; i < 7; i++) {"
6161 " result += o.x;"
6162 "}"
6163 "result");
6164 CHECK_EQ(42 * 7, value->Int32Value());
6165}
6166
6167
6168// Test the case when we stored callback into
6169// a stub, but it got invalidated later on.
6170THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6171 v8::HandleScope scope;
6172 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6173 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6174 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6175 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6176
6177 LocalContext context;
6178 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6179 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6180
6181 v8::Handle<Value> value = CompileRun(
6182 "inbetween = new Object();"
6183 "o.__proto__ = inbetween;"
6184 "inbetween.__proto__ = p;"
6185 "for (var i = 0; i < 10; i++) {"
6186 " o.y;"
6187 // Now it should be ICed and keep a reference to y defined on p
6188 "}"
6189 "inbetween.y = 42;"
6190 "var result = 0;"
6191 "for (var i = 0; i < 10; i++) {"
6192 " result += o.y;"
6193 "}"
6194 "result");
6195 CHECK_EQ(42 * 10, value->Int32Value());
6196}
6197
6198
6199// Test the case when we stored callback into
6200// a stub, but it got invalidated later on due to override on
6201// global object which is between interceptor and callbacks' holders.
6202THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6203 v8::HandleScope scope;
6204 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6205 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6206 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6207 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6208
6209 LocalContext context;
6210 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6211 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6212
6213 v8::Handle<Value> value = CompileRun(
6214 "o.__proto__ = this;"
6215 "this.__proto__ = p;"
6216 "for (var i = 0; i < 10; i++) {"
6217 " if (o.y != 239) throw 'oops: ' + o.y;"
6218 // Now it should be ICed and keep a reference to y defined on p
6219 "}"
6220 "this.y = 42;"
6221 "var result = 0;"
6222 "for (var i = 0; i < 10; i++) {"
6223 " result += o.y;"
6224 "}"
6225 "result");
6226 CHECK_EQ(42 * 10, value->Int32Value());
6227}
6228
6229
6230static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6231 const AccessorInfo& info) {
6232 ApiTestFuzzer::Fuzz();
6233 CHECK(v8_str("x")->Equals(name));
6234 return v8::Integer::New(0);
6235}
6236
6237
6238THREADED_TEST(InterceptorReturningZero) {
6239 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6240 "o.x == undefined ? 1 : 0",
6241 0);
6242}
6243
6244
6245static v8::Handle<Value> InterceptorStoreICSetter(
6246 Local<String> key, Local<Value> value, const AccessorInfo&) {
6247 CHECK(v8_str("x")->Equals(key));
6248 CHECK_EQ(42, value->Int32Value());
6249 return value;
6250}
6251
6252
6253// This test should hit the store IC for the interceptor case.
6254THREADED_TEST(InterceptorStoreIC) {
6255 v8::HandleScope scope;
6256 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6257 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6258 InterceptorStoreICSetter);
6259 LocalContext context;
6260 context->Global()->Set(v8_str("o"), templ->NewInstance());
6261 v8::Handle<Value> value = CompileRun(
6262 "for (var i = 0; i < 1000; i++) {"
6263 " o.x = 42;"
6264 "}");
6265}
6266
6267
6268THREADED_TEST(InterceptorStoreICWithNoSetter) {
6269 v8::HandleScope scope;
6270 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6271 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6272 LocalContext context;
6273 context->Global()->Set(v8_str("o"), templ->NewInstance());
6274 v8::Handle<Value> value = CompileRun(
6275 "for (var i = 0; i < 1000; i++) {"
6276 " o.y = 239;"
6277 "}"
6278 "42 + o.y");
6279 CHECK_EQ(239 + 42, value->Int32Value());
6280}
6281
6282
6283
6284
6285v8::Handle<Value> call_ic_function;
6286v8::Handle<Value> call_ic_function2;
6287v8::Handle<Value> call_ic_function3;
6288
6289static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6290 const AccessorInfo& info) {
6291 ApiTestFuzzer::Fuzz();
6292 CHECK(v8_str("x")->Equals(name));
6293 return call_ic_function;
6294}
6295
6296
6297// This test should hit the call IC for the interceptor case.
6298THREADED_TEST(InterceptorCallIC) {
6299 v8::HandleScope scope;
6300 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6301 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6302 LocalContext context;
6303 context->Global()->Set(v8_str("o"), templ->NewInstance());
6304 call_ic_function =
6305 v8_compile("function f(x) { return x + 1; }; f")->Run();
6306 v8::Handle<Value> value = CompileRun(
6307 "var result = 0;"
6308 "for (var i = 0; i < 1000; i++) {"
6309 " result = o.x(41);"
6310 "}");
6311 CHECK_EQ(42, value->Int32Value());
6312}
6313
6314
6315// This test checks that if interceptor doesn't provide
6316// a value, we can fetch regular value.
6317THREADED_TEST(InterceptorCallICSeesOthers) {
6318 v8::HandleScope scope;
6319 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6320 templ->SetNamedPropertyHandler(NoBlockGetterX);
6321 LocalContext context;
6322 context->Global()->Set(v8_str("o"), templ->NewInstance());
6323 v8::Handle<Value> value = CompileRun(
6324 "o.x = function f(x) { return x + 1; };"
6325 "var result = 0;"
6326 "for (var i = 0; i < 7; i++) {"
6327 " result = o.x(41);"
6328 "}");
6329 CHECK_EQ(42, value->Int32Value());
6330}
6331
6332
6333static v8::Handle<Value> call_ic_function4;
6334static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6335 const AccessorInfo& info) {
6336 ApiTestFuzzer::Fuzz();
6337 CHECK(v8_str("x")->Equals(name));
6338 return call_ic_function4;
6339}
6340
6341
6342// This test checks that if interceptor provides a function,
6343// even if we cached shadowed variant, interceptor's function
6344// is invoked
6345THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6346 v8::HandleScope scope;
6347 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6348 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6349 LocalContext context;
6350 context->Global()->Set(v8_str("o"), templ->NewInstance());
6351 call_ic_function4 =
6352 v8_compile("function f(x) { return x - 1; }; f")->Run();
6353 v8::Handle<Value> value = CompileRun(
6354 "o.__proto__.x = function(x) { return x + 1; };"
6355 "var result = 0;"
6356 "for (var i = 0; i < 1000; i++) {"
6357 " result = o.x(42);"
6358 "}");
6359 CHECK_EQ(41, value->Int32Value());
6360}
6361
6362
6363// Test the case when we stored cacheable lookup into
6364// a stub, but it got invalidated later on
6365THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6366 v8::HandleScope scope;
6367 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6368 templ->SetNamedPropertyHandler(NoBlockGetterX);
6369 LocalContext context;
6370 context->Global()->Set(v8_str("o"), templ->NewInstance());
6371 v8::Handle<Value> value = CompileRun(
6372 "proto1 = new Object();"
6373 "proto2 = new Object();"
6374 "o.__proto__ = proto1;"
6375 "proto1.__proto__ = proto2;"
6376 "proto2.y = function(x) { return x + 1; };"
6377 // Invoke it many times to compile a stub
6378 "for (var i = 0; i < 7; i++) {"
6379 " o.y(42);"
6380 "}"
6381 "proto1.y = function(x) { return x - 1; };"
6382 "var result = 0;"
6383 "for (var i = 0; i < 7; i++) {"
6384 " result += o.y(42);"
6385 "}");
6386 CHECK_EQ(41 * 7, value->Int32Value());
6387}
6388
6389
6390static v8::Handle<Value> call_ic_function5;
6391static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6392 const AccessorInfo& info) {
6393 ApiTestFuzzer::Fuzz();
6394 if (v8_str("x")->Equals(name))
6395 return call_ic_function5;
6396 else
6397 return Local<Value>();
6398}
6399
6400
6401// This test checks that if interceptor doesn't provide a function,
6402// cached constant function is used
6403THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6404 v8::HandleScope scope;
6405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6406 templ->SetNamedPropertyHandler(NoBlockGetterX);
6407 LocalContext context;
6408 context->Global()->Set(v8_str("o"), templ->NewInstance());
6409 v8::Handle<Value> value = CompileRun(
6410 "function inc(x) { return x + 1; };"
6411 "inc(1);"
6412 "o.x = inc;"
6413 "var result = 0;"
6414 "for (var i = 0; i < 1000; i++) {"
6415 " result = o.x(42);"
6416 "}");
6417 CHECK_EQ(43, value->Int32Value());
6418}
6419
6420
6421// This test checks that if interceptor provides a function,
6422// even if we cached constant function, interceptor's function
6423// is invoked
6424THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6425 v8::HandleScope scope;
6426 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6427 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6428 LocalContext context;
6429 context->Global()->Set(v8_str("o"), templ->NewInstance());
6430 call_ic_function5 =
6431 v8_compile("function f(x) { return x - 1; }; f")->Run();
6432 v8::Handle<Value> value = CompileRun(
6433 "function inc(x) { return x + 1; };"
6434 "inc(1);"
6435 "o.x = inc;"
6436 "var result = 0;"
6437 "for (var i = 0; i < 1000; i++) {"
6438 " result = o.x(42);"
6439 "}");
6440 CHECK_EQ(41, value->Int32Value());
6441}
6442
6443
6444// Test the case when we stored constant function into
6445// a stub, but it got invalidated later on
6446THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6447 v8::HandleScope scope;
6448 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6449 templ->SetNamedPropertyHandler(NoBlockGetterX);
6450 LocalContext context;
6451 context->Global()->Set(v8_str("o"), templ->NewInstance());
6452 v8::Handle<Value> value = CompileRun(
6453 "function inc(x) { return x + 1; };"
6454 "inc(1);"
6455 "proto1 = new Object();"
6456 "proto2 = new Object();"
6457 "o.__proto__ = proto1;"
6458 "proto1.__proto__ = proto2;"
6459 "proto2.y = inc;"
6460 // Invoke it many times to compile a stub
6461 "for (var i = 0; i < 7; i++) {"
6462 " o.y(42);"
6463 "}"
6464 "proto1.y = function(x) { return x - 1; };"
6465 "var result = 0;"
6466 "for (var i = 0; i < 7; i++) {"
6467 " result += o.y(42);"
6468 "}");
6469 CHECK_EQ(41 * 7, value->Int32Value());
6470}
6471
6472
6473// Test the case when we stored constant function into
6474// a stub, but it got invalidated later on due to override on
6475// global object which is between interceptor and constant function' holders.
6476THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6477 v8::HandleScope scope;
6478 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6479 templ->SetNamedPropertyHandler(NoBlockGetterX);
6480 LocalContext context;
6481 context->Global()->Set(v8_str("o"), templ->NewInstance());
6482 v8::Handle<Value> value = CompileRun(
6483 "function inc(x) { return x + 1; };"
6484 "inc(1);"
6485 "o.__proto__ = this;"
6486 "this.__proto__.y = inc;"
6487 // Invoke it many times to compile a stub
6488 "for (var i = 0; i < 7; i++) {"
6489 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6490 "}"
6491 "this.y = function(x) { return x - 1; };"
6492 "var result = 0;"
6493 "for (var i = 0; i < 7; i++) {"
6494 " result += o.y(42);"
6495 "}");
6496 CHECK_EQ(41 * 7, value->Int32Value());
6497}
6498
6499
Leon Clarke4515c472010-02-03 11:58:03 +00006500// Test the case when actual function to call sits on global object.
6501THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6502 v8::HandleScope scope;
6503 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6504 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6505
6506 LocalContext context;
6507 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6508
6509 v8::Handle<Value> value = CompileRun(
6510 "try {"
6511 " o.__proto__ = this;"
6512 " for (var i = 0; i < 10; i++) {"
6513 " var v = o.parseFloat('239');"
6514 " if (v != 239) throw v;"
6515 // Now it should be ICed and keep a reference to parseFloat.
6516 " }"
6517 " var result = 0;"
6518 " for (var i = 0; i < 10; i++) {"
6519 " result += o.parseFloat('239');"
6520 " }"
6521 " result"
6522 "} catch(e) {"
6523 " e"
6524 "};");
6525 CHECK_EQ(239 * 10, value->Int32Value());
6526}
6527
Andrei Popescu402d9372010-02-26 13:31:12 +00006528static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6529 const AccessorInfo& info) {
6530 ApiTestFuzzer::Fuzz();
6531 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6532 ++(*call_count);
6533 if ((*call_count) % 20 == 0) {
6534 v8::internal::Heap::CollectAllGarbage(true);
6535 }
6536 return v8::Handle<Value>();
6537}
6538
6539static v8::Handle<Value> FastApiCallback_TrivialSignature(
6540 const v8::Arguments& args) {
6541 ApiTestFuzzer::Fuzz();
6542 CHECK_EQ(args.This(), args.Holder());
6543 CHECK(args.Data()->Equals(v8_str("method_data")));
6544 return v8::Integer::New(args[0]->Int32Value() + 1);
6545}
6546
6547static v8::Handle<Value> FastApiCallback_SimpleSignature(
6548 const v8::Arguments& args) {
6549 ApiTestFuzzer::Fuzz();
6550 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6551 CHECK(args.Data()->Equals(v8_str("method_data")));
6552 // Note, we're using HasRealNamedProperty instead of Has to avoid
6553 // invoking the interceptor again.
6554 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6555 return v8::Integer::New(args[0]->Int32Value() + 1);
6556}
6557
6558// Helper to maximize the odds of object moving.
6559static void GenerateSomeGarbage() {
6560 CompileRun(
6561 "var garbage;"
6562 "for (var i = 0; i < 1000; i++) {"
6563 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6564 "}"
6565 "garbage = undefined;");
6566}
6567
6568THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6569 int interceptor_call_count = 0;
6570 v8::HandleScope scope;
6571 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6572 v8::Handle<v8::FunctionTemplate> method_templ =
6573 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6574 v8_str("method_data"),
6575 v8::Handle<v8::Signature>());
6576 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6577 proto_templ->Set(v8_str("method"), method_templ);
6578 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6579 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6580 NULL, NULL, NULL, NULL,
6581 v8::External::Wrap(&interceptor_call_count));
6582 LocalContext context;
6583 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6584 GenerateSomeGarbage();
6585 context->Global()->Set(v8_str("o"), fun->NewInstance());
6586 v8::Handle<Value> value = CompileRun(
6587 "var result = 0;"
6588 "for (var i = 0; i < 100; i++) {"
6589 " result = o.method(41);"
6590 "}");
6591 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6592 CHECK_EQ(100, interceptor_call_count);
6593}
6594
6595THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6596 int interceptor_call_count = 0;
6597 v8::HandleScope scope;
6598 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6599 v8::Handle<v8::FunctionTemplate> method_templ =
6600 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6601 v8_str("method_data"),
6602 v8::Signature::New(fun_templ));
6603 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6604 proto_templ->Set(v8_str("method"), method_templ);
6605 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6606 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6607 NULL, NULL, NULL, NULL,
6608 v8::External::Wrap(&interceptor_call_count));
6609 LocalContext context;
6610 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6611 GenerateSomeGarbage();
6612 context->Global()->Set(v8_str("o"), fun->NewInstance());
6613 v8::Handle<Value> value = CompileRun(
6614 "o.foo = 17;"
6615 "var receiver = {};"
6616 "receiver.__proto__ = o;"
6617 "var result = 0;"
6618 "for (var i = 0; i < 100; i++) {"
6619 " result = receiver.method(41);"
6620 "}");
6621 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6622 CHECK_EQ(100, interceptor_call_count);
6623}
6624
6625THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6626 int interceptor_call_count = 0;
6627 v8::HandleScope scope;
6628 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6629 v8::Handle<v8::FunctionTemplate> method_templ =
6630 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6631 v8_str("method_data"),
6632 v8::Signature::New(fun_templ));
6633 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6634 proto_templ->Set(v8_str("method"), method_templ);
6635 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6636 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6637 NULL, NULL, NULL, NULL,
6638 v8::External::Wrap(&interceptor_call_count));
6639 LocalContext context;
6640 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6641 GenerateSomeGarbage();
6642 context->Global()->Set(v8_str("o"), fun->NewInstance());
6643 v8::Handle<Value> value = CompileRun(
6644 "o.foo = 17;"
6645 "var receiver = {};"
6646 "receiver.__proto__ = o;"
6647 "var result = 0;"
6648 "var saved_result = 0;"
6649 "for (var i = 0; i < 100; i++) {"
6650 " result = receiver.method(41);"
6651 " if (i == 50) {"
6652 " saved_result = result;"
6653 " receiver = {method: function(x) { return x - 1 }};"
6654 " }"
6655 "}");
6656 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6657 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6658 CHECK_GE(interceptor_call_count, 50);
6659}
6660
6661THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6662 int interceptor_call_count = 0;
6663 v8::HandleScope scope;
6664 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6665 v8::Handle<v8::FunctionTemplate> method_templ =
6666 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6667 v8_str("method_data"),
6668 v8::Signature::New(fun_templ));
6669 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6670 proto_templ->Set(v8_str("method"), method_templ);
6671 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6672 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6673 NULL, NULL, NULL, NULL,
6674 v8::External::Wrap(&interceptor_call_count));
6675 LocalContext context;
6676 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6677 GenerateSomeGarbage();
6678 context->Global()->Set(v8_str("o"), fun->NewInstance());
6679 v8::Handle<Value> value = CompileRun(
6680 "o.foo = 17;"
6681 "var receiver = {};"
6682 "receiver.__proto__ = o;"
6683 "var result = 0;"
6684 "var saved_result = 0;"
6685 "for (var i = 0; i < 100; i++) {"
6686 " result = receiver.method(41);"
6687 " if (i == 50) {"
6688 " saved_result = result;"
6689 " o.method = function(x) { return x - 1 };"
6690 " }"
6691 "}");
6692 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6693 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6694 CHECK_GE(interceptor_call_count, 50);
6695}
6696
Steve Block6ded16b2010-05-10 14:33:55 +01006697THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
6698 int interceptor_call_count = 0;
6699 v8::HandleScope scope;
6700 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6701 v8::Handle<v8::FunctionTemplate> method_templ =
6702 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6703 v8_str("method_data"),
6704 v8::Signature::New(fun_templ));
6705 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6706 proto_templ->Set(v8_str("method"), method_templ);
6707 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6708 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6709 NULL, NULL, NULL, NULL,
6710 v8::External::Wrap(&interceptor_call_count));
6711 LocalContext context;
6712 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6713 GenerateSomeGarbage();
6714 context->Global()->Set(v8_str("o"), fun->NewInstance());
6715 v8::TryCatch try_catch;
6716 v8::Handle<Value> value = CompileRun(
6717 "o.foo = 17;"
6718 "var receiver = {};"
6719 "receiver.__proto__ = o;"
6720 "var result = 0;"
6721 "var saved_result = 0;"
6722 "for (var i = 0; i < 100; i++) {"
6723 " result = receiver.method(41);"
6724 " if (i == 50) {"
6725 " saved_result = result;"
6726 " receiver = 333;"
6727 " }"
6728 "}");
6729 CHECK(try_catch.HasCaught());
6730 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6731 try_catch.Exception()->ToString());
6732 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6733 CHECK_GE(interceptor_call_count, 50);
6734}
6735
Andrei Popescu402d9372010-02-26 13:31:12 +00006736THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6737 int interceptor_call_count = 0;
6738 v8::HandleScope scope;
6739 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6740 v8::Handle<v8::FunctionTemplate> method_templ =
6741 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6742 v8_str("method_data"),
6743 v8::Signature::New(fun_templ));
6744 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6745 proto_templ->Set(v8_str("method"), method_templ);
6746 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6747 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6748 NULL, NULL, NULL, NULL,
6749 v8::External::Wrap(&interceptor_call_count));
6750 LocalContext context;
6751 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6752 GenerateSomeGarbage();
6753 context->Global()->Set(v8_str("o"), fun->NewInstance());
6754 v8::TryCatch try_catch;
6755 v8::Handle<Value> value = CompileRun(
6756 "o.foo = 17;"
6757 "var receiver = {};"
6758 "receiver.__proto__ = o;"
6759 "var result = 0;"
6760 "var saved_result = 0;"
6761 "for (var i = 0; i < 100; i++) {"
6762 " result = receiver.method(41);"
6763 " if (i == 50) {"
6764 " saved_result = result;"
6765 " receiver = {method: receiver.method};"
6766 " }"
6767 "}");
6768 CHECK(try_catch.HasCaught());
6769 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
6770 try_catch.Exception()->ToString());
6771 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6772 CHECK_GE(interceptor_call_count, 50);
6773}
6774
6775THREADED_TEST(CallICFastApi_TrivialSignature) {
6776 v8::HandleScope scope;
6777 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6778 v8::Handle<v8::FunctionTemplate> method_templ =
6779 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6780 v8_str("method_data"),
6781 v8::Handle<v8::Signature>());
6782 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6783 proto_templ->Set(v8_str("method"), method_templ);
6784 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6785 LocalContext context;
6786 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6787 GenerateSomeGarbage();
6788 context->Global()->Set(v8_str("o"), fun->NewInstance());
6789 v8::Handle<Value> value = CompileRun(
6790 "var result = 0;"
6791 "for (var i = 0; i < 100; i++) {"
6792 " result = o.method(41);"
6793 "}");
6794
6795 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6796}
6797
6798THREADED_TEST(CallICFastApi_SimpleSignature) {
6799 v8::HandleScope scope;
6800 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6801 v8::Handle<v8::FunctionTemplate> method_templ =
6802 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6803 v8_str("method_data"),
6804 v8::Signature::New(fun_templ));
6805 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6806 proto_templ->Set(v8_str("method"), method_templ);
6807 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6808 LocalContext context;
6809 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6810 GenerateSomeGarbage();
6811 context->Global()->Set(v8_str("o"), fun->NewInstance());
6812 v8::Handle<Value> value = CompileRun(
6813 "o.foo = 17;"
6814 "var receiver = {};"
6815 "receiver.__proto__ = o;"
6816 "var result = 0;"
6817 "for (var i = 0; i < 100; i++) {"
6818 " result = receiver.method(41);"
6819 "}");
6820
6821 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6822}
6823
Steve Block6ded16b2010-05-10 14:33:55 +01006824THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006825 v8::HandleScope scope;
6826 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6827 v8::Handle<v8::FunctionTemplate> method_templ =
6828 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6829 v8_str("method_data"),
6830 v8::Signature::New(fun_templ));
6831 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6832 proto_templ->Set(v8_str("method"), method_templ);
6833 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6834 LocalContext context;
6835 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6836 GenerateSomeGarbage();
6837 context->Global()->Set(v8_str("o"), fun->NewInstance());
6838 v8::Handle<Value> value = CompileRun(
6839 "o.foo = 17;"
6840 "var receiver = {};"
6841 "receiver.__proto__ = o;"
6842 "var result = 0;"
6843 "var saved_result = 0;"
6844 "for (var i = 0; i < 100; i++) {"
6845 " result = receiver.method(41);"
6846 " if (i == 50) {"
6847 " saved_result = result;"
6848 " receiver = {method: function(x) { return x - 1 }};"
6849 " }"
6850 "}");
6851 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6852 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6853}
6854
Steve Block6ded16b2010-05-10 14:33:55 +01006855THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
6856 v8::HandleScope scope;
6857 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6858 v8::Handle<v8::FunctionTemplate> method_templ =
6859 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6860 v8_str("method_data"),
6861 v8::Signature::New(fun_templ));
6862 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6863 proto_templ->Set(v8_str("method"), method_templ);
6864 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6865 LocalContext context;
6866 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6867 GenerateSomeGarbage();
6868 context->Global()->Set(v8_str("o"), fun->NewInstance());
6869 v8::TryCatch try_catch;
6870 v8::Handle<Value> value = CompileRun(
6871 "o.foo = 17;"
6872 "var receiver = {};"
6873 "receiver.__proto__ = o;"
6874 "var result = 0;"
6875 "var saved_result = 0;"
6876 "for (var i = 0; i < 100; i++) {"
6877 " result = receiver.method(41);"
6878 " if (i == 50) {"
6879 " saved_result = result;"
6880 " receiver = 333;"
6881 " }"
6882 "}");
6883 CHECK(try_catch.HasCaught());
6884 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6885 try_catch.Exception()->ToString());
6886 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6887}
6888
Leon Clarke4515c472010-02-03 11:58:03 +00006889
Steve Blocka7e24c12009-10-30 11:49:00 +00006890static int interceptor_call_count = 0;
6891
6892static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
6893 const AccessorInfo& info) {
6894 ApiTestFuzzer::Fuzz();
6895 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
6896 return call_ic_function2;
6897 }
6898 return v8::Handle<Value>();
6899}
6900
6901
6902// This test should hit load and call ICs for the interceptor case.
6903// Once in a while, the interceptor will reply that a property was not
6904// found in which case we should get a reference error.
6905THREADED_TEST(InterceptorICReferenceErrors) {
6906 v8::HandleScope scope;
6907 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6908 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
6909 LocalContext context(0, templ, v8::Handle<Value>());
6910 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
6911 v8::Handle<Value> value = CompileRun(
6912 "function f() {"
6913 " for (var i = 0; i < 1000; i++) {"
6914 " try { x; } catch(e) { return true; }"
6915 " }"
6916 " return false;"
6917 "};"
6918 "f();");
6919 CHECK_EQ(true, value->BooleanValue());
6920 interceptor_call_count = 0;
6921 value = CompileRun(
6922 "function g() {"
6923 " for (var i = 0; i < 1000; i++) {"
6924 " try { x(42); } catch(e) { return true; }"
6925 " }"
6926 " return false;"
6927 "};"
6928 "g();");
6929 CHECK_EQ(true, value->BooleanValue());
6930}
6931
6932
6933static int interceptor_ic_exception_get_count = 0;
6934
6935static v8::Handle<Value> InterceptorICExceptionGetter(
6936 Local<String> name,
6937 const AccessorInfo& info) {
6938 ApiTestFuzzer::Fuzz();
6939 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
6940 return call_ic_function3;
6941 }
6942 if (interceptor_ic_exception_get_count == 20) {
6943 return v8::ThrowException(v8_num(42));
6944 }
6945 // Do not handle get for properties other than x.
6946 return v8::Handle<Value>();
6947}
6948
6949// Test interceptor load/call IC where the interceptor throws an
6950// exception once in a while.
6951THREADED_TEST(InterceptorICGetterExceptions) {
6952 interceptor_ic_exception_get_count = 0;
6953 v8::HandleScope scope;
6954 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6955 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
6956 LocalContext context(0, templ, v8::Handle<Value>());
6957 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
6958 v8::Handle<Value> value = CompileRun(
6959 "function f() {"
6960 " for (var i = 0; i < 100; i++) {"
6961 " try { x; } catch(e) { return true; }"
6962 " }"
6963 " return false;"
6964 "};"
6965 "f();");
6966 CHECK_EQ(true, value->BooleanValue());
6967 interceptor_ic_exception_get_count = 0;
6968 value = CompileRun(
6969 "function f() {"
6970 " for (var i = 0; i < 100; i++) {"
6971 " try { x(42); } catch(e) { return true; }"
6972 " }"
6973 " return false;"
6974 "};"
6975 "f();");
6976 CHECK_EQ(true, value->BooleanValue());
6977}
6978
6979
6980static int interceptor_ic_exception_set_count = 0;
6981
6982static v8::Handle<Value> InterceptorICExceptionSetter(
6983 Local<String> key, Local<Value> value, const AccessorInfo&) {
6984 ApiTestFuzzer::Fuzz();
6985 if (++interceptor_ic_exception_set_count > 20) {
6986 return v8::ThrowException(v8_num(42));
6987 }
6988 // Do not actually handle setting.
6989 return v8::Handle<Value>();
6990}
6991
6992// Test interceptor store IC where the interceptor throws an exception
6993// once in a while.
6994THREADED_TEST(InterceptorICSetterExceptions) {
6995 interceptor_ic_exception_set_count = 0;
6996 v8::HandleScope scope;
6997 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6998 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
6999 LocalContext context(0, templ, v8::Handle<Value>());
7000 v8::Handle<Value> value = CompileRun(
7001 "function f() {"
7002 " for (var i = 0; i < 100; i++) {"
7003 " try { x = 42; } catch(e) { return true; }"
7004 " }"
7005 " return false;"
7006 "};"
7007 "f();");
7008 CHECK_EQ(true, value->BooleanValue());
7009}
7010
7011
7012// Test that we ignore null interceptors.
7013THREADED_TEST(NullNamedInterceptor) {
7014 v8::HandleScope scope;
7015 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7016 templ->SetNamedPropertyHandler(0);
7017 LocalContext context;
7018 templ->Set("x", v8_num(42));
7019 v8::Handle<v8::Object> obj = templ->NewInstance();
7020 context->Global()->Set(v8_str("obj"), obj);
7021 v8::Handle<Value> value = CompileRun("obj.x");
7022 CHECK(value->IsInt32());
7023 CHECK_EQ(42, value->Int32Value());
7024}
7025
7026
7027// Test that we ignore null interceptors.
7028THREADED_TEST(NullIndexedInterceptor) {
7029 v8::HandleScope scope;
7030 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7031 templ->SetIndexedPropertyHandler(0);
7032 LocalContext context;
7033 templ->Set("42", v8_num(42));
7034 v8::Handle<v8::Object> obj = templ->NewInstance();
7035 context->Global()->Set(v8_str("obj"), obj);
7036 v8::Handle<Value> value = CompileRun("obj[42]");
7037 CHECK(value->IsInt32());
7038 CHECK_EQ(42, value->Int32Value());
7039}
7040
7041
7042static v8::Handle<Value> ParentGetter(Local<String> name,
7043 const AccessorInfo& info) {
7044 ApiTestFuzzer::Fuzz();
7045 return v8_num(1);
7046}
7047
7048
7049static v8::Handle<Value> ChildGetter(Local<String> name,
7050 const AccessorInfo& info) {
7051 ApiTestFuzzer::Fuzz();
7052 return v8_num(42);
7053}
7054
7055
7056THREADED_TEST(Overriding) {
7057 v8::HandleScope scope;
7058 LocalContext context;
7059
7060 // Parent template.
7061 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7062 Local<ObjectTemplate> parent_instance_templ =
7063 parent_templ->InstanceTemplate();
7064 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7065
7066 // Template that inherits from the parent template.
7067 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7068 Local<ObjectTemplate> child_instance_templ =
7069 child_templ->InstanceTemplate();
7070 child_templ->Inherit(parent_templ);
7071 // Override 'f'. The child version of 'f' should get called for child
7072 // instances.
7073 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7074 // Add 'g' twice. The 'g' added last should get called for instances.
7075 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7076 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7077
7078 // Add 'h' as an accessor to the proto template with ReadOnly attributes
7079 // so 'h' can be shadowed on the instance object.
7080 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7081 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7082 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7083
7084 // Add 'i' as an accessor to the instance template with ReadOnly attributes
7085 // but the attribute does not have effect because it is duplicated with
7086 // NULL setter.
7087 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7088 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7089
7090
7091
7092 // Instantiate the child template.
7093 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7094
7095 // Check that the child function overrides the parent one.
7096 context->Global()->Set(v8_str("o"), instance);
7097 Local<Value> value = v8_compile("o.f")->Run();
7098 // Check that the 'g' that was added last is hit.
7099 CHECK_EQ(42, value->Int32Value());
7100 value = v8_compile("o.g")->Run();
7101 CHECK_EQ(42, value->Int32Value());
7102
7103 // Check 'h' can be shadowed.
7104 value = v8_compile("o.h = 3; o.h")->Run();
7105 CHECK_EQ(3, value->Int32Value());
7106
7107 // Check 'i' is cannot be shadowed or changed.
7108 value = v8_compile("o.i = 3; o.i")->Run();
7109 CHECK_EQ(42, value->Int32Value());
7110}
7111
7112
7113static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7114 ApiTestFuzzer::Fuzz();
7115 if (args.IsConstructCall()) {
7116 return v8::Boolean::New(true);
7117 }
7118 return v8::Boolean::New(false);
7119}
7120
7121
7122THREADED_TEST(IsConstructCall) {
7123 v8::HandleScope scope;
7124
7125 // Function template with call handler.
7126 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7127 templ->SetCallHandler(IsConstructHandler);
7128
7129 LocalContext context;
7130
7131 context->Global()->Set(v8_str("f"), templ->GetFunction());
7132 Local<Value> value = v8_compile("f()")->Run();
7133 CHECK(!value->BooleanValue());
7134 value = v8_compile("new f()")->Run();
7135 CHECK(value->BooleanValue());
7136}
7137
7138
7139THREADED_TEST(ObjectProtoToString) {
7140 v8::HandleScope scope;
7141 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7142 templ->SetClassName(v8_str("MyClass"));
7143
7144 LocalContext context;
7145
7146 Local<String> customized_tostring = v8_str("customized toString");
7147
7148 // Replace Object.prototype.toString
7149 v8_compile("Object.prototype.toString = function() {"
7150 " return 'customized toString';"
7151 "}")->Run();
7152
7153 // Normal ToString call should call replaced Object.prototype.toString
7154 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7155 Local<String> value = instance->ToString();
7156 CHECK(value->IsString() && value->Equals(customized_tostring));
7157
7158 // ObjectProtoToString should not call replace toString function.
7159 value = instance->ObjectProtoToString();
7160 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7161
7162 // Check global
7163 value = context->Global()->ObjectProtoToString();
7164 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7165
7166 // Check ordinary object
7167 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01007168 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +00007169 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7170}
7171
7172
7173bool ApiTestFuzzer::fuzzing_ = false;
7174v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
7175 v8::internal::OS::CreateSemaphore(0);
7176int ApiTestFuzzer::active_tests_;
7177int ApiTestFuzzer::tests_being_run_;
7178int ApiTestFuzzer::current_;
7179
7180
7181// We are in a callback and want to switch to another thread (if we
7182// are currently running the thread fuzzing test).
7183void ApiTestFuzzer::Fuzz() {
7184 if (!fuzzing_) return;
7185 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7186 test->ContextSwitch();
7187}
7188
7189
7190// Let the next thread go. Since it is also waiting on the V8 lock it may
7191// not start immediately.
7192bool ApiTestFuzzer::NextThread() {
7193 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +00007194 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00007195 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +00007196 if (kLogThreading)
7197 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +00007198 return false;
7199 }
Steve Blockd0582a62009-12-15 09:54:21 +00007200 if (kLogThreading) {
7201 printf("Switch from %s to %s\n",
7202 test_name,
7203 RegisterThreadedTest::nth(test_position)->name());
7204 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007205 current_ = test_position;
7206 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7207 return true;
7208}
7209
7210
7211void ApiTestFuzzer::Run() {
7212 // When it is our turn...
7213 gate_->Wait();
7214 {
7215 // ... get the V8 lock and start running the test.
7216 v8::Locker locker;
7217 CallTest();
7218 }
7219 // This test finished.
7220 active_ = false;
7221 active_tests_--;
7222 // If it was the last then signal that fact.
7223 if (active_tests_ == 0) {
7224 all_tests_done_->Signal();
7225 } else {
7226 // Otherwise select a new test and start that.
7227 NextThread();
7228 }
7229}
7230
7231
7232static unsigned linear_congruential_generator;
7233
7234
7235void ApiTestFuzzer::Setup(PartOfTest part) {
7236 linear_congruential_generator = i::FLAG_testing_prng_seed;
7237 fuzzing_ = true;
7238 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7239 int end = (part == FIRST_PART)
7240 ? (RegisterThreadedTest::count() >> 1)
7241 : RegisterThreadedTest::count();
7242 active_tests_ = tests_being_run_ = end - start;
7243 for (int i = 0; i < tests_being_run_; i++) {
7244 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7245 }
7246 for (int i = 0; i < active_tests_; i++) {
7247 RegisterThreadedTest::nth(i)->fuzzer_->Start();
7248 }
7249}
7250
7251
7252static void CallTestNumber(int test_number) {
7253 (RegisterThreadedTest::nth(test_number)->callback())();
7254}
7255
7256
7257void ApiTestFuzzer::RunAllTests() {
7258 // Set off the first test.
7259 current_ = -1;
7260 NextThread();
7261 // Wait till they are all done.
7262 all_tests_done_->Wait();
7263}
7264
7265
7266int ApiTestFuzzer::GetNextTestNumber() {
7267 int next_test;
7268 do {
7269 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7270 linear_congruential_generator *= 1664525u;
7271 linear_congruential_generator += 1013904223u;
7272 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7273 return next_test;
7274}
7275
7276
7277void ApiTestFuzzer::ContextSwitch() {
7278 // If the new thread is the same as the current thread there is nothing to do.
7279 if (NextThread()) {
7280 // Now it can start.
7281 v8::Unlocker unlocker;
7282 // Wait till someone starts us again.
7283 gate_->Wait();
7284 // And we're off.
7285 }
7286}
7287
7288
7289void ApiTestFuzzer::TearDown() {
7290 fuzzing_ = false;
7291 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7292 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7293 if (fuzzer != NULL) fuzzer->Join();
7294 }
7295}
7296
7297
7298// Lets not be needlessly self-referential.
7299TEST(Threading) {
7300 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7301 ApiTestFuzzer::RunAllTests();
7302 ApiTestFuzzer::TearDown();
7303}
7304
7305TEST(Threading2) {
7306 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7307 ApiTestFuzzer::RunAllTests();
7308 ApiTestFuzzer::TearDown();
7309}
7310
7311
7312void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +00007313 if (kLogThreading)
7314 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00007315 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +00007316 if (kLogThreading)
7317 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00007318}
7319
7320
7321static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7322 CHECK(v8::Locker::IsLocked());
7323 ApiTestFuzzer::Fuzz();
7324 v8::Unlocker unlocker;
7325 const char* code = "throw 7;";
7326 {
7327 v8::Locker nested_locker;
7328 v8::HandleScope scope;
7329 v8::Handle<Value> exception;
7330 { v8::TryCatch try_catch;
7331 v8::Handle<Value> value = CompileRun(code);
7332 CHECK(value.IsEmpty());
7333 CHECK(try_catch.HasCaught());
7334 // Make sure to wrap the exception in a new handle because
7335 // the handle returned from the TryCatch is destroyed
7336 // when the TryCatch is destroyed.
7337 exception = Local<Value>::New(try_catch.Exception());
7338 }
7339 return v8::ThrowException(exception);
7340 }
7341}
7342
7343
7344static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7345 CHECK(v8::Locker::IsLocked());
7346 ApiTestFuzzer::Fuzz();
7347 v8::Unlocker unlocker;
7348 const char* code = "throw 7;";
7349 {
7350 v8::Locker nested_locker;
7351 v8::HandleScope scope;
7352 v8::Handle<Value> value = CompileRun(code);
7353 CHECK(value.IsEmpty());
7354 return v8_str("foo");
7355 }
7356}
7357
7358
7359// These are locking tests that don't need to be run again
7360// as part of the locking aggregation tests.
7361TEST(NestedLockers) {
7362 v8::Locker locker;
7363 CHECK(v8::Locker::IsLocked());
7364 v8::HandleScope scope;
7365 LocalContext env;
7366 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7367 Local<Function> fun = fun_templ->GetFunction();
7368 env->Global()->Set(v8_str("throw_in_js"), fun);
7369 Local<Script> script = v8_compile("(function () {"
7370 " try {"
7371 " throw_in_js();"
7372 " return 42;"
7373 " } catch (e) {"
7374 " return e * 13;"
7375 " }"
7376 "})();");
7377 CHECK_EQ(91, script->Run()->Int32Value());
7378}
7379
7380
7381// These are locking tests that don't need to be run again
7382// as part of the locking aggregation tests.
7383TEST(NestedLockersNoTryCatch) {
7384 v8::Locker locker;
7385 v8::HandleScope scope;
7386 LocalContext env;
7387 Local<v8::FunctionTemplate> fun_templ =
7388 v8::FunctionTemplate::New(ThrowInJSNoCatch);
7389 Local<Function> fun = fun_templ->GetFunction();
7390 env->Global()->Set(v8_str("throw_in_js"), fun);
7391 Local<Script> script = v8_compile("(function () {"
7392 " try {"
7393 " throw_in_js();"
7394 " return 42;"
7395 " } catch (e) {"
7396 " return e * 13;"
7397 " }"
7398 "})();");
7399 CHECK_EQ(91, script->Run()->Int32Value());
7400}
7401
7402
7403THREADED_TEST(RecursiveLocking) {
7404 v8::Locker locker;
7405 {
7406 v8::Locker locker2;
7407 CHECK(v8::Locker::IsLocked());
7408 }
7409}
7410
7411
7412static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7413 ApiTestFuzzer::Fuzz();
7414 v8::Unlocker unlocker;
7415 return v8::Undefined();
7416}
7417
7418
7419THREADED_TEST(LockUnlockLock) {
7420 {
7421 v8::Locker locker;
7422 v8::HandleScope scope;
7423 LocalContext env;
7424 Local<v8::FunctionTemplate> fun_templ =
7425 v8::FunctionTemplate::New(UnlockForAMoment);
7426 Local<Function> fun = fun_templ->GetFunction();
7427 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7428 Local<Script> script = v8_compile("(function () {"
7429 " unlock_for_a_moment();"
7430 " return 42;"
7431 "})();");
7432 CHECK_EQ(42, script->Run()->Int32Value());
7433 }
7434 {
7435 v8::Locker locker;
7436 v8::HandleScope scope;
7437 LocalContext env;
7438 Local<v8::FunctionTemplate> fun_templ =
7439 v8::FunctionTemplate::New(UnlockForAMoment);
7440 Local<Function> fun = fun_templ->GetFunction();
7441 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7442 Local<Script> script = v8_compile("(function () {"
7443 " unlock_for_a_moment();"
7444 " return 42;"
7445 "})();");
7446 CHECK_EQ(42, script->Run()->Int32Value());
7447 }
7448}
7449
7450
Leon Clarked91b9f72010-01-27 17:25:45 +00007451static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00007452 int count = 0;
Leon Clarked91b9f72010-01-27 17:25:45 +00007453 v8::internal::HeapIterator it;
7454 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7455 if (object->IsJSGlobalObject()) count++;
7456 return count;
7457}
7458
7459
7460static int GetSurvivingGlobalObjectsCount() {
Steve Blocka7e24c12009-10-30 11:49:00 +00007461 // We need to collect all garbage twice to be sure that everything
7462 // has been collected. This is because inline caches are cleared in
7463 // the first garbage collection but some of the maps have already
7464 // been marked at that point. Therefore some of the maps are not
7465 // collected until the second garbage collection.
7466 v8::internal::Heap::CollectAllGarbage(false);
7467 v8::internal::Heap::CollectAllGarbage(false);
Leon Clarked91b9f72010-01-27 17:25:45 +00007468 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00007469#ifdef DEBUG
7470 if (count > 0) v8::internal::Heap::TracePathToGlobal();
7471#endif
7472 return count;
7473}
7474
7475
7476TEST(DontLeakGlobalObjects) {
7477 // Regression test for issues 1139850 and 1174891.
7478
7479 v8::V8::Initialize();
7480
7481 int count = GetSurvivingGlobalObjectsCount();
7482
7483 for (int i = 0; i < 5; i++) {
7484 { v8::HandleScope scope;
7485 LocalContext context;
7486 }
7487 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7488
7489 { v8::HandleScope scope;
7490 LocalContext context;
7491 v8_compile("Date")->Run();
7492 }
7493 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7494
7495 { v8::HandleScope scope;
7496 LocalContext context;
7497 v8_compile("/aaa/")->Run();
7498 }
7499 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7500
7501 { v8::HandleScope scope;
7502 const char* extension_list[] = { "v8/gc" };
7503 v8::ExtensionConfiguration extensions(1, extension_list);
7504 LocalContext context(&extensions);
7505 v8_compile("gc();")->Run();
7506 }
7507 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7508 }
7509}
7510
7511
7512v8::Persistent<v8::Object> some_object;
7513v8::Persistent<v8::Object> bad_handle;
7514
7515void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7516 v8::HandleScope scope;
7517 bad_handle = v8::Persistent<v8::Object>::New(some_object);
7518}
7519
7520
7521THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7522 LocalContext context;
7523
7524 v8::Persistent<v8::Object> handle1, handle2;
7525 {
7526 v8::HandleScope scope;
7527 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7528 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7529 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7530 }
7531 // Note: order is implementation dependent alas: currently
7532 // global handle nodes are processed by PostGarbageCollectionProcessing
7533 // in reverse allocation order, so if second allocated handle is deleted,
7534 // weak callback of the first handle would be able to 'reallocate' it.
7535 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7536 handle2.Dispose();
7537 i::Heap::CollectAllGarbage(false);
7538}
7539
7540
7541v8::Persistent<v8::Object> to_be_disposed;
7542
7543void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7544 to_be_disposed.Dispose();
7545 i::Heap::CollectAllGarbage(false);
7546}
7547
7548
7549THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7550 LocalContext context;
7551
7552 v8::Persistent<v8::Object> handle1, handle2;
7553 {
7554 v8::HandleScope scope;
7555 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7556 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7557 }
7558 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7559 to_be_disposed = handle2;
7560 i::Heap::CollectAllGarbage(false);
7561}
7562
Steve Blockd0582a62009-12-15 09:54:21 +00007563void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7564 handle.Dispose();
7565}
7566
7567void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7568 v8::HandleScope scope;
7569 v8::Persistent<v8::Object>::New(v8::Object::New());
7570}
7571
7572
7573THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
7574 LocalContext context;
7575
7576 v8::Persistent<v8::Object> handle1, handle2, handle3;
7577 {
7578 v8::HandleScope scope;
7579 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
7580 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7581 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7582 }
7583 handle2.MakeWeak(NULL, DisposingCallback);
7584 handle3.MakeWeak(NULL, HandleCreatingCallback);
7585 i::Heap::CollectAllGarbage(false);
7586}
7587
Steve Blocka7e24c12009-10-30 11:49:00 +00007588
7589THREADED_TEST(CheckForCrossContextObjectLiterals) {
7590 v8::V8::Initialize();
7591
7592 const int nof = 2;
7593 const char* sources[nof] = {
7594 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
7595 "Object()"
7596 };
7597
7598 for (int i = 0; i < nof; i++) {
7599 const char* source = sources[i];
7600 { v8::HandleScope scope;
7601 LocalContext context;
7602 CompileRun(source);
7603 }
7604 { v8::HandleScope scope;
7605 LocalContext context;
7606 CompileRun(source);
7607 }
7608 }
7609}
7610
7611
7612static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
7613 v8::HandleScope inner;
7614 env->Enter();
7615 v8::Handle<Value> three = v8_num(3);
7616 v8::Handle<Value> value = inner.Close(three);
7617 env->Exit();
7618 return value;
7619}
7620
7621
7622THREADED_TEST(NestedHandleScopeAndContexts) {
7623 v8::HandleScope outer;
7624 v8::Persistent<Context> env = Context::New();
7625 env->Enter();
7626 v8::Handle<Value> value = NestedScope(env);
7627 v8::Handle<String> str = value->ToString();
7628 env->Exit();
7629 env.Dispose();
7630}
7631
7632
7633THREADED_TEST(ExternalAllocatedMemory) {
7634 v8::HandleScope outer;
7635 v8::Persistent<Context> env = Context::New();
7636 const int kSize = 1024*1024;
7637 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
7638 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
7639}
7640
7641
7642THREADED_TEST(DisposeEnteredContext) {
7643 v8::HandleScope scope;
7644 LocalContext outer;
7645 { v8::Persistent<v8::Context> inner = v8::Context::New();
7646 inner->Enter();
7647 inner.Dispose();
7648 inner.Clear();
7649 inner->Exit();
7650 }
7651}
7652
7653
7654// Regression test for issue 54, object templates with internal fields
7655// but no accessors or interceptors did not get their internal field
7656// count set on instances.
7657THREADED_TEST(Regress54) {
7658 v8::HandleScope outer;
7659 LocalContext context;
7660 static v8::Persistent<v8::ObjectTemplate> templ;
7661 if (templ.IsEmpty()) {
7662 v8::HandleScope inner;
7663 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
7664 local->SetInternalFieldCount(1);
7665 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
7666 }
7667 v8::Handle<v8::Object> result = templ->NewInstance();
7668 CHECK_EQ(1, result->InternalFieldCount());
7669}
7670
7671
7672// If part of the threaded tests, this test makes ThreadingTest fail
7673// on mac.
7674TEST(CatchStackOverflow) {
7675 v8::HandleScope scope;
7676 LocalContext context;
7677 v8::TryCatch try_catch;
7678 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
7679 "function f() {"
7680 " return f();"
7681 "}"
7682 ""
7683 "f();"));
7684 v8::Handle<v8::Value> result = script->Run();
7685 CHECK(result.IsEmpty());
7686}
7687
7688
7689static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
7690 const char* resource_name,
7691 int line_offset) {
7692 v8::HandleScope scope;
7693 v8::TryCatch try_catch;
7694 v8::Handle<v8::Value> result = script->Run();
7695 CHECK(result.IsEmpty());
7696 CHECK(try_catch.HasCaught());
7697 v8::Handle<v8::Message> message = try_catch.Message();
7698 CHECK(!message.IsEmpty());
7699 CHECK_EQ(10 + line_offset, message->GetLineNumber());
7700 CHECK_EQ(91, message->GetStartPosition());
7701 CHECK_EQ(92, message->GetEndPosition());
7702 CHECK_EQ(2, message->GetStartColumn());
7703 CHECK_EQ(3, message->GetEndColumn());
7704 v8::String::AsciiValue line(message->GetSourceLine());
7705 CHECK_EQ(" throw 'nirk';", *line);
7706 v8::String::AsciiValue name(message->GetScriptResourceName());
7707 CHECK_EQ(resource_name, *name);
7708}
7709
7710
7711THREADED_TEST(TryCatchSourceInfo) {
7712 v8::HandleScope scope;
7713 LocalContext context;
7714 v8::Handle<v8::String> source = v8::String::New(
7715 "function Foo() {\n"
7716 " return Bar();\n"
7717 "}\n"
7718 "\n"
7719 "function Bar() {\n"
7720 " return Baz();\n"
7721 "}\n"
7722 "\n"
7723 "function Baz() {\n"
7724 " throw 'nirk';\n"
7725 "}\n"
7726 "\n"
7727 "Foo();\n");
7728
7729 const char* resource_name;
7730 v8::Handle<v8::Script> script;
7731 resource_name = "test.js";
7732 script = v8::Script::Compile(source, v8::String::New(resource_name));
7733 CheckTryCatchSourceInfo(script, resource_name, 0);
7734
7735 resource_name = "test1.js";
7736 v8::ScriptOrigin origin1(v8::String::New(resource_name));
7737 script = v8::Script::Compile(source, &origin1);
7738 CheckTryCatchSourceInfo(script, resource_name, 0);
7739
7740 resource_name = "test2.js";
7741 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
7742 script = v8::Script::Compile(source, &origin2);
7743 CheckTryCatchSourceInfo(script, resource_name, 7);
7744}
7745
7746
7747THREADED_TEST(CompilationCache) {
7748 v8::HandleScope scope;
7749 LocalContext context;
7750 v8::Handle<v8::String> source0 = v8::String::New("1234");
7751 v8::Handle<v8::String> source1 = v8::String::New("1234");
7752 v8::Handle<v8::Script> script0 =
7753 v8::Script::Compile(source0, v8::String::New("test.js"));
7754 v8::Handle<v8::Script> script1 =
7755 v8::Script::Compile(source1, v8::String::New("test.js"));
7756 v8::Handle<v8::Script> script2 =
7757 v8::Script::Compile(source0); // different origin
7758 CHECK_EQ(1234, script0->Run()->Int32Value());
7759 CHECK_EQ(1234, script1->Run()->Int32Value());
7760 CHECK_EQ(1234, script2->Run()->Int32Value());
7761}
7762
7763
7764static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
7765 ApiTestFuzzer::Fuzz();
7766 return v8_num(42);
7767}
7768
7769
7770THREADED_TEST(CallbackFunctionName) {
7771 v8::HandleScope scope;
7772 LocalContext context;
7773 Local<ObjectTemplate> t = ObjectTemplate::New();
7774 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
7775 context->Global()->Set(v8_str("obj"), t->NewInstance());
7776 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
7777 CHECK(value->IsString());
7778 v8::String::AsciiValue name(value);
7779 CHECK_EQ("asdf", *name);
7780}
7781
7782
7783THREADED_TEST(DateAccess) {
7784 v8::HandleScope scope;
7785 LocalContext context;
7786 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
7787 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +01007788 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00007789}
7790
7791
7792void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +01007793 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00007794 v8::Handle<v8::Array> props = obj->GetPropertyNames();
7795 CHECK_EQ(elmc, props->Length());
7796 for (int i = 0; i < elmc; i++) {
7797 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
7798 CHECK_EQ(elmv[i], *elm);
7799 }
7800}
7801
7802
7803THREADED_TEST(PropertyEnumeration) {
7804 v8::HandleScope scope;
7805 LocalContext context;
7806 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
7807 "var result = [];"
7808 "result[0] = {};"
7809 "result[1] = {a: 1, b: 2};"
7810 "result[2] = [1, 2, 3];"
7811 "var proto = {x: 1, y: 2, z: 3};"
7812 "var x = { __proto__: proto, w: 0, z: 1 };"
7813 "result[3] = x;"
7814 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01007815 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00007816 CHECK_EQ(4, elms->Length());
7817 int elmc0 = 0;
7818 const char** elmv0 = NULL;
7819 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
7820 int elmc1 = 2;
7821 const char* elmv1[] = {"a", "b"};
7822 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
7823 int elmc2 = 3;
7824 const char* elmv2[] = {"0", "1", "2"};
7825 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
7826 int elmc3 = 4;
7827 const char* elmv3[] = {"w", "z", "x", "y"};
7828 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
7829}
7830
7831
Steve Blocka7e24c12009-10-30 11:49:00 +00007832static bool NamedSetAccessBlocker(Local<v8::Object> obj,
7833 Local<Value> name,
7834 v8::AccessType type,
7835 Local<Value> data) {
7836 return type != v8::ACCESS_SET;
7837}
7838
7839
7840static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
7841 uint32_t key,
7842 v8::AccessType type,
7843 Local<Value> data) {
7844 return type != v8::ACCESS_SET;
7845}
7846
7847
7848THREADED_TEST(DisableAccessChecksWhileConfiguring) {
7849 v8::HandleScope scope;
7850 LocalContext context;
7851 Local<ObjectTemplate> templ = ObjectTemplate::New();
7852 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7853 IndexedSetAccessBlocker);
7854 templ->Set(v8_str("x"), v8::True());
7855 Local<v8::Object> instance = templ->NewInstance();
7856 context->Global()->Set(v8_str("obj"), instance);
7857 Local<Value> value = CompileRun("obj.x");
7858 CHECK(value->BooleanValue());
7859}
7860
7861
7862static bool NamedGetAccessBlocker(Local<v8::Object> obj,
7863 Local<Value> name,
7864 v8::AccessType type,
7865 Local<Value> data) {
7866 return false;
7867}
7868
7869
7870static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
7871 uint32_t key,
7872 v8::AccessType type,
7873 Local<Value> data) {
7874 return false;
7875}
7876
7877
7878
7879THREADED_TEST(AccessChecksReenabledCorrectly) {
7880 v8::HandleScope scope;
7881 LocalContext context;
7882 Local<ObjectTemplate> templ = ObjectTemplate::New();
7883 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7884 IndexedGetAccessBlocker);
7885 templ->Set(v8_str("a"), v8_str("a"));
7886 // Add more than 8 (see kMaxFastProperties) properties
7887 // so that the constructor will force copying map.
7888 // Cannot sprintf, gcc complains unsafety.
7889 char buf[4];
7890 for (char i = '0'; i <= '9' ; i++) {
7891 buf[0] = i;
7892 for (char j = '0'; j <= '9'; j++) {
7893 buf[1] = j;
7894 for (char k = '0'; k <= '9'; k++) {
7895 buf[2] = k;
7896 buf[3] = 0;
7897 templ->Set(v8_str(buf), v8::Number::New(k));
7898 }
7899 }
7900 }
7901
7902 Local<v8::Object> instance_1 = templ->NewInstance();
7903 context->Global()->Set(v8_str("obj_1"), instance_1);
7904
7905 Local<Value> value_1 = CompileRun("obj_1.a");
7906 CHECK(value_1->IsUndefined());
7907
7908 Local<v8::Object> instance_2 = templ->NewInstance();
7909 context->Global()->Set(v8_str("obj_2"), instance_2);
7910
7911 Local<Value> value_2 = CompileRun("obj_2.a");
7912 CHECK(value_2->IsUndefined());
7913}
7914
7915
7916// This tests that access check information remains on the global
7917// object template when creating contexts.
7918THREADED_TEST(AccessControlRepeatedContextCreation) {
7919 v8::HandleScope handle_scope;
7920 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7921 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7922 IndexedSetAccessBlocker);
7923 i::Handle<i::ObjectTemplateInfo> internal_template =
7924 v8::Utils::OpenHandle(*global_template);
7925 CHECK(!internal_template->constructor()->IsUndefined());
7926 i::Handle<i::FunctionTemplateInfo> constructor(
7927 i::FunctionTemplateInfo::cast(internal_template->constructor()));
7928 CHECK(!constructor->access_check_info()->IsUndefined());
7929 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7930 CHECK(!constructor->access_check_info()->IsUndefined());
7931}
7932
7933
7934THREADED_TEST(TurnOnAccessCheck) {
7935 v8::HandleScope handle_scope;
7936
7937 // Create an environment with access check to the global object disabled by
7938 // default.
7939 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7940 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7941 IndexedGetAccessBlocker,
7942 v8::Handle<v8::Value>(),
7943 false);
7944 v8::Persistent<Context> context = Context::New(NULL, global_template);
7945 Context::Scope context_scope(context);
7946
7947 // Set up a property and a number of functions.
7948 context->Global()->Set(v8_str("a"), v8_num(1));
7949 CompileRun("function f1() {return a;}"
7950 "function f2() {return a;}"
7951 "function g1() {return h();}"
7952 "function g2() {return h();}"
7953 "function h() {return 1;}");
7954 Local<Function> f1 =
7955 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
7956 Local<Function> f2 =
7957 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
7958 Local<Function> g1 =
7959 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
7960 Local<Function> g2 =
7961 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
7962 Local<Function> h =
7963 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
7964
7965 // Get the global object.
7966 v8::Handle<v8::Object> global = context->Global();
7967
7968 // Call f1 one time and f2 a number of times. This will ensure that f1 still
7969 // uses the runtime system to retreive property a whereas f2 uses global load
7970 // inline cache.
7971 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
7972 for (int i = 0; i < 4; i++) {
7973 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
7974 }
7975
7976 // Same for g1 and g2.
7977 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
7978 for (int i = 0; i < 4; i++) {
7979 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
7980 }
7981
7982 // Detach the global and turn on access check.
7983 context->DetachGlobal();
7984 context->Global()->TurnOnAccessCheck();
7985
7986 // Failing access check to property get results in undefined.
7987 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
7988 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
7989
7990 // Failing access check to function call results in exception.
7991 CHECK(g1->Call(global, 0, NULL).IsEmpty());
7992 CHECK(g2->Call(global, 0, NULL).IsEmpty());
7993
7994 // No failing access check when just returning a constant.
7995 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
7996}
7997
7998
7999// This test verifies that pre-compilation (aka preparsing) can be called
8000// without initializing the whole VM. Thus we cannot run this test in a
8001// multi-threaded setup.
8002TEST(PreCompile) {
8003 // TODO(155): This test would break without the initialization of V8. This is
8004 // a workaround for now to make this test not fail.
8005 v8::V8::Initialize();
8006 const char *script = "function foo(a) { return a+1; }";
Steve Blockd0582a62009-12-15 09:54:21 +00008007 v8::ScriptData *sd =
8008 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +00008009 CHECK_NE(sd->Length(), 0);
8010 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +00008011 CHECK(!sd->HasError());
8012 delete sd;
8013}
8014
8015
8016TEST(PreCompileWithError) {
8017 v8::V8::Initialize();
8018 const char *script = "function foo(a) { return 1 * * 2; }";
8019 v8::ScriptData *sd =
8020 v8::ScriptData::PreCompile(script, i::StrLength(script));
8021 CHECK(sd->HasError());
8022 delete sd;
8023}
8024
8025
8026TEST(Regress31661) {
8027 v8::V8::Initialize();
8028 const char *script = " The Definintive Guide";
8029 v8::ScriptData *sd =
8030 v8::ScriptData::PreCompile(script, i::StrLength(script));
8031 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +00008032 delete sd;
8033}
8034
8035
8036// This tests that we do not allow dictionary load/call inline caches
8037// to use functions that have not yet been compiled. The potential
8038// problem of loading a function that has not yet been compiled can
8039// arise because we share code between contexts via the compilation
8040// cache.
8041THREADED_TEST(DictionaryICLoadedFunction) {
8042 v8::HandleScope scope;
8043 // Test LoadIC.
8044 for (int i = 0; i < 2; i++) {
8045 LocalContext context;
8046 context->Global()->Set(v8_str("tmp"), v8::True());
8047 context->Global()->Delete(v8_str("tmp"));
8048 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8049 }
8050 // Test CallIC.
8051 for (int i = 0; i < 2; i++) {
8052 LocalContext context;
8053 context->Global()->Set(v8_str("tmp"), v8::True());
8054 context->Global()->Delete(v8_str("tmp"));
8055 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8056 }
8057}
8058
8059
8060// Test that cross-context new calls use the context of the callee to
8061// create the new JavaScript object.
8062THREADED_TEST(CrossContextNew) {
8063 v8::HandleScope scope;
8064 v8::Persistent<Context> context0 = Context::New();
8065 v8::Persistent<Context> context1 = Context::New();
8066
8067 // Allow cross-domain access.
8068 Local<String> token = v8_str("<security token>");
8069 context0->SetSecurityToken(token);
8070 context1->SetSecurityToken(token);
8071
8072 // Set an 'x' property on the Object prototype and define a
8073 // constructor function in context0.
8074 context0->Enter();
8075 CompileRun("Object.prototype.x = 42; function C() {};");
8076 context0->Exit();
8077
8078 // Call the constructor function from context0 and check that the
8079 // result has the 'x' property.
8080 context1->Enter();
8081 context1->Global()->Set(v8_str("other"), context0->Global());
8082 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8083 CHECK(value->IsInt32());
8084 CHECK_EQ(42, value->Int32Value());
8085 context1->Exit();
8086
8087 // Dispose the contexts to allow them to be garbage collected.
8088 context0.Dispose();
8089 context1.Dispose();
8090}
8091
8092
8093class RegExpInterruptTest {
8094 public:
8095 RegExpInterruptTest() : block_(NULL) {}
8096 ~RegExpInterruptTest() { delete block_; }
8097 void RunTest() {
8098 block_ = i::OS::CreateSemaphore(0);
8099 gc_count_ = 0;
8100 gc_during_regexp_ = 0;
8101 regexp_success_ = false;
8102 gc_success_ = false;
8103 GCThread gc_thread(this);
8104 gc_thread.Start();
8105 v8::Locker::StartPreemption(1);
8106
8107 LongRunningRegExp();
8108 {
8109 v8::Unlocker unlock;
8110 gc_thread.Join();
8111 }
8112 v8::Locker::StopPreemption();
8113 CHECK(regexp_success_);
8114 CHECK(gc_success_);
8115 }
8116 private:
8117 // Number of garbage collections required.
8118 static const int kRequiredGCs = 5;
8119
8120 class GCThread : public i::Thread {
8121 public:
8122 explicit GCThread(RegExpInterruptTest* test)
8123 : test_(test) {}
8124 virtual void Run() {
8125 test_->CollectGarbage();
8126 }
8127 private:
8128 RegExpInterruptTest* test_;
8129 };
8130
8131 void CollectGarbage() {
8132 block_->Wait();
8133 while (gc_during_regexp_ < kRequiredGCs) {
8134 {
8135 v8::Locker lock;
8136 // TODO(lrn): Perhaps create some garbage before collecting.
8137 i::Heap::CollectAllGarbage(false);
8138 gc_count_++;
8139 }
8140 i::OS::Sleep(1);
8141 }
8142 gc_success_ = true;
8143 }
8144
8145 void LongRunningRegExp() {
8146 block_->Signal(); // Enable garbage collection thread on next preemption.
8147 int rounds = 0;
8148 while (gc_during_regexp_ < kRequiredGCs) {
8149 int gc_before = gc_count_;
8150 {
8151 // Match 15-30 "a"'s against 14 and a "b".
8152 const char* c_source =
8153 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8154 ".exec('aaaaaaaaaaaaaaab') === null";
8155 Local<String> source = String::New(c_source);
8156 Local<Script> script = Script::Compile(source);
8157 Local<Value> result = script->Run();
8158 if (!result->BooleanValue()) {
8159 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
8160 return;
8161 }
8162 }
8163 {
8164 // Match 15-30 "a"'s against 15 and a "b".
8165 const char* c_source =
8166 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8167 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8168 Local<String> source = String::New(c_source);
8169 Local<Script> script = Script::Compile(source);
8170 Local<Value> result = script->Run();
8171 if (!result->BooleanValue()) {
8172 gc_during_regexp_ = kRequiredGCs;
8173 return;
8174 }
8175 }
8176 int gc_after = gc_count_;
8177 gc_during_regexp_ += gc_after - gc_before;
8178 rounds++;
8179 i::OS::Sleep(1);
8180 }
8181 regexp_success_ = true;
8182 }
8183
8184 i::Semaphore* block_;
8185 int gc_count_;
8186 int gc_during_regexp_;
8187 bool regexp_success_;
8188 bool gc_success_;
8189};
8190
8191
8192// Test that a regular expression execution can be interrupted and
8193// survive a garbage collection.
8194TEST(RegExpInterruption) {
8195 v8::Locker lock;
8196 v8::V8::Initialize();
8197 v8::HandleScope scope;
8198 Local<Context> local_env;
8199 {
8200 LocalContext env;
8201 local_env = env.local();
8202 }
8203
8204 // Local context should still be live.
8205 CHECK(!local_env.IsEmpty());
8206 local_env->Enter();
8207
8208 // Should complete without problems.
8209 RegExpInterruptTest().RunTest();
8210
8211 local_env->Exit();
8212}
8213
8214
8215class ApplyInterruptTest {
8216 public:
8217 ApplyInterruptTest() : block_(NULL) {}
8218 ~ApplyInterruptTest() { delete block_; }
8219 void RunTest() {
8220 block_ = i::OS::CreateSemaphore(0);
8221 gc_count_ = 0;
8222 gc_during_apply_ = 0;
8223 apply_success_ = false;
8224 gc_success_ = false;
8225 GCThread gc_thread(this);
8226 gc_thread.Start();
8227 v8::Locker::StartPreemption(1);
8228
8229 LongRunningApply();
8230 {
8231 v8::Unlocker unlock;
8232 gc_thread.Join();
8233 }
8234 v8::Locker::StopPreemption();
8235 CHECK(apply_success_);
8236 CHECK(gc_success_);
8237 }
8238 private:
8239 // Number of garbage collections required.
8240 static const int kRequiredGCs = 2;
8241
8242 class GCThread : public i::Thread {
8243 public:
8244 explicit GCThread(ApplyInterruptTest* test)
8245 : test_(test) {}
8246 virtual void Run() {
8247 test_->CollectGarbage();
8248 }
8249 private:
8250 ApplyInterruptTest* test_;
8251 };
8252
8253 void CollectGarbage() {
8254 block_->Wait();
8255 while (gc_during_apply_ < kRequiredGCs) {
8256 {
8257 v8::Locker lock;
8258 i::Heap::CollectAllGarbage(false);
8259 gc_count_++;
8260 }
8261 i::OS::Sleep(1);
8262 }
8263 gc_success_ = true;
8264 }
8265
8266 void LongRunningApply() {
8267 block_->Signal();
8268 int rounds = 0;
8269 while (gc_during_apply_ < kRequiredGCs) {
8270 int gc_before = gc_count_;
8271 {
8272 const char* c_source =
8273 "function do_very_little(bar) {"
8274 " this.foo = bar;"
8275 "}"
8276 "for (var i = 0; i < 100000; i++) {"
8277 " do_very_little.apply(this, ['bar']);"
8278 "}";
8279 Local<String> source = String::New(c_source);
8280 Local<Script> script = Script::Compile(source);
8281 Local<Value> result = script->Run();
8282 // Check that no exception was thrown.
8283 CHECK(!result.IsEmpty());
8284 }
8285 int gc_after = gc_count_;
8286 gc_during_apply_ += gc_after - gc_before;
8287 rounds++;
8288 }
8289 apply_success_ = true;
8290 }
8291
8292 i::Semaphore* block_;
8293 int gc_count_;
8294 int gc_during_apply_;
8295 bool apply_success_;
8296 bool gc_success_;
8297};
8298
8299
8300// Test that nothing bad happens if we get a preemption just when we were
8301// about to do an apply().
8302TEST(ApplyInterruption) {
8303 v8::Locker lock;
8304 v8::V8::Initialize();
8305 v8::HandleScope scope;
8306 Local<Context> local_env;
8307 {
8308 LocalContext env;
8309 local_env = env.local();
8310 }
8311
8312 // Local context should still be live.
8313 CHECK(!local_env.IsEmpty());
8314 local_env->Enter();
8315
8316 // Should complete without problems.
8317 ApplyInterruptTest().RunTest();
8318
8319 local_env->Exit();
8320}
8321
8322
8323// Verify that we can clone an object
8324TEST(ObjectClone) {
8325 v8::HandleScope scope;
8326 LocalContext env;
8327
8328 const char* sample =
8329 "var rv = {};" \
8330 "rv.alpha = 'hello';" \
8331 "rv.beta = 123;" \
8332 "rv;";
8333
8334 // Create an object, verify basics.
8335 Local<Value> val = CompileRun(sample);
8336 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008337 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008338 obj->Set(v8_str("gamma"), v8_str("cloneme"));
8339
8340 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8341 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8342 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8343
8344 // Clone it.
8345 Local<v8::Object> clone = obj->Clone();
8346 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8347 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8348 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8349
8350 // Set a property on the clone, verify each object.
8351 clone->Set(v8_str("beta"), v8::Integer::New(456));
8352 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8353 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8354}
8355
8356
8357class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8358 public:
8359 explicit AsciiVectorResource(i::Vector<const char> vector)
8360 : data_(vector) {}
8361 virtual ~AsciiVectorResource() {}
8362 virtual size_t length() const { return data_.length(); }
8363 virtual const char* data() const { return data_.start(); }
8364 private:
8365 i::Vector<const char> data_;
8366};
8367
8368
8369class UC16VectorResource : public v8::String::ExternalStringResource {
8370 public:
8371 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8372 : data_(vector) {}
8373 virtual ~UC16VectorResource() {}
8374 virtual size_t length() const { return data_.length(); }
8375 virtual const i::uc16* data() const { return data_.start(); }
8376 private:
8377 i::Vector<const i::uc16> data_;
8378};
8379
8380
8381static void MorphAString(i::String* string,
8382 AsciiVectorResource* ascii_resource,
8383 UC16VectorResource* uc16_resource) {
8384 CHECK(i::StringShape(string).IsExternal());
8385 if (string->IsAsciiRepresentation()) {
8386 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00008387 CHECK(string->map() == i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008388 // Morph external string to be TwoByte string.
Steve Blockd0582a62009-12-15 09:54:21 +00008389 string->set_map(i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008390 i::ExternalTwoByteString* morphed =
8391 i::ExternalTwoByteString::cast(string);
8392 morphed->set_resource(uc16_resource);
8393 } else {
8394 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00008395 CHECK(string->map() == i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008396 // Morph external string to be ASCII string.
Steve Blockd0582a62009-12-15 09:54:21 +00008397 string->set_map(i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008398 i::ExternalAsciiString* morphed =
8399 i::ExternalAsciiString::cast(string);
8400 morphed->set_resource(ascii_resource);
8401 }
8402}
8403
8404
8405// Test that we can still flatten a string if the components it is built up
8406// from have been turned into 16 bit strings in the mean time.
8407THREADED_TEST(MorphCompositeStringTest) {
8408 const char* c_string = "Now is the time for all good men"
8409 " to come to the aid of the party";
8410 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8411 {
8412 v8::HandleScope scope;
8413 LocalContext env;
8414 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00008415 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008416 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00008417 i::Vector<const uint16_t>(two_byte_string,
8418 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008419
8420 Local<String> lhs(v8::Utils::ToLocal(
8421 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8422 Local<String> rhs(v8::Utils::ToLocal(
8423 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8424
8425 env->Global()->Set(v8_str("lhs"), lhs);
8426 env->Global()->Set(v8_str("rhs"), rhs);
8427
8428 CompileRun(
8429 "var cons = lhs + rhs;"
8430 "var slice = lhs.substring(1, lhs.length - 1);"
8431 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8432
8433 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8434 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8435
8436 // Now do some stuff to make sure the strings are flattened, etc.
8437 CompileRun(
8438 "/[^a-z]/.test(cons);"
8439 "/[^a-z]/.test(slice);"
8440 "/[^a-z]/.test(slice_on_cons);");
8441 const char* expected_cons =
8442 "Now is the time for all good men to come to the aid of the party"
8443 "Now is the time for all good men to come to the aid of the party";
8444 const char* expected_slice =
8445 "ow is the time for all good men to come to the aid of the part";
8446 const char* expected_slice_on_cons =
8447 "ow is the time for all good men to come to the aid of the party"
8448 "Now is the time for all good men to come to the aid of the part";
8449 CHECK_EQ(String::New(expected_cons),
8450 env->Global()->Get(v8_str("cons")));
8451 CHECK_EQ(String::New(expected_slice),
8452 env->Global()->Get(v8_str("slice")));
8453 CHECK_EQ(String::New(expected_slice_on_cons),
8454 env->Global()->Get(v8_str("slice_on_cons")));
8455 }
8456}
8457
8458
8459TEST(CompileExternalTwoByteSource) {
8460 v8::HandleScope scope;
8461 LocalContext context;
8462
8463 // This is a very short list of sources, which currently is to check for a
8464 // regression caused by r2703.
8465 const char* ascii_sources[] = {
8466 "0.5",
8467 "-0.5", // This mainly testes PushBack in the Scanner.
8468 "--0.5", // This mainly testes PushBack in the Scanner.
8469 NULL
8470 };
8471
8472 // Compile the sources as external two byte strings.
8473 for (int i = 0; ascii_sources[i] != NULL; i++) {
8474 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8475 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00008476 i::Vector<const uint16_t>(two_byte_string,
8477 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +00008478 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8479 v8::Script::Compile(source);
8480 }
8481}
8482
8483
8484class RegExpStringModificationTest {
8485 public:
8486 RegExpStringModificationTest()
8487 : block_(i::OS::CreateSemaphore(0)),
8488 morphs_(0),
8489 morphs_during_regexp_(0),
8490 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8491 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
8492 ~RegExpStringModificationTest() { delete block_; }
8493 void RunTest() {
8494 regexp_success_ = false;
8495 morph_success_ = false;
8496
8497 // Initialize the contents of two_byte_content_ to be a uc16 representation
8498 // of "aaaaaaaaaaaaaab".
8499 for (int i = 0; i < 14; i++) {
8500 two_byte_content_[i] = 'a';
8501 }
8502 two_byte_content_[14] = 'b';
8503
8504 // Create the input string for the regexp - the one we are going to change
8505 // properties of.
8506 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8507
8508 // Inject the input as a global variable.
8509 i::Handle<i::String> input_name =
8510 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
8511 i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
8512
8513
8514 MorphThread morph_thread(this);
8515 morph_thread.Start();
8516 v8::Locker::StartPreemption(1);
8517 LongRunningRegExp();
8518 {
8519 v8::Unlocker unlock;
8520 morph_thread.Join();
8521 }
8522 v8::Locker::StopPreemption();
8523 CHECK(regexp_success_);
8524 CHECK(morph_success_);
8525 }
8526 private:
8527
8528 // Number of string modifications required.
8529 static const int kRequiredModifications = 5;
8530 static const int kMaxModifications = 100;
8531
8532 class MorphThread : public i::Thread {
8533 public:
8534 explicit MorphThread(RegExpStringModificationTest* test)
8535 : test_(test) {}
8536 virtual void Run() {
8537 test_->MorphString();
8538 }
8539 private:
8540 RegExpStringModificationTest* test_;
8541 };
8542
8543 void MorphString() {
8544 block_->Wait();
8545 while (morphs_during_regexp_ < kRequiredModifications &&
8546 morphs_ < kMaxModifications) {
8547 {
8548 v8::Locker lock;
8549 // Swap string between ascii and two-byte representation.
8550 i::String* string = *input_;
8551 MorphAString(string, &ascii_resource_, &uc16_resource_);
8552 morphs_++;
8553 }
8554 i::OS::Sleep(1);
8555 }
8556 morph_success_ = true;
8557 }
8558
8559 void LongRunningRegExp() {
8560 block_->Signal(); // Enable morphing thread on next preemption.
8561 while (morphs_during_regexp_ < kRequiredModifications &&
8562 morphs_ < kMaxModifications) {
8563 int morphs_before = morphs_;
8564 {
8565 // Match 15-30 "a"'s against 14 and a "b".
8566 const char* c_source =
8567 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8568 ".exec(input) === null";
8569 Local<String> source = String::New(c_source);
8570 Local<Script> script = Script::Compile(source);
8571 Local<Value> result = script->Run();
8572 CHECK(result->IsTrue());
8573 }
8574 int morphs_after = morphs_;
8575 morphs_during_regexp_ += morphs_after - morphs_before;
8576 }
8577 regexp_success_ = true;
8578 }
8579
8580 i::uc16 two_byte_content_[15];
8581 i::Semaphore* block_;
8582 int morphs_;
8583 int morphs_during_regexp_;
8584 bool regexp_success_;
8585 bool morph_success_;
8586 i::Handle<i::String> input_;
8587 AsciiVectorResource ascii_resource_;
8588 UC16VectorResource uc16_resource_;
8589};
8590
8591
8592// Test that a regular expression execution can be interrupted and
8593// the string changed without failing.
8594TEST(RegExpStringModification) {
8595 v8::Locker lock;
8596 v8::V8::Initialize();
8597 v8::HandleScope scope;
8598 Local<Context> local_env;
8599 {
8600 LocalContext env;
8601 local_env = env.local();
8602 }
8603
8604 // Local context should still be live.
8605 CHECK(!local_env.IsEmpty());
8606 local_env->Enter();
8607
8608 // Should complete without problems.
8609 RegExpStringModificationTest().RunTest();
8610
8611 local_env->Exit();
8612}
8613
8614
8615// Test that we can set a property on the global object even if there
8616// is a read-only property in the prototype chain.
8617TEST(ReadOnlyPropertyInGlobalProto) {
8618 v8::HandleScope scope;
8619 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8620 LocalContext context(0, templ);
8621 v8::Handle<v8::Object> global = context->Global();
8622 v8::Handle<v8::Object> global_proto =
8623 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
8624 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
8625 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
8626 // Check without 'eval' or 'with'.
8627 v8::Handle<v8::Value> res =
8628 CompileRun("function f() { x = 42; return x; }; f()");
8629 // Check with 'eval'.
8630 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
8631 CHECK_EQ(v8::Integer::New(42), res);
8632 // Check with 'with'.
8633 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
8634 CHECK_EQ(v8::Integer::New(42), res);
8635}
8636
8637static int force_set_set_count = 0;
8638static int force_set_get_count = 0;
8639bool pass_on_get = false;
8640
8641static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
8642 const v8::AccessorInfo& info) {
8643 force_set_get_count++;
8644 if (pass_on_get) {
8645 return v8::Handle<v8::Value>();
8646 } else {
8647 return v8::Int32::New(3);
8648 }
8649}
8650
8651static void ForceSetSetter(v8::Local<v8::String> name,
8652 v8::Local<v8::Value> value,
8653 const v8::AccessorInfo& info) {
8654 force_set_set_count++;
8655}
8656
8657static v8::Handle<v8::Value> ForceSetInterceptSetter(
8658 v8::Local<v8::String> name,
8659 v8::Local<v8::Value> value,
8660 const v8::AccessorInfo& info) {
8661 force_set_set_count++;
8662 return v8::Undefined();
8663}
8664
8665TEST(ForceSet) {
8666 force_set_get_count = 0;
8667 force_set_set_count = 0;
8668 pass_on_get = false;
8669
8670 v8::HandleScope scope;
8671 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8672 v8::Handle<v8::String> access_property = v8::String::New("a");
8673 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
8674 LocalContext context(NULL, templ);
8675 v8::Handle<v8::Object> global = context->Global();
8676
8677 // Ordinary properties
8678 v8::Handle<v8::String> simple_property = v8::String::New("p");
8679 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
8680 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8681 // This should fail because the property is read-only
8682 global->Set(simple_property, v8::Int32::New(5));
8683 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8684 // This should succeed even though the property is read-only
8685 global->ForceSet(simple_property, v8::Int32::New(6));
8686 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
8687
8688 // Accessors
8689 CHECK_EQ(0, force_set_set_count);
8690 CHECK_EQ(0, force_set_get_count);
8691 CHECK_EQ(3, global->Get(access_property)->Int32Value());
8692 // CHECK_EQ the property shouldn't override it, just call the setter
8693 // which in this case does nothing.
8694 global->Set(access_property, v8::Int32::New(7));
8695 CHECK_EQ(3, global->Get(access_property)->Int32Value());
8696 CHECK_EQ(1, force_set_set_count);
8697 CHECK_EQ(2, force_set_get_count);
8698 // Forcing the property to be set should override the accessor without
8699 // calling it
8700 global->ForceSet(access_property, v8::Int32::New(8));
8701 CHECK_EQ(8, global->Get(access_property)->Int32Value());
8702 CHECK_EQ(1, force_set_set_count);
8703 CHECK_EQ(2, force_set_get_count);
8704}
8705
8706TEST(ForceSetWithInterceptor) {
8707 force_set_get_count = 0;
8708 force_set_set_count = 0;
8709 pass_on_get = false;
8710
8711 v8::HandleScope scope;
8712 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8713 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
8714 LocalContext context(NULL, templ);
8715 v8::Handle<v8::Object> global = context->Global();
8716
8717 v8::Handle<v8::String> some_property = v8::String::New("a");
8718 CHECK_EQ(0, force_set_set_count);
8719 CHECK_EQ(0, force_set_get_count);
8720 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8721 // Setting the property shouldn't override it, just call the setter
8722 // which in this case does nothing.
8723 global->Set(some_property, v8::Int32::New(7));
8724 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8725 CHECK_EQ(1, force_set_set_count);
8726 CHECK_EQ(2, force_set_get_count);
8727 // Getting the property when the interceptor returns an empty handle
8728 // should yield undefined, since the property isn't present on the
8729 // object itself yet.
8730 pass_on_get = true;
8731 CHECK(global->Get(some_property)->IsUndefined());
8732 CHECK_EQ(1, force_set_set_count);
8733 CHECK_EQ(3, force_set_get_count);
8734 // Forcing the property to be set should cause the value to be
8735 // set locally without calling the interceptor.
8736 global->ForceSet(some_property, v8::Int32::New(8));
8737 CHECK_EQ(8, global->Get(some_property)->Int32Value());
8738 CHECK_EQ(1, force_set_set_count);
8739 CHECK_EQ(4, force_set_get_count);
8740 // Reenabling the interceptor should cause it to take precedence over
8741 // the property
8742 pass_on_get = false;
8743 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8744 CHECK_EQ(1, force_set_set_count);
8745 CHECK_EQ(5, force_set_get_count);
8746 // The interceptor should also work for other properties
8747 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
8748 CHECK_EQ(1, force_set_set_count);
8749 CHECK_EQ(6, force_set_get_count);
8750}
8751
8752
8753THREADED_TEST(ForceDelete) {
8754 v8::HandleScope scope;
8755 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8756 LocalContext context(NULL, templ);
8757 v8::Handle<v8::Object> global = context->Global();
8758
8759 // Ordinary properties
8760 v8::Handle<v8::String> simple_property = v8::String::New("p");
8761 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
8762 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8763 // This should fail because the property is dont-delete.
8764 CHECK(!global->Delete(simple_property));
8765 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8766 // This should succeed even though the property is dont-delete.
8767 CHECK(global->ForceDelete(simple_property));
8768 CHECK(global->Get(simple_property)->IsUndefined());
8769}
8770
8771
8772static int force_delete_interceptor_count = 0;
8773static bool pass_on_delete = false;
8774
8775
8776static v8::Handle<v8::Boolean> ForceDeleteDeleter(
8777 v8::Local<v8::String> name,
8778 const v8::AccessorInfo& info) {
8779 force_delete_interceptor_count++;
8780 if (pass_on_delete) {
8781 return v8::Handle<v8::Boolean>();
8782 } else {
8783 return v8::True();
8784 }
8785}
8786
8787
8788THREADED_TEST(ForceDeleteWithInterceptor) {
8789 force_delete_interceptor_count = 0;
8790 pass_on_delete = false;
8791
8792 v8::HandleScope scope;
8793 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8794 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
8795 LocalContext context(NULL, templ);
8796 v8::Handle<v8::Object> global = context->Global();
8797
8798 v8::Handle<v8::String> some_property = v8::String::New("a");
8799 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
8800
8801 // Deleting a property should get intercepted and nothing should
8802 // happen.
8803 CHECK_EQ(0, force_delete_interceptor_count);
8804 CHECK(global->Delete(some_property));
8805 CHECK_EQ(1, force_delete_interceptor_count);
8806 CHECK_EQ(42, global->Get(some_property)->Int32Value());
8807 // Deleting the property when the interceptor returns an empty
8808 // handle should not delete the property since it is DontDelete.
8809 pass_on_delete = true;
8810 CHECK(!global->Delete(some_property));
8811 CHECK_EQ(2, force_delete_interceptor_count);
8812 CHECK_EQ(42, global->Get(some_property)->Int32Value());
8813 // Forcing the property to be deleted should delete the value
8814 // without calling the interceptor.
8815 CHECK(global->ForceDelete(some_property));
8816 CHECK(global->Get(some_property)->IsUndefined());
8817 CHECK_EQ(2, force_delete_interceptor_count);
8818}
8819
8820
8821// Make sure that forcing a delete invalidates any IC stubs, so we
8822// don't read the hole value.
8823THREADED_TEST(ForceDeleteIC) {
8824 v8::HandleScope scope;
8825 LocalContext context;
8826 // Create a DontDelete variable on the global object.
8827 CompileRun("this.__proto__ = { foo: 'horse' };"
8828 "var foo = 'fish';"
8829 "function f() { return foo.length; }");
8830 // Initialize the IC for foo in f.
8831 CompileRun("for (var i = 0; i < 4; i++) f();");
8832 // Make sure the value of foo is correct before the deletion.
8833 CHECK_EQ(4, CompileRun("f()")->Int32Value());
8834 // Force the deletion of foo.
8835 CHECK(context->Global()->ForceDelete(v8_str("foo")));
8836 // Make sure the value for foo is read from the prototype, and that
8837 // we don't get in trouble with reading the deleted cell value
8838 // sentinel.
8839 CHECK_EQ(5, CompileRun("f()")->Int32Value());
8840}
8841
8842
8843v8::Persistent<Context> calling_context0;
8844v8::Persistent<Context> calling_context1;
8845v8::Persistent<Context> calling_context2;
8846
8847
8848// Check that the call to the callback is initiated in
8849// calling_context2, the directly calling context is calling_context1
8850// and the callback itself is in calling_context0.
8851static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
8852 ApiTestFuzzer::Fuzz();
8853 CHECK(Context::GetCurrent() == calling_context0);
8854 CHECK(Context::GetCalling() == calling_context1);
8855 CHECK(Context::GetEntered() == calling_context2);
8856 return v8::Integer::New(42);
8857}
8858
8859
8860THREADED_TEST(GetCallingContext) {
8861 v8::HandleScope scope;
8862
8863 calling_context0 = Context::New();
8864 calling_context1 = Context::New();
8865 calling_context2 = Context::New();
8866
8867 // Allow cross-domain access.
8868 Local<String> token = v8_str("<security token>");
8869 calling_context0->SetSecurityToken(token);
8870 calling_context1->SetSecurityToken(token);
8871 calling_context2->SetSecurityToken(token);
8872
8873 // Create an object with a C++ callback in context0.
8874 calling_context0->Enter();
8875 Local<v8::FunctionTemplate> callback_templ =
8876 v8::FunctionTemplate::New(GetCallingContextCallback);
8877 calling_context0->Global()->Set(v8_str("callback"),
8878 callback_templ->GetFunction());
8879 calling_context0->Exit();
8880
8881 // Expose context0 in context1 and setup a function that calls the
8882 // callback function.
8883 calling_context1->Enter();
8884 calling_context1->Global()->Set(v8_str("context0"),
8885 calling_context0->Global());
8886 CompileRun("function f() { context0.callback() }");
8887 calling_context1->Exit();
8888
8889 // Expose context1 in context2 and call the callback function in
8890 // context0 indirectly through f in context1.
8891 calling_context2->Enter();
8892 calling_context2->Global()->Set(v8_str("context1"),
8893 calling_context1->Global());
8894 CompileRun("context1.f()");
8895 calling_context2->Exit();
8896
8897 // Dispose the contexts to allow them to be garbage collected.
8898 calling_context0.Dispose();
8899 calling_context1.Dispose();
8900 calling_context2.Dispose();
8901 calling_context0.Clear();
8902 calling_context1.Clear();
8903 calling_context2.Clear();
8904}
8905
8906
8907// Check that a variable declaration with no explicit initialization
8908// value does not shadow an existing property in the prototype chain.
8909//
8910// This is consistent with Firefox and Safari.
8911//
8912// See http://crbug.com/12548.
8913THREADED_TEST(InitGlobalVarInProtoChain) {
8914 v8::HandleScope scope;
8915 LocalContext context;
8916 // Introduce a variable in the prototype chain.
8917 CompileRun("__proto__.x = 42");
8918 v8::Handle<v8::Value> result = CompileRun("var x; x");
8919 CHECK(!result->IsUndefined());
8920 CHECK_EQ(42, result->Int32Value());
8921}
8922
8923
8924// Regression test for issue 398.
8925// If a function is added to an object, creating a constant function
8926// field, and the result is cloned, replacing the constant function on the
8927// original should not affect the clone.
8928// See http://code.google.com/p/v8/issues/detail?id=398
8929THREADED_TEST(ReplaceConstantFunction) {
8930 v8::HandleScope scope;
8931 LocalContext context;
8932 v8::Handle<v8::Object> obj = v8::Object::New();
8933 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
8934 v8::Handle<v8::String> foo_string = v8::String::New("foo");
8935 obj->Set(foo_string, func_templ->GetFunction());
8936 v8::Handle<v8::Object> obj_clone = obj->Clone();
8937 obj_clone->Set(foo_string, v8::String::New("Hello"));
8938 CHECK(!obj->Get(foo_string)->IsUndefined());
8939}
8940
8941
8942// Regression test for http://crbug.com/16276.
8943THREADED_TEST(Regress16276) {
8944 v8::HandleScope scope;
8945 LocalContext context;
8946 // Force the IC in f to be a dictionary load IC.
8947 CompileRun("function f(obj) { return obj.x; }\n"
8948 "var obj = { x: { foo: 42 }, y: 87 };\n"
8949 "var x = obj.x;\n"
8950 "delete obj.y;\n"
8951 "for (var i = 0; i < 5; i++) f(obj);");
8952 // Detach the global object to make 'this' refer directly to the
8953 // global object (not the proxy), and make sure that the dictionary
8954 // load IC doesn't mess up loading directly from the global object.
8955 context->DetachGlobal();
8956 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
8957}
8958
8959
8960THREADED_TEST(PixelArray) {
8961 v8::HandleScope scope;
8962 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +00008963 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +00008964 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
8965 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
8966 pixel_data);
8967 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
8968 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +00008969 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +00008970 }
8971 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
8972 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +00008973 CHECK_EQ(i % 256, pixels->get(i));
8974 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00008975 }
8976
8977 v8::Handle<v8::Object> obj = v8::Object::New();
8978 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
8979 // Set the elements to be the pixels.
8980 // jsobj->set_elements(*pixels);
8981 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
8982 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
8983 obj->Set(v8_str("field"), v8::Int32::New(1503));
8984 context->Global()->Set(v8_str("pixels"), obj);
8985 v8::Handle<v8::Value> result = CompileRun("pixels.field");
8986 CHECK_EQ(1503, result->Int32Value());
8987 result = CompileRun("pixels[1]");
8988 CHECK_EQ(1, result->Int32Value());
8989
8990 result = CompileRun("var sum = 0;"
8991 "for (var i = 0; i < 8; i++) {"
8992 " sum += pixels[i] = pixels[i] = -i;"
8993 "}"
8994 "sum;");
8995 CHECK_EQ(-28, result->Int32Value());
8996
8997 result = CompileRun("var sum = 0;"
8998 "for (var i = 0; i < 8; i++) {"
8999 " sum += pixels[i] = pixels[i] = 0;"
9000 "}"
9001 "sum;");
9002 CHECK_EQ(0, result->Int32Value());
9003
9004 result = CompileRun("var sum = 0;"
9005 "for (var i = 0; i < 8; i++) {"
9006 " sum += pixels[i] = pixels[i] = 255;"
9007 "}"
9008 "sum;");
9009 CHECK_EQ(8 * 255, result->Int32Value());
9010
9011 result = CompileRun("var sum = 0;"
9012 "for (var i = 0; i < 8; i++) {"
9013 " sum += pixels[i] = pixels[i] = 256 + i;"
9014 "}"
9015 "sum;");
9016 CHECK_EQ(2076, result->Int32Value());
9017
9018 result = CompileRun("var sum = 0;"
9019 "for (var i = 0; i < 8; i++) {"
9020 " sum += pixels[i] = pixels[i] = i;"
9021 "}"
9022 "sum;");
9023 CHECK_EQ(28, result->Int32Value());
9024
9025 result = CompileRun("var sum = 0;"
9026 "for (var i = 0; i < 8; i++) {"
9027 " sum += pixels[i];"
9028 "}"
9029 "sum;");
9030 CHECK_EQ(28, result->Int32Value());
9031
9032 i::Handle<i::Smi> value(i::Smi::FromInt(2));
9033 i::SetElement(jsobj, 1, value);
9034 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9035 *value.location() = i::Smi::FromInt(256);
9036 i::SetElement(jsobj, 1, value);
9037 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9038 *value.location() = i::Smi::FromInt(-1);
9039 i::SetElement(jsobj, 1, value);
9040 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9041
9042 result = CompileRun("for (var i = 0; i < 8; i++) {"
9043 " pixels[i] = (i * 65) - 109;"
9044 "}"
9045 "pixels[1] + pixels[6];");
9046 CHECK_EQ(255, result->Int32Value());
9047 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9048 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9049 CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9050 CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9051 CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9052 CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9053 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9054 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9055 result = CompileRun("var sum = 0;"
9056 "for (var i = 0; i < 8; i++) {"
9057 " sum += pixels[i];"
9058 "}"
9059 "sum;");
9060 CHECK_EQ(984, result->Int32Value());
9061
9062 result = CompileRun("for (var i = 0; i < 8; i++) {"
9063 " pixels[i] = (i * 1.1);"
9064 "}"
9065 "pixels[1] + pixels[6];");
9066 CHECK_EQ(8, result->Int32Value());
9067 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9068 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9069 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9070 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9071 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9072 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9073 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9074 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9075
9076 result = CompileRun("for (var i = 0; i < 8; i++) {"
9077 " pixels[7] = undefined;"
9078 "}"
9079 "pixels[7];");
9080 CHECK_EQ(0, result->Int32Value());
9081 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9082
9083 result = CompileRun("for (var i = 0; i < 8; i++) {"
9084 " pixels[6] = '2.3';"
9085 "}"
9086 "pixels[6];");
9087 CHECK_EQ(2, result->Int32Value());
9088 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9089
9090 result = CompileRun("for (var i = 0; i < 8; i++) {"
9091 " pixels[5] = NaN;"
9092 "}"
9093 "pixels[5];");
9094 CHECK_EQ(0, result->Int32Value());
9095 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9096
9097 result = CompileRun("for (var i = 0; i < 8; i++) {"
9098 " pixels[8] = Infinity;"
9099 "}"
9100 "pixels[8];");
9101 CHECK_EQ(255, result->Int32Value());
9102 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9103
9104 result = CompileRun("for (var i = 0; i < 8; i++) {"
9105 " pixels[9] = -Infinity;"
9106 "}"
9107 "pixels[9];");
9108 CHECK_EQ(0, result->Int32Value());
9109 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9110
9111 result = CompileRun("pixels[3] = 33;"
9112 "delete pixels[3];"
9113 "pixels[3];");
9114 CHECK_EQ(33, result->Int32Value());
9115
9116 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9117 "pixels[2] = 12; pixels[3] = 13;"
9118 "pixels.__defineGetter__('2',"
9119 "function() { return 120; });"
9120 "pixels[2];");
9121 CHECK_EQ(12, result->Int32Value());
9122
9123 result = CompileRun("var js_array = new Array(40);"
9124 "js_array[0] = 77;"
9125 "js_array;");
9126 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9127
9128 result = CompileRun("pixels[1] = 23;"
9129 "pixels.__proto__ = [];"
9130 "js_array.__proto__ = pixels;"
9131 "js_array.concat(pixels);");
9132 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9133 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9134
9135 result = CompileRun("pixels[1] = 23;");
9136 CHECK_EQ(23, result->Int32Value());
9137
Steve Blockd0582a62009-12-15 09:54:21 +00009138 // Test for index greater than 255. Regression test for:
9139 // http://code.google.com/p/chromium/issues/detail?id=26337.
9140 result = CompileRun("pixels[256] = 255;");
9141 CHECK_EQ(255, result->Int32Value());
9142 result = CompileRun("var i = 0;"
9143 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9144 "i");
9145 CHECK_EQ(255, result->Int32Value());
9146
Steve Blocka7e24c12009-10-30 11:49:00 +00009147 free(pixel_data);
9148}
9149
9150
Steve Block3ce2e202009-11-05 08:53:23 +00009151template <class ExternalArrayClass, class ElementType>
9152static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9153 int64_t low,
9154 int64_t high) {
9155 v8::HandleScope scope;
9156 LocalContext context;
9157 const int kElementCount = 40;
9158 int element_size = 0;
9159 switch (array_type) {
9160 case v8::kExternalByteArray:
9161 case v8::kExternalUnsignedByteArray:
9162 element_size = 1;
9163 break;
9164 case v8::kExternalShortArray:
9165 case v8::kExternalUnsignedShortArray:
9166 element_size = 2;
9167 break;
9168 case v8::kExternalIntArray:
9169 case v8::kExternalUnsignedIntArray:
9170 case v8::kExternalFloatArray:
9171 element_size = 4;
9172 break;
9173 default:
9174 UNREACHABLE();
9175 break;
9176 }
9177 ElementType* array_data =
9178 static_cast<ElementType*>(malloc(kElementCount * element_size));
9179 i::Handle<ExternalArrayClass> array =
9180 i::Handle<ExternalArrayClass>::cast(
9181 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9182 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9183 for (int i = 0; i < kElementCount; i++) {
9184 array->set(i, static_cast<ElementType>(i));
9185 }
9186 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9187 for (int i = 0; i < kElementCount; i++) {
9188 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9189 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9190 }
9191
9192 v8::Handle<v8::Object> obj = v8::Object::New();
9193 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9194 // Set the elements to be the external array.
9195 obj->SetIndexedPropertiesToExternalArrayData(array_data,
9196 array_type,
9197 kElementCount);
9198 CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9199 obj->Set(v8_str("field"), v8::Int32::New(1503));
9200 context->Global()->Set(v8_str("ext_array"), obj);
9201 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9202 CHECK_EQ(1503, result->Int32Value());
9203 result = CompileRun("ext_array[1]");
9204 CHECK_EQ(1, result->Int32Value());
9205
9206 // Check pass through of assigned smis
9207 result = CompileRun("var sum = 0;"
9208 "for (var i = 0; i < 8; i++) {"
9209 " sum += ext_array[i] = ext_array[i] = -i;"
9210 "}"
9211 "sum;");
9212 CHECK_EQ(-28, result->Int32Value());
9213
9214 // Check assigned smis
9215 result = CompileRun("for (var i = 0; i < 8; i++) {"
9216 " ext_array[i] = i;"
9217 "}"
9218 "var sum = 0;"
9219 "for (var i = 0; i < 8; i++) {"
9220 " sum += ext_array[i];"
9221 "}"
9222 "sum;");
9223 CHECK_EQ(28, result->Int32Value());
9224
9225 // Check assigned smis in reverse order
9226 result = CompileRun("for (var i = 8; --i >= 0; ) {"
9227 " ext_array[i] = i;"
9228 "}"
9229 "var sum = 0;"
9230 "for (var i = 0; i < 8; i++) {"
9231 " sum += ext_array[i];"
9232 "}"
9233 "sum;");
9234 CHECK_EQ(28, result->Int32Value());
9235
9236 // Check pass through of assigned HeapNumbers
9237 result = CompileRun("var sum = 0;"
9238 "for (var i = 0; i < 16; i+=2) {"
9239 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9240 "}"
9241 "sum;");
9242 CHECK_EQ(-28, result->Int32Value());
9243
9244 // Check assigned HeapNumbers
9245 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9246 " ext_array[i] = (i * 0.5);"
9247 "}"
9248 "var sum = 0;"
9249 "for (var i = 0; i < 16; i+=2) {"
9250 " sum += ext_array[i];"
9251 "}"
9252 "sum;");
9253 CHECK_EQ(28, result->Int32Value());
9254
9255 // Check assigned HeapNumbers in reverse order
9256 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9257 " ext_array[i] = (i * 0.5);"
9258 "}"
9259 "var sum = 0;"
9260 "for (var i = 0; i < 16; i+=2) {"
9261 " sum += ext_array[i];"
9262 "}"
9263 "sum;");
9264 CHECK_EQ(28, result->Int32Value());
9265
9266 i::ScopedVector<char> test_buf(1024);
9267
9268 // Check legal boundary conditions.
9269 // The repeated loads and stores ensure the ICs are exercised.
9270 const char* boundary_program =
9271 "var res = 0;"
9272 "for (var i = 0; i < 16; i++) {"
9273 " ext_array[i] = %lld;"
9274 " if (i > 8) {"
9275 " res = ext_array[i];"
9276 " }"
9277 "}"
9278 "res;";
9279 i::OS::SNPrintF(test_buf,
9280 boundary_program,
9281 low);
9282 result = CompileRun(test_buf.start());
9283 CHECK_EQ(low, result->IntegerValue());
9284
9285 i::OS::SNPrintF(test_buf,
9286 boundary_program,
9287 high);
9288 result = CompileRun(test_buf.start());
9289 CHECK_EQ(high, result->IntegerValue());
9290
9291 // Check misprediction of type in IC.
9292 result = CompileRun("var tmp_array = ext_array;"
9293 "var sum = 0;"
9294 "for (var i = 0; i < 8; i++) {"
9295 " tmp_array[i] = i;"
9296 " sum += tmp_array[i];"
9297 " if (i == 4) {"
9298 " tmp_array = {};"
9299 " }"
9300 "}"
9301 "sum;");
9302 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9303 CHECK_EQ(28, result->Int32Value());
9304
9305 // Make sure out-of-range loads do not throw.
9306 i::OS::SNPrintF(test_buf,
9307 "var caught_exception = false;"
9308 "try {"
9309 " ext_array[%d];"
9310 "} catch (e) {"
9311 " caught_exception = true;"
9312 "}"
9313 "caught_exception;",
9314 kElementCount);
9315 result = CompileRun(test_buf.start());
9316 CHECK_EQ(false, result->BooleanValue());
9317
9318 // Make sure out-of-range stores do not throw.
9319 i::OS::SNPrintF(test_buf,
9320 "var caught_exception = false;"
9321 "try {"
9322 " ext_array[%d] = 1;"
9323 "} catch (e) {"
9324 " caught_exception = true;"
9325 "}"
9326 "caught_exception;",
9327 kElementCount);
9328 result = CompileRun(test_buf.start());
9329 CHECK_EQ(false, result->BooleanValue());
9330
9331 // Check other boundary conditions, values and operations.
9332 result = CompileRun("for (var i = 0; i < 8; i++) {"
9333 " ext_array[7] = undefined;"
9334 "}"
9335 "ext_array[7];");
9336 CHECK_EQ(0, result->Int32Value());
9337 CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9338
9339 result = CompileRun("for (var i = 0; i < 8; i++) {"
9340 " ext_array[6] = '2.3';"
9341 "}"
9342 "ext_array[6];");
9343 CHECK_EQ(2, result->Int32Value());
9344 CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9345
9346 if (array_type != v8::kExternalFloatArray) {
9347 // Though the specification doesn't state it, be explicit about
9348 // converting NaNs and +/-Infinity to zero.
9349 result = CompileRun("for (var i = 0; i < 8; i++) {"
9350 " ext_array[i] = 5;"
9351 "}"
9352 "for (var i = 0; i < 8; i++) {"
9353 " ext_array[i] = NaN;"
9354 "}"
9355 "ext_array[5];");
9356 CHECK_EQ(0, result->Int32Value());
9357 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9358
9359 result = CompileRun("for (var i = 0; i < 8; i++) {"
9360 " ext_array[i] = 5;"
9361 "}"
9362 "for (var i = 0; i < 8; i++) {"
9363 " ext_array[i] = Infinity;"
9364 "}"
9365 "ext_array[5];");
9366 CHECK_EQ(0, result->Int32Value());
9367 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9368
9369 result = CompileRun("for (var i = 0; i < 8; i++) {"
9370 " ext_array[i] = 5;"
9371 "}"
9372 "for (var i = 0; i < 8; i++) {"
9373 " ext_array[i] = -Infinity;"
9374 "}"
9375 "ext_array[5];");
9376 CHECK_EQ(0, result->Int32Value());
9377 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9378 }
9379
9380 result = CompileRun("ext_array[3] = 33;"
9381 "delete ext_array[3];"
9382 "ext_array[3];");
9383 CHECK_EQ(33, result->Int32Value());
9384
9385 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9386 "ext_array[2] = 12; ext_array[3] = 13;"
9387 "ext_array.__defineGetter__('2',"
9388 "function() { return 120; });"
9389 "ext_array[2];");
9390 CHECK_EQ(12, result->Int32Value());
9391
9392 result = CompileRun("var js_array = new Array(40);"
9393 "js_array[0] = 77;"
9394 "js_array;");
9395 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9396
9397 result = CompileRun("ext_array[1] = 23;"
9398 "ext_array.__proto__ = [];"
9399 "js_array.__proto__ = ext_array;"
9400 "js_array.concat(ext_array);");
9401 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9402 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9403
9404 result = CompileRun("ext_array[1] = 23;");
9405 CHECK_EQ(23, result->Int32Value());
9406
Steve Blockd0582a62009-12-15 09:54:21 +00009407 // Test more complex manipulations which cause eax to contain values
9408 // that won't be completely overwritten by loads from the arrays.
9409 // This catches bugs in the instructions used for the KeyedLoadIC
9410 // for byte and word types.
9411 {
9412 const int kXSize = 300;
9413 const int kYSize = 300;
9414 const int kLargeElementCount = kXSize * kYSize * 4;
9415 ElementType* large_array_data =
9416 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9417 i::Handle<ExternalArrayClass> large_array =
9418 i::Handle<ExternalArrayClass>::cast(
9419 i::Factory::NewExternalArray(kLargeElementCount,
9420 array_type,
9421 array_data));
9422 v8::Handle<v8::Object> large_obj = v8::Object::New();
9423 // Set the elements to be the external array.
9424 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9425 array_type,
9426 kLargeElementCount);
9427 context->Global()->Set(v8_str("large_array"), large_obj);
9428 // Initialize contents of a few rows.
9429 for (int x = 0; x < 300; x++) {
9430 int row = 0;
9431 int offset = row * 300 * 4;
9432 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9433 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9434 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9435 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9436 row = 150;
9437 offset = row * 300 * 4;
9438 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9439 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9440 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9441 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9442 row = 298;
9443 offset = row * 300 * 4;
9444 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9445 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9446 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9447 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9448 }
9449 // The goal of the code below is to make "offset" large enough
9450 // that the computation of the index (which goes into eax) has
9451 // high bits set which will not be overwritten by a byte or short
9452 // load.
9453 result = CompileRun("var failed = false;"
9454 "var offset = 0;"
9455 "for (var i = 0; i < 300; i++) {"
9456 " if (large_array[4 * i] != 127 ||"
9457 " large_array[4 * i + 1] != 0 ||"
9458 " large_array[4 * i + 2] != 0 ||"
9459 " large_array[4 * i + 3] != 127) {"
9460 " failed = true;"
9461 " }"
9462 "}"
9463 "offset = 150 * 300 * 4;"
9464 "for (var i = 0; i < 300; i++) {"
9465 " if (large_array[offset + 4 * i] != 127 ||"
9466 " large_array[offset + 4 * i + 1] != 0 ||"
9467 " large_array[offset + 4 * i + 2] != 0 ||"
9468 " large_array[offset + 4 * i + 3] != 127) {"
9469 " failed = true;"
9470 " }"
9471 "}"
9472 "offset = 298 * 300 * 4;"
9473 "for (var i = 0; i < 300; i++) {"
9474 " if (large_array[offset + 4 * i] != 127 ||"
9475 " large_array[offset + 4 * i + 1] != 0 ||"
9476 " large_array[offset + 4 * i + 2] != 0 ||"
9477 " large_array[offset + 4 * i + 3] != 127) {"
9478 " failed = true;"
9479 " }"
9480 "}"
9481 "!failed;");
9482 CHECK_EQ(true, result->BooleanValue());
9483 free(large_array_data);
9484 }
9485
Steve Block3ce2e202009-11-05 08:53:23 +00009486 free(array_data);
9487}
9488
9489
9490THREADED_TEST(ExternalByteArray) {
9491 ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
9492 v8::kExternalByteArray,
9493 -128,
9494 127);
9495}
9496
9497
9498THREADED_TEST(ExternalUnsignedByteArray) {
9499 ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
9500 v8::kExternalUnsignedByteArray,
9501 0,
9502 255);
9503}
9504
9505
9506THREADED_TEST(ExternalShortArray) {
9507 ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
9508 v8::kExternalShortArray,
9509 -32768,
9510 32767);
9511}
9512
9513
9514THREADED_TEST(ExternalUnsignedShortArray) {
9515 ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
9516 v8::kExternalUnsignedShortArray,
9517 0,
9518 65535);
9519}
9520
9521
9522THREADED_TEST(ExternalIntArray) {
9523 ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
9524 v8::kExternalIntArray,
9525 INT_MIN, // -2147483648
9526 INT_MAX); // 2147483647
9527}
9528
9529
9530THREADED_TEST(ExternalUnsignedIntArray) {
9531 ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
9532 v8::kExternalUnsignedIntArray,
9533 0,
9534 UINT_MAX); // 4294967295
9535}
9536
9537
9538THREADED_TEST(ExternalFloatArray) {
9539 ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
9540 v8::kExternalFloatArray,
9541 -500,
9542 500);
9543}
9544
9545
9546THREADED_TEST(ExternalArrays) {
9547 TestExternalByteArray();
9548 TestExternalUnsignedByteArray();
9549 TestExternalShortArray();
9550 TestExternalUnsignedShortArray();
9551 TestExternalIntArray();
9552 TestExternalUnsignedIntArray();
9553 TestExternalFloatArray();
9554}
9555
9556
Steve Blocka7e24c12009-10-30 11:49:00 +00009557THREADED_TEST(ScriptContextDependence) {
9558 v8::HandleScope scope;
9559 LocalContext c1;
9560 const char *source = "foo";
9561 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
9562 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
9563 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
9564 CHECK_EQ(dep->Run()->Int32Value(), 100);
9565 CHECK_EQ(indep->Run()->Int32Value(), 100);
9566 LocalContext c2;
9567 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
9568 CHECK_EQ(dep->Run()->Int32Value(), 100);
9569 CHECK_EQ(indep->Run()->Int32Value(), 101);
9570}
9571
9572
9573THREADED_TEST(StackTrace) {
9574 v8::HandleScope scope;
9575 LocalContext context;
9576 v8::TryCatch try_catch;
9577 const char *source = "function foo() { FAIL.FAIL; }; foo();";
9578 v8::Handle<v8::String> src = v8::String::New(source);
9579 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
9580 v8::Script::New(src, origin)->Run();
9581 CHECK(try_catch.HasCaught());
9582 v8::String::Utf8Value stack(try_catch.StackTrace());
9583 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
9584}
9585
9586
Kristian Monsen25f61362010-05-21 11:50:48 +01009587// Checks that a StackFrame has certain expected values.
9588void checkStackFrame(const char* expected_script_name,
9589 const char* expected_func_name, int expected_line_number,
9590 int expected_column, bool is_eval, bool is_constructor,
9591 v8::Handle<v8::StackFrame> frame) {
9592 v8::HandleScope scope;
9593 v8::String::Utf8Value func_name(frame->GetFunctionName());
9594 v8::String::Utf8Value script_name(frame->GetScriptName());
9595 if (*script_name == NULL) {
9596 // The situation where there is no associated script, like for evals.
9597 CHECK(expected_script_name == NULL);
9598 } else {
9599 CHECK(strstr(*script_name, expected_script_name) != NULL);
9600 }
9601 CHECK(strstr(*func_name, expected_func_name) != NULL);
9602 CHECK_EQ(expected_line_number, frame->GetLineNumber());
9603 CHECK_EQ(expected_column, frame->GetColumn());
9604 CHECK_EQ(is_eval, frame->IsEval());
9605 CHECK_EQ(is_constructor, frame->IsConstructor());
9606}
9607
9608
9609v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
9610 v8::HandleScope scope;
9611 const char* origin = "capture-stack-trace-test";
9612 const int kOverviewTest = 1;
9613 const int kDetailedTest = 2;
9614
9615 ASSERT(args.Length() == 1);
9616
9617 int testGroup = args[0]->Int32Value();
9618 if (testGroup == kOverviewTest) {
9619 v8::Handle<v8::StackTrace> stackTrace =
9620 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
9621 CHECK_EQ(4, stackTrace->GetFrameCount());
9622 checkStackFrame(origin, "bar", 2, 10, false, false,
9623 stackTrace->GetFrame(0));
9624 checkStackFrame(origin, "foo", 6, 3, false, false,
9625 stackTrace->GetFrame(1));
9626 checkStackFrame(NULL, "", 1, 1, false, false,
9627 stackTrace->GetFrame(2));
9628 // The last frame is an anonymous function that has the initial call.
9629 checkStackFrame(origin, "", 8, 7, false, false,
9630 stackTrace->GetFrame(3));
9631
9632 CHECK(stackTrace->AsArray()->IsArray());
9633 } else if (testGroup == kDetailedTest) {
9634 v8::Handle<v8::StackTrace> stackTrace =
9635 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
9636 CHECK_EQ(4, stackTrace->GetFrameCount());
9637 checkStackFrame(origin, "bat", 4, 22, false, false,
9638 stackTrace->GetFrame(0));
9639 checkStackFrame(origin, "baz", 8, 3, false, true,
9640 stackTrace->GetFrame(1));
9641 checkStackFrame(NULL, "", 1, 1, true, false,
9642 stackTrace->GetFrame(2));
9643 // The last frame is an anonymous function that has the initial call to foo.
9644 checkStackFrame(origin, "", 10, 1, false, false,
9645 stackTrace->GetFrame(3));
9646
9647 CHECK(stackTrace->AsArray()->IsArray());
9648 }
9649 return v8::Undefined();
9650}
9651
9652
9653// Tests the C++ StackTrace API.
9654THREADED_TEST(CaptureStackTrace) {
9655 v8::HandleScope scope;
9656 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
9657 Local<ObjectTemplate> templ = ObjectTemplate::New();
9658 templ->Set(v8_str("AnalyzeStackInNativeCode"),
9659 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
9660 LocalContext context(0, templ);
9661
9662 // Test getting OVERVIEW information. Should ignore information that is not
9663 // script name, function name, line number, and column offset.
9664 const char *overview_source =
9665 "function bar() {\n"
9666 " var y; AnalyzeStackInNativeCode(1);\n"
9667 "}\n"
9668 "function foo() {\n"
9669 "\n"
9670 " bar();\n"
9671 "}\n"
9672 "var x;eval('new foo();');";
9673 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
9674 v8::Handle<Value> overview_result =
9675 v8::Script::New(overview_src, origin)->Run();
9676 ASSERT(!overview_result.IsEmpty());
9677 ASSERT(overview_result->IsObject());
9678
9679 // Test getting DETAILED information.
9680 const char *detailed_source =
9681 "function bat() {AnalyzeStackInNativeCode(2);\n"
9682 "}\n"
9683 "\n"
9684 "function baz() {\n"
9685 " bat();\n"
9686 "}\n"
9687 "eval('new baz();');";
9688 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
9689 // Make the script using a non-zero line and column offset.
9690 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
9691 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
9692 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
9693 v8::Handle<v8::Script> detailed_script(
9694 v8::Script::New(detailed_src, &detailed_origin));
9695 v8::Handle<Value> detailed_result = detailed_script->Run();
9696 ASSERT(!detailed_result.IsEmpty());
9697 ASSERT(detailed_result->IsObject());
9698}
9699
9700
Steve Block3ce2e202009-11-05 08:53:23 +00009701// Test that idle notification can be handled and eventually returns true.
Steve Blocka7e24c12009-10-30 11:49:00 +00009702THREADED_TEST(IdleNotification) {
Steve Block3ce2e202009-11-05 08:53:23 +00009703 bool rv = false;
9704 for (int i = 0; i < 100; i++) {
9705 rv = v8::V8::IdleNotification();
9706 if (rv)
9707 break;
9708 }
9709 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +00009710}
9711
9712
9713static uint32_t* stack_limit;
9714
9715static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
9716 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
9717 return v8::Undefined();
9718}
9719
9720
9721// Uses the address of a local variable to determine the stack top now.
9722// Given a size, returns an address that is that far from the current
9723// top of stack.
9724static uint32_t* ComputeStackLimit(uint32_t size) {
9725 uint32_t* answer = &size - (size / sizeof(size));
9726 // If the size is very large and the stack is very near the bottom of
9727 // memory then the calculation above may wrap around and give an address
9728 // that is above the (downwards-growing) stack. In that case we return
9729 // a very low address.
9730 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
9731 return answer;
9732}
9733
9734
9735TEST(SetResourceConstraints) {
9736 static const int K = 1024;
9737 uint32_t* set_limit = ComputeStackLimit(128 * K);
9738
9739 // Set stack limit.
9740 v8::ResourceConstraints constraints;
9741 constraints.set_stack_limit(set_limit);
9742 CHECK(v8::SetResourceConstraints(&constraints));
9743
9744 // Execute a script.
9745 v8::HandleScope scope;
9746 LocalContext env;
9747 Local<v8::FunctionTemplate> fun_templ =
9748 v8::FunctionTemplate::New(GetStackLimitCallback);
9749 Local<Function> fun = fun_templ->GetFunction();
9750 env->Global()->Set(v8_str("get_stack_limit"), fun);
9751 CompileRun("get_stack_limit();");
9752
9753 CHECK(stack_limit == set_limit);
9754}
9755
9756
9757TEST(SetResourceConstraintsInThread) {
9758 uint32_t* set_limit;
9759 {
9760 v8::Locker locker;
9761 static const int K = 1024;
9762 set_limit = ComputeStackLimit(128 * K);
9763
9764 // Set stack limit.
9765 v8::ResourceConstraints constraints;
9766 constraints.set_stack_limit(set_limit);
9767 CHECK(v8::SetResourceConstraints(&constraints));
9768
9769 // Execute a script.
9770 v8::HandleScope scope;
9771 LocalContext env;
9772 Local<v8::FunctionTemplate> fun_templ =
9773 v8::FunctionTemplate::New(GetStackLimitCallback);
9774 Local<Function> fun = fun_templ->GetFunction();
9775 env->Global()->Set(v8_str("get_stack_limit"), fun);
9776 CompileRun("get_stack_limit();");
9777
9778 CHECK(stack_limit == set_limit);
9779 }
9780 {
9781 v8::Locker locker;
9782 CHECK(stack_limit == set_limit);
9783 }
9784}
Steve Block3ce2e202009-11-05 08:53:23 +00009785
9786
9787THREADED_TEST(GetHeapStatistics) {
9788 v8::HandleScope scope;
9789 LocalContext c1;
9790 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +00009791 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
9792 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +00009793 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +00009794 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
9795 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
9796}
9797
9798
9799static double DoubleFromBits(uint64_t value) {
9800 double target;
9801#ifdef BIG_ENDIAN_FLOATING_POINT
9802 const int kIntSize = 4;
9803 // Somebody swapped the lower and higher half of doubles.
9804 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9805 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9806#else
9807 memcpy(&target, &value, sizeof(target));
9808#endif
9809 return target;
9810}
9811
9812
9813static uint64_t DoubleToBits(double value) {
9814 uint64_t target;
9815#ifdef BIG_ENDIAN_FLOATING_POINT
9816 const int kIntSize = 4;
9817 // Somebody swapped the lower and higher half of doubles.
9818 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9819 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9820#else
9821 memcpy(&target, &value, sizeof(target));
9822#endif
9823 return target;
9824}
9825
9826
9827static double DoubleToDateTime(double input) {
9828 double date_limit = 864e13;
9829 if (IsNaN(input) || input < -date_limit || input > date_limit) {
9830 return i::OS::nan_value();
9831 }
9832 return (input < 0) ? -(floor(-input)) : floor(input);
9833}
9834
9835// We don't have a consistent way to write 64-bit constants syntactically, so we
9836// split them into two 32-bit constants and combine them programmatically.
9837static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
9838 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
9839}
9840
9841
9842THREADED_TEST(QuietSignalingNaNs) {
9843 v8::HandleScope scope;
9844 LocalContext context;
9845 v8::TryCatch try_catch;
9846
9847 // Special double values.
9848 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
9849 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
9850 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
9851 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
9852 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
9853 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
9854 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
9855
9856 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
9857 // on either side of the epoch.
9858 double date_limit = 864e13;
9859
9860 double test_values[] = {
9861 snan,
9862 qnan,
9863 infinity,
9864 max_normal,
9865 date_limit + 1,
9866 date_limit,
9867 min_normal,
9868 max_denormal,
9869 min_denormal,
9870 0,
9871 -0,
9872 -min_denormal,
9873 -max_denormal,
9874 -min_normal,
9875 -date_limit,
9876 -date_limit - 1,
9877 -max_normal,
9878 -infinity,
9879 -qnan,
9880 -snan
9881 };
9882 int num_test_values = 20;
9883
9884 for (int i = 0; i < num_test_values; i++) {
9885 double test_value = test_values[i];
9886
9887 // Check that Number::New preserves non-NaNs and quiets SNaNs.
9888 v8::Handle<v8::Value> number = v8::Number::New(test_value);
9889 double stored_number = number->NumberValue();
9890 if (!IsNaN(test_value)) {
9891 CHECK_EQ(test_value, stored_number);
9892 } else {
9893 uint64_t stored_bits = DoubleToBits(stored_number);
9894 // Check if quiet nan (bits 51..62 all set).
9895 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9896 }
9897
9898 // Check that Date::New preserves non-NaNs in the date range and
9899 // quiets SNaNs.
9900 v8::Handle<v8::Value> date = v8::Date::New(test_value);
9901 double expected_stored_date = DoubleToDateTime(test_value);
9902 double stored_date = date->NumberValue();
9903 if (!IsNaN(expected_stored_date)) {
9904 CHECK_EQ(expected_stored_date, stored_date);
9905 } else {
9906 uint64_t stored_bits = DoubleToBits(stored_date);
9907 // Check if quiet nan (bits 51..62 all set).
9908 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9909 }
9910 }
9911}
9912
9913
9914static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
9915 v8::HandleScope scope;
9916 v8::TryCatch tc;
9917 v8::Handle<v8::String> str = args[0]->ToString();
9918 if (tc.HasCaught())
9919 return tc.ReThrow();
9920 return v8::Undefined();
9921}
9922
9923
9924// Test that an exception can be propagated down through a spaghetti
9925// stack using ReThrow.
9926THREADED_TEST(SpaghettiStackReThrow) {
9927 v8::HandleScope scope;
9928 LocalContext context;
9929 context->Global()->Set(
9930 v8::String::New("s"),
9931 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
9932 v8::TryCatch try_catch;
9933 CompileRun(
9934 "var i = 0;"
9935 "var o = {"
9936 " toString: function () {"
9937 " if (i == 10) {"
9938 " throw 'Hey!';"
9939 " } else {"
9940 " i++;"
9941 " return s(o);"
9942 " }"
9943 " }"
9944 "};"
9945 "s(o);");
9946 CHECK(try_catch.HasCaught());
9947 v8::String::Utf8Value value(try_catch.Exception());
9948 CHECK_EQ(0, strcmp(*value, "Hey!"));
9949}
9950
9951
Steve Blockd0582a62009-12-15 09:54:21 +00009952TEST(Regress528) {
9953 v8::V8::Initialize();
9954
9955 v8::HandleScope scope;
9956 v8::Persistent<Context> context;
9957 v8::Persistent<Context> other_context;
9958 int gc_count;
9959
9960 // Create a context used to keep the code from aging in the compilation
9961 // cache.
9962 other_context = Context::New();
9963
9964 // Context-dependent context data creates reference from the compilation
9965 // cache to the global object.
9966 const char* source_simple = "1";
9967 context = Context::New();
9968 {
9969 v8::HandleScope scope;
9970
9971 context->Enter();
9972 Local<v8::String> obj = v8::String::New("");
9973 context->SetData(obj);
9974 CompileRun(source_simple);
9975 context->Exit();
9976 }
9977 context.Dispose();
9978 for (gc_count = 1; gc_count < 10; gc_count++) {
9979 other_context->Enter();
9980 CompileRun(source_simple);
9981 other_context->Exit();
9982 v8::internal::Heap::CollectAllGarbage(false);
9983 if (GetGlobalObjectsCount() == 1) break;
9984 }
9985 CHECK_GE(2, gc_count);
9986 CHECK_EQ(1, GetGlobalObjectsCount());
9987
9988 // Eval in a function creates reference from the compilation cache to the
9989 // global object.
9990 const char* source_eval = "function f(){eval('1')}; f()";
9991 context = Context::New();
9992 {
9993 v8::HandleScope scope;
9994
9995 context->Enter();
9996 CompileRun(source_eval);
9997 context->Exit();
9998 }
9999 context.Dispose();
10000 for (gc_count = 1; gc_count < 10; gc_count++) {
10001 other_context->Enter();
10002 CompileRun(source_eval);
10003 other_context->Exit();
10004 v8::internal::Heap::CollectAllGarbage(false);
10005 if (GetGlobalObjectsCount() == 1) break;
10006 }
10007 CHECK_GE(2, gc_count);
10008 CHECK_EQ(1, GetGlobalObjectsCount());
10009
10010 // Looking up the line number for an exception creates reference from the
10011 // compilation cache to the global object.
10012 const char* source_exception = "function f(){throw 1;} f()";
10013 context = Context::New();
10014 {
10015 v8::HandleScope scope;
10016
10017 context->Enter();
10018 v8::TryCatch try_catch;
10019 CompileRun(source_exception);
10020 CHECK(try_catch.HasCaught());
10021 v8::Handle<v8::Message> message = try_catch.Message();
10022 CHECK(!message.IsEmpty());
10023 CHECK_EQ(1, message->GetLineNumber());
10024 context->Exit();
10025 }
10026 context.Dispose();
10027 for (gc_count = 1; gc_count < 10; gc_count++) {
10028 other_context->Enter();
10029 CompileRun(source_exception);
10030 other_context->Exit();
10031 v8::internal::Heap::CollectAllGarbage(false);
10032 if (GetGlobalObjectsCount() == 1) break;
10033 }
10034 CHECK_GE(2, gc_count);
10035 CHECK_EQ(1, GetGlobalObjectsCount());
10036
10037 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000010038}
Andrei Popescu402d9372010-02-26 13:31:12 +000010039
10040
10041THREADED_TEST(ScriptOrigin) {
10042 v8::HandleScope scope;
10043 LocalContext env;
10044 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10045 v8::Handle<v8::String> script = v8::String::New(
10046 "function f() {}\n\nfunction g() {}");
10047 v8::Script::Compile(script, &origin)->Run();
10048 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10049 env->Global()->Get(v8::String::New("f")));
10050 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10051 env->Global()->Get(v8::String::New("g")));
10052
10053 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
10054 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
10055 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
10056
10057 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
10058 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
10059 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
10060}
10061
10062
10063THREADED_TEST(ScriptLineNumber) {
10064 v8::HandleScope scope;
10065 LocalContext env;
10066 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
10067 v8::Handle<v8::String> script = v8::String::New(
10068 "function f() {}\n\nfunction g() {}");
10069 v8::Script::Compile(script, &origin)->Run();
10070 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
10071 env->Global()->Get(v8::String::New("f")));
10072 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
10073 env->Global()->Get(v8::String::New("g")));
10074 CHECK_EQ(0, f->GetScriptLineNumber());
10075 CHECK_EQ(2, g->GetScriptLineNumber());
10076}
10077
10078
10079static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
10080 const AccessorInfo& info) {
10081 return v8_num(42);
10082}
10083
10084
10085static void SetterWhichSetsYOnThisTo23(Local<String> name,
10086 Local<Value> value,
10087 const AccessorInfo& info) {
10088 info.This()->Set(v8_str("y"), v8_num(23));
10089}
10090
10091
Steve Block6ded16b2010-05-10 14:33:55 +010010092TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000010093 v8::HandleScope scope;
10094 Local<ObjectTemplate> templ = ObjectTemplate::New();
10095 templ->SetAccessor(v8_str("x"),
10096 GetterWhichReturns42,
10097 SetterWhichSetsYOnThisTo23);
10098 LocalContext context;
10099 context->Global()->Set(v8_str("P"), templ->NewInstance());
10100 CompileRun("function C1() {"
10101 " this.x = 23;"
10102 "};"
10103 "C1.prototype = P;"
10104 "function C2() {"
10105 " this.x = 23"
10106 "};"
10107 "C2.prototype = { };"
10108 "C2.prototype.__proto__ = P;");
10109
10110 v8::Local<v8::Script> script;
10111 script = v8::Script::Compile(v8_str("new C1();"));
10112 for (int i = 0; i < 10; i++) {
10113 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10114 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10115 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10116 }
10117
10118 script = v8::Script::Compile(v8_str("new C2();"));
10119 for (int i = 0; i < 10; i++) {
10120 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10121 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10122 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10123 }
10124}
10125
10126
10127static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10128 Local<String> name, const AccessorInfo& info) {
10129 return v8_num(42);
10130}
10131
10132
10133static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10134 Local<String> name, Local<Value> value, const AccessorInfo& info) {
10135 if (name->Equals(v8_str("x"))) {
10136 info.This()->Set(v8_str("y"), v8_num(23));
10137 }
10138 return v8::Handle<Value>();
10139}
10140
10141
10142THREADED_TEST(InterceptorOnConstructorPrototype) {
10143 v8::HandleScope scope;
10144 Local<ObjectTemplate> templ = ObjectTemplate::New();
10145 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10146 NamedPropertySetterWhichSetsYOnThisTo23);
10147 LocalContext context;
10148 context->Global()->Set(v8_str("P"), templ->NewInstance());
10149 CompileRun("function C1() {"
10150 " this.x = 23;"
10151 "};"
10152 "C1.prototype = P;"
10153 "function C2() {"
10154 " this.x = 23"
10155 "};"
10156 "C2.prototype = { };"
10157 "C2.prototype.__proto__ = P;");
10158
10159 v8::Local<v8::Script> script;
10160 script = v8::Script::Compile(v8_str("new C1();"));
10161 for (int i = 0; i < 10; i++) {
10162 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10163 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10164 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10165 }
10166
10167 script = v8::Script::Compile(v8_str("new C2();"));
10168 for (int i = 0; i < 10; i++) {
10169 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10170 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10171 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10172 }
10173}
Steve Block6ded16b2010-05-10 14:33:55 +010010174
10175
10176TEST(Bug618) {
10177 const char* source = "function C1() {"
10178 " this.x = 23;"
10179 "};"
10180 "C1.prototype = P;";
10181
10182 v8::HandleScope scope;
10183 LocalContext context;
10184 v8::Local<v8::Script> script;
10185
10186 // Use a simple object as prototype.
10187 v8::Local<v8::Object> prototype = v8::Object::New();
10188 prototype->Set(v8_str("y"), v8_num(42));
10189 context->Global()->Set(v8_str("P"), prototype);
10190
10191 // This compile will add the code to the compilation cache.
10192 CompileRun(source);
10193
10194 script = v8::Script::Compile(v8_str("new C1();"));
10195 for (int i = 0; i < 10; i++) {
10196 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10197 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10198 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10199 }
10200
10201 // Use an API object with accessors as prototype.
10202 Local<ObjectTemplate> templ = ObjectTemplate::New();
10203 templ->SetAccessor(v8_str("x"),
10204 GetterWhichReturns42,
10205 SetterWhichSetsYOnThisTo23);
10206 context->Global()->Set(v8_str("P"), templ->NewInstance());
10207
10208 // This compile will get the code from the compilation cache.
10209 CompileRun(source);
10210
10211 script = v8::Script::Compile(v8_str("new C1();"));
10212 for (int i = 0; i < 10; i++) {
10213 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10214 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10215 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10216 }
10217}
10218
10219int prologue_call_count = 0;
10220int epilogue_call_count = 0;
10221int prologue_call_count_second = 0;
10222int epilogue_call_count_second = 0;
10223
10224void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10225 ++prologue_call_count;
10226}
10227
10228void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10229 ++epilogue_call_count;
10230}
10231
10232void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10233 ++prologue_call_count_second;
10234}
10235
10236void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10237 ++epilogue_call_count_second;
10238}
10239
10240TEST(GCCallbacks) {
10241 LocalContext context;
10242
10243 v8::V8::AddGCPrologueCallback(PrologueCallback);
10244 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10245 CHECK_EQ(0, prologue_call_count);
10246 CHECK_EQ(0, epilogue_call_count);
10247 i::Heap::CollectAllGarbage(false);
10248 CHECK_EQ(1, prologue_call_count);
10249 CHECK_EQ(1, epilogue_call_count);
10250 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10251 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10252 i::Heap::CollectAllGarbage(false);
10253 CHECK_EQ(2, prologue_call_count);
10254 CHECK_EQ(2, epilogue_call_count);
10255 CHECK_EQ(1, prologue_call_count_second);
10256 CHECK_EQ(1, epilogue_call_count_second);
10257 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10258 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10259 i::Heap::CollectAllGarbage(false);
10260 CHECK_EQ(2, prologue_call_count);
10261 CHECK_EQ(2, epilogue_call_count);
10262 CHECK_EQ(2, prologue_call_count_second);
10263 CHECK_EQ(2, epilogue_call_count_second);
10264 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10265 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
10266 i::Heap::CollectAllGarbage(false);
10267 CHECK_EQ(2, prologue_call_count);
10268 CHECK_EQ(2, epilogue_call_count);
10269 CHECK_EQ(2, prologue_call_count_second);
10270 CHECK_EQ(2, epilogue_call_count_second);
10271}
Kristian Monsen25f61362010-05-21 11:50:48 +010010272
10273
10274THREADED_TEST(AddToJSFunctionResultCache) {
10275 i::FLAG_allow_natives_syntax = true;
10276 v8::HandleScope scope;
10277
10278 LocalContext context;
10279
10280 const char* code =
10281 "(function() {"
10282 " var key0 = 'a';"
10283 " var key1 = 'b';"
10284 " var r0 = %_GetFromCache(0, key0);"
10285 " var r1 = %_GetFromCache(0, key1);"
10286 " var r0_ = %_GetFromCache(0, key0);"
10287 " if (r0 !== r0_)"
10288 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
10289 " var r1_ = %_GetFromCache(0, key1);"
10290 " if (r1 !== r1_)"
10291 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
10292 " return 'PASSED';"
10293 "})()";
10294 v8::internal::Heap::ClearJSFunctionResultCaches();
10295 ExpectString(code, "PASSED");
10296}
10297
10298
10299static const int k0CacheSize = 16;
10300
10301THREADED_TEST(FillJSFunctionResultCache) {
10302 i::FLAG_allow_natives_syntax = true;
10303 v8::HandleScope scope;
10304
10305 LocalContext context;
10306
10307 const char* code =
10308 "(function() {"
10309 " var k = 'a';"
10310 " var r = %_GetFromCache(0, k);"
10311 " for (var i = 0; i < 16; i++) {"
10312 " %_GetFromCache(0, 'a' + i);"
10313 " };"
10314 " if (r === %_GetFromCache(0, k))"
10315 " return 'FAILED: k0CacheSize is too small';"
10316 " return 'PASSED';"
10317 "})()";
10318 v8::internal::Heap::ClearJSFunctionResultCaches();
10319 ExpectString(code, "PASSED");
10320}
10321
10322
10323THREADED_TEST(RoundRobinGetFromCache) {
10324 i::FLAG_allow_natives_syntax = true;
10325 v8::HandleScope scope;
10326
10327 LocalContext context;
10328
10329 const char* code =
10330 "(function() {"
10331 " var keys = [];"
10332 " for (var i = 0; i < 16; i++) keys.push(i);"
10333 " var values = [];"
10334 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10335 " for (var i = 0; i < 16; i++) {"
10336 " var v = %_GetFromCache(0, keys[i]);"
10337 " if (v !== values[i])"
10338 " return 'Wrong value for ' + "
10339 " keys[i] + ': ' + v + ' vs. ' + values[i];"
10340 " };"
10341 " return 'PASSED';"
10342 "})()";
10343 v8::internal::Heap::ClearJSFunctionResultCaches();
10344 ExpectString(code, "PASSED");
10345}
10346
10347
10348THREADED_TEST(ReverseGetFromCache) {
10349 i::FLAG_allow_natives_syntax = true;
10350 v8::HandleScope scope;
10351
10352 LocalContext context;
10353
10354 const char* code =
10355 "(function() {"
10356 " var keys = [];"
10357 " for (var i = 0; i < 16; i++) keys.push(i);"
10358 " var values = [];"
10359 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
10360 " for (var i = 15; i >= 16; i--) {"
10361 " var v = %_GetFromCache(0, keys[i]);"
10362 " if (v !== values[i])"
10363 " return 'Wrong value for ' + "
10364 " keys[i] + ': ' + v + ' vs. ' + values[i];"
10365 " };"
10366 " return 'PASSED';"
10367 "})()";
10368 v8::internal::Heap::ClearJSFunctionResultCaches();
10369 ExpectString(code, "PASSED");
10370}
10371
10372
10373THREADED_TEST(TestEviction) {
10374 i::FLAG_allow_natives_syntax = true;
10375 v8::HandleScope scope;
10376
10377 LocalContext context;
10378
10379 const char* code =
10380 "(function() {"
10381 " for (var i = 0; i < 2*16; i++) {"
10382 " %_GetFromCache(0, 'a' + i);"
10383 " };"
10384 " return 'PASSED';"
10385 "})()";
10386 v8::internal::Heap::ClearJSFunctionResultCaches();
10387 ExpectString(code, "PASSED");
10388}