blob: 84fdd68b4bd284eb56e27476e9180232639e9b46 [file] [log] [blame]
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001// Copyright 2007-2009 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org3811b432009-10-28 14:53:37 +000028#include <limits.h>
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include "v8.h"
31
32#include "api.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000033#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000034#include "execution.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000035#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000038#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "cctest.h"
40
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000041static const bool kLogThreading = true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000042
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000063
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000191 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192
193 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000194 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000195
196 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000197 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000198
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]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000219 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
221 v8::Handle<Value> value5 = CompileRun(
222 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000223 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
225 v8::Handle<Value> value6 = CompileRun(
226 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000227 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000228
229 v8::Handle<Value> value7 = CompileRun(
230 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
231 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000232 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000233
234 v8::Handle<Value> value8 = CompileRun(
235 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000236 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000237}
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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000267THREADED_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
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000297 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000298 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000299 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +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
ager@chromium.org5ec48922009-05-05 07:25:34 +0000338 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000339 : 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:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000355 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356 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()));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000379 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000380 CHECK_EQ(0, TestResource::dispose_count);
381 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000382 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000383 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384 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());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000400 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000401 CHECK_EQ(0, TestAsciiResource::dispose_count);
402 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000403 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000404 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405 CHECK_EQ(1, TestAsciiResource::dispose_count);
406}
407
408
ager@chromium.org6f10e412009-02-13 10:11:16 +0000409THREADED_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);
ager@chromium.org5c838252010-02-19 08:53:10 +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
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000425 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000426 CHECK_EQ(0, TestResource::dispose_count);
427 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000428 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000429 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000430 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);
ager@chromium.org5c838252010-02-19 08:53:10 +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
ager@chromium.org6f10e412009-02-13 10:11:16 +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());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000451 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000452 CHECK_EQ(0, TestAsciiResource::dispose_count);
453 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000454 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000455 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000456 CHECK_EQ(1, TestAsciiResource::dispose_count);
457}
458
459
ager@chromium.org5c838252010-02-19 08:53:10 +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
ager@chromium.org6f10e412009-02-13 10:11:16 +0000534THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000535 {
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 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000547 i::Heap::CollectAllGarbage(false);
548 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000549}
550
551
552THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000553 {
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 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000565 i::Heap::CollectAllGarbage(false);
566 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000567}
568
569
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570THREADED_TEST(ScavengeExternalString) {
571 TestResource::dispose_count = 0;
572 {
573 v8::HandleScope scope;
574 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
575 Local<String> string =
576 String::NewExternal(new TestResource(two_byte_string));
577 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
578 i::Heap::CollectGarbage(0, i::NEW_SPACE);
579 CHECK(i::Heap::InNewSpace(*istring));
580 CHECK_EQ(0, TestResource::dispose_count);
581 }
582 i::Heap::CollectGarbage(0, i::NEW_SPACE);
583 CHECK_EQ(1, TestResource::dispose_count);
584}
585
586
587THREADED_TEST(ScavengeExternalAsciiString) {
588 TestAsciiResource::dispose_count = 0;
589 {
590 v8::HandleScope scope;
591 const char* one_byte_string = "test string";
592 Local<String> string = String::NewExternal(
593 new TestAsciiResource(i::StrDup(one_byte_string)));
594 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
595 i::Heap::CollectGarbage(0, i::NEW_SPACE);
596 CHECK(i::Heap::InNewSpace(*istring));
597 CHECK_EQ(0, TestAsciiResource::dispose_count);
598 }
599 i::Heap::CollectGarbage(0, i::NEW_SPACE);
600 CHECK_EQ(1, TestAsciiResource::dispose_count);
601}
602
603
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000604THREADED_TEST(StringConcat) {
605 {
606 v8::HandleScope scope;
607 LocalContext env;
608 const char* one_byte_string_1 = "function a_times_t";
609 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
610 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
611 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
612 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
613 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
614 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
615 Local<String> left = v8_str(one_byte_string_1);
616 Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
617 Local<String> source = String::Concat(left, right);
618 right = String::NewExternal(
619 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
620 source = String::Concat(source, right);
621 right = String::NewExternal(
622 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
623 source = String::Concat(source, right);
624 right = v8_str(one_byte_string_2);
625 source = String::Concat(source, right);
626 right = String::New(AsciiToTwoByteString(two_byte_string_2));
627 source = String::Concat(source, right);
628 right = String::NewExternal(
629 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
630 source = String::Concat(source, right);
631 Local<Script> script = Script::Compile(source);
632 Local<Value> value = script->Run();
633 CHECK(value->IsNumber());
634 CHECK_EQ(68, value->Int32Value());
635 }
636 v8::internal::CompilationCache::Clear();
637 i::Heap::CollectAllGarbage(false);
638 i::Heap::CollectAllGarbage(false);
639}
640
641
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000642THREADED_TEST(GlobalProperties) {
643 v8::HandleScope scope;
644 LocalContext env;
645 v8::Handle<v8::Object> global = env->Global();
646 global->Set(v8_str("pi"), v8_num(3.1415926));
647 Local<Value> pi = global->Get(v8_str("pi"));
648 CHECK_EQ(3.1415926, pi->NumberValue());
649}
650
651
652static v8::Handle<Value> handle_call(const v8::Arguments& args) {
653 ApiTestFuzzer::Fuzz();
654 return v8_num(102);
655}
656
657
658static v8::Handle<Value> construct_call(const v8::Arguments& args) {
659 ApiTestFuzzer::Fuzz();
660 args.This()->Set(v8_str("x"), v8_num(1));
661 args.This()->Set(v8_str("y"), v8_num(2));
662 return args.This();
663}
664
665THREADED_TEST(FunctionTemplate) {
666 v8::HandleScope scope;
667 LocalContext env;
668 {
669 Local<v8::FunctionTemplate> fun_templ =
670 v8::FunctionTemplate::New(handle_call);
671 Local<Function> fun = fun_templ->GetFunction();
672 env->Global()->Set(v8_str("obj"), fun);
673 Local<Script> script = v8_compile("obj()");
674 CHECK_EQ(102, script->Run()->Int32Value());
675 }
676 // Use SetCallHandler to initialize a function template, should work like the
677 // previous one.
678 {
679 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
680 fun_templ->SetCallHandler(handle_call);
681 Local<Function> fun = fun_templ->GetFunction();
682 env->Global()->Set(v8_str("obj"), fun);
683 Local<Script> script = v8_compile("obj()");
684 CHECK_EQ(102, script->Run()->Int32Value());
685 }
686 // Test constructor calls.
687 {
688 Local<v8::FunctionTemplate> fun_templ =
689 v8::FunctionTemplate::New(construct_call);
690 fun_templ->SetClassName(v8_str("funky"));
691 Local<Function> fun = fun_templ->GetFunction();
692 env->Global()->Set(v8_str("obj"), fun);
693 Local<Script> script = v8_compile("var s = new obj(); s.x");
694 CHECK_EQ(1, script->Run()->Int32Value());
695
696 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
697 CHECK_EQ(v8_str("[object funky]"), result);
698 }
699}
700
701
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000702THREADED_TEST(FindInstanceInPrototypeChain) {
703 v8::HandleScope scope;
704 LocalContext env;
705
706 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
707 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
708 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
709 derived->Inherit(base);
710
711 Local<v8::Function> base_function = base->GetFunction();
712 Local<v8::Function> derived_function = derived->GetFunction();
713 Local<v8::Function> other_function = other->GetFunction();
714
715 Local<v8::Object> base_instance = base_function->NewInstance();
716 Local<v8::Object> derived_instance = derived_function->NewInstance();
717 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
718 Local<v8::Object> other_instance = other_function->NewInstance();
719 derived_instance2->Set(v8_str("__proto__"), derived_instance);
720 other_instance->Set(v8_str("__proto__"), derived_instance2);
721
722 // base_instance is only an instance of base.
723 CHECK_EQ(base_instance,
724 base_instance->FindInstanceInPrototypeChain(base));
725 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
726 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
727
728 // derived_instance is an instance of base and derived.
729 CHECK_EQ(derived_instance,
730 derived_instance->FindInstanceInPrototypeChain(base));
731 CHECK_EQ(derived_instance,
732 derived_instance->FindInstanceInPrototypeChain(derived));
733 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
734
735 // other_instance is an instance of other and its immediate
736 // prototype derived_instance2 is an instance of base and derived.
737 // Note, derived_instance is an instance of base and derived too,
738 // but it comes after derived_instance2 in the prototype chain of
739 // other_instance.
740 CHECK_EQ(derived_instance2,
741 other_instance->FindInstanceInPrototypeChain(base));
742 CHECK_EQ(derived_instance2,
743 other_instance->FindInstanceInPrototypeChain(derived));
744 CHECK_EQ(other_instance,
745 other_instance->FindInstanceInPrototypeChain(other));
746}
747
748
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000749THREADED_TEST(TinyInteger) {
750 v8::HandleScope scope;
751 LocalContext env;
752 int32_t value = 239;
753 Local<v8::Integer> value_obj = v8::Integer::New(value);
754 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
755}
756
757
758THREADED_TEST(BigSmiInteger) {
759 v8::HandleScope scope;
760 LocalContext env;
761 int32_t value = i::Smi::kMaxValue;
762 // We cannot add one to a Smi::kMaxValue without wrapping.
763 if (i::kSmiValueSize < 32) {
764 CHECK(i::Smi::IsValid(value));
765 CHECK(!i::Smi::IsValid(value + 1));
766 Local<v8::Integer> value_obj = v8::Integer::New(value);
767 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
768 }
769}
770
771
772THREADED_TEST(BigInteger) {
773 v8::HandleScope scope;
774 LocalContext env;
775 // We cannot add one to a Smi::kMaxValue without wrapping.
776 if (i::kSmiValueSize < 32) {
777 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
778 // The code will not be run in that case, due to the "if" guard.
779 int32_t value =
780 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
781 CHECK(value > i::Smi::kMaxValue);
782 CHECK(!i::Smi::IsValid(value));
783 Local<v8::Integer> value_obj = v8::Integer::New(value);
784 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
785 }
786}
787
788
789THREADED_TEST(TinyUnsignedInteger) {
790 v8::HandleScope scope;
791 LocalContext env;
792 uint32_t value = 239;
793 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
794 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
795}
796
797
798THREADED_TEST(BigUnsignedSmiInteger) {
799 v8::HandleScope scope;
800 LocalContext env;
801 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
802 CHECK(i::Smi::IsValid(value));
803 CHECK(!i::Smi::IsValid(value + 1));
804 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
805 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
806}
807
808
809THREADED_TEST(BigUnsignedInteger) {
810 v8::HandleScope scope;
811 LocalContext env;
812 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
813 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
814 CHECK(!i::Smi::IsValid(value));
815 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
816 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
817}
818
819
820THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
821 v8::HandleScope scope;
822 LocalContext env;
823 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
824 uint32_t value = INT32_MAX_AS_UINT + 1;
825 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
826 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
827 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
828}
829
830
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000831THREADED_TEST(Number) {
832 v8::HandleScope scope;
833 LocalContext env;
834 double PI = 3.1415926;
835 Local<v8::Number> pi_obj = v8::Number::New(PI);
836 CHECK_EQ(PI, pi_obj->NumberValue());
837}
838
839
840THREADED_TEST(ToNumber) {
841 v8::HandleScope scope;
842 LocalContext env;
843 Local<String> str = v8_str("3.1415926");
844 CHECK_EQ(3.1415926, str->NumberValue());
845 v8::Handle<v8::Boolean> t = v8::True();
846 CHECK_EQ(1.0, t->NumberValue());
847 v8::Handle<v8::Boolean> f = v8::False();
848 CHECK_EQ(0.0, f->NumberValue());
849}
850
851
852THREADED_TEST(Date) {
853 v8::HandleScope scope;
854 LocalContext env;
855 double PI = 3.1415926;
856 Local<Value> date_obj = v8::Date::New(PI);
857 CHECK_EQ(3.0, date_obj->NumberValue());
858}
859
860
861THREADED_TEST(Boolean) {
862 v8::HandleScope scope;
863 LocalContext env;
864 v8::Handle<v8::Boolean> t = v8::True();
865 CHECK(t->Value());
866 v8::Handle<v8::Boolean> f = v8::False();
867 CHECK(!f->Value());
868 v8::Handle<v8::Primitive> u = v8::Undefined();
869 CHECK(!u->BooleanValue());
870 v8::Handle<v8::Primitive> n = v8::Null();
871 CHECK(!n->BooleanValue());
872 v8::Handle<String> str1 = v8_str("");
873 CHECK(!str1->BooleanValue());
874 v8::Handle<String> str2 = v8_str("x");
875 CHECK(str2->BooleanValue());
876 CHECK(!v8::Number::New(0)->BooleanValue());
877 CHECK(v8::Number::New(-1)->BooleanValue());
878 CHECK(v8::Number::New(1)->BooleanValue());
879 CHECK(v8::Number::New(42)->BooleanValue());
880 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
881}
882
883
884static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
885 ApiTestFuzzer::Fuzz();
886 return v8_num(13.4);
887}
888
889
890static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
891 ApiTestFuzzer::Fuzz();
892 return v8_num(876);
893}
894
895
896THREADED_TEST(GlobalPrototype) {
897 v8::HandleScope scope;
898 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
899 func_templ->PrototypeTemplate()->Set(
900 "dummy",
901 v8::FunctionTemplate::New(DummyCallHandler));
902 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
903 templ->Set("x", v8_num(200));
904 templ->SetAccessor(v8_str("m"), GetM);
905 LocalContext env(0, templ);
906 v8::Handle<v8::Object> obj = env->Global();
907 v8::Handle<Script> script = v8_compile("dummy()");
908 v8::Handle<Value> result = script->Run();
909 CHECK_EQ(13.4, result->NumberValue());
910 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
911 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
912}
913
914
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000915THREADED_TEST(ObjectTemplate) {
916 v8::HandleScope scope;
917 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
918 templ1->Set("x", v8_num(10));
919 templ1->Set("y", v8_num(13));
920 LocalContext env;
921 Local<v8::Object> instance1 = templ1->NewInstance();
922 env->Global()->Set(v8_str("p"), instance1);
923 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
924 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
925 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
926 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
927 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
928 templ2->Set("a", v8_num(12));
929 templ2->Set("b", templ1);
930 Local<v8::Object> instance2 = templ2->NewInstance();
931 env->Global()->Set(v8_str("q"), instance2);
932 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
933 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
934 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
935 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
936}
937
938
939static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
940 ApiTestFuzzer::Fuzz();
941 return v8_num(17.2);
942}
943
944
945static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
946 ApiTestFuzzer::Fuzz();
947 return v8_num(15.2);
948}
949
950
951THREADED_TEST(DescriptorInheritance) {
952 v8::HandleScope scope;
953 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
954 super->PrototypeTemplate()->Set("flabby",
955 v8::FunctionTemplate::New(GetFlabby));
956 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
957
958 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
959
960 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
961 base1->Inherit(super);
962 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
963
964 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
965 base2->Inherit(super);
966 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
967
968 LocalContext env;
969
970 env->Global()->Set(v8_str("s"), super->GetFunction());
971 env->Global()->Set(v8_str("base1"), base1->GetFunction());
972 env->Global()->Set(v8_str("base2"), base2->GetFunction());
973
974 // Checks right __proto__ chain.
975 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
976 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
977
978 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
979
980 // Instance accessor should not be visible on function object or its prototype
981 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
982 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
983 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
984
985 env->Global()->Set(v8_str("obj"),
986 base1->GetFunction()->NewInstance());
987 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
988 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
989 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
990 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
991 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
992
993 env->Global()->Set(v8_str("obj2"),
994 base2->GetFunction()->NewInstance());
995 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
996 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
997 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
998 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
999 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1000
1001 // base1 and base2 cannot cross reference to each's prototype
1002 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1003 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1004}
1005
1006
1007int echo_named_call_count;
1008
1009
1010static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1011 const AccessorInfo& info) {
1012 ApiTestFuzzer::Fuzz();
1013 CHECK_EQ(v8_str("data"), info.Data());
1014 echo_named_call_count++;
1015 return name;
1016}
1017
1018
1019THREADED_TEST(NamedPropertyHandlerGetter) {
1020 echo_named_call_count = 0;
1021 v8::HandleScope scope;
1022 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1023 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1024 0, 0, 0, 0,
1025 v8_str("data"));
1026 LocalContext env;
1027 env->Global()->Set(v8_str("obj"),
1028 templ->GetFunction()->NewInstance());
1029 CHECK_EQ(echo_named_call_count, 0);
1030 v8_compile("obj.x")->Run();
1031 CHECK_EQ(echo_named_call_count, 1);
1032 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1033 v8::Handle<Value> str = CompileRun(code);
1034 String::AsciiValue value(str);
1035 CHECK_EQ(*value, "oddlepoddle");
1036 // Check default behavior
1037 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1038 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1039 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1040}
1041
1042
1043int echo_indexed_call_count = 0;
1044
1045
1046static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1047 const AccessorInfo& info) {
1048 ApiTestFuzzer::Fuzz();
1049 CHECK_EQ(v8_num(637), info.Data());
1050 echo_indexed_call_count++;
1051 return v8_num(index);
1052}
1053
1054
1055THREADED_TEST(IndexedPropertyHandlerGetter) {
1056 v8::HandleScope scope;
1057 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1058 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1059 0, 0, 0, 0,
1060 v8_num(637));
1061 LocalContext env;
1062 env->Global()->Set(v8_str("obj"),
1063 templ->GetFunction()->NewInstance());
1064 Local<Script> script = v8_compile("obj[900]");
1065 CHECK_EQ(script->Run()->Int32Value(), 900);
1066}
1067
1068
1069v8::Handle<v8::Object> bottom;
1070
1071static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1072 uint32_t index,
1073 const AccessorInfo& info) {
1074 ApiTestFuzzer::Fuzz();
1075 CHECK(info.This()->Equals(bottom));
1076 return v8::Handle<Value>();
1077}
1078
1079static v8::Handle<Value> CheckThisNamedPropertyHandler(
1080 Local<String> name,
1081 const AccessorInfo& info) {
1082 ApiTestFuzzer::Fuzz();
1083 CHECK(info.This()->Equals(bottom));
1084 return v8::Handle<Value>();
1085}
1086
1087
1088v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1089 Local<Value> value,
1090 const AccessorInfo& info) {
1091 ApiTestFuzzer::Fuzz();
1092 CHECK(info.This()->Equals(bottom));
1093 return v8::Handle<Value>();
1094}
1095
1096
1097v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1098 Local<Value> value,
1099 const AccessorInfo& info) {
1100 ApiTestFuzzer::Fuzz();
1101 CHECK(info.This()->Equals(bottom));
1102 return v8::Handle<Value>();
1103}
1104
1105v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1106 uint32_t index,
1107 const AccessorInfo& info) {
1108 ApiTestFuzzer::Fuzz();
1109 CHECK(info.This()->Equals(bottom));
1110 return v8::Handle<v8::Boolean>();
1111}
1112
1113
1114v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1115 const AccessorInfo& info) {
1116 ApiTestFuzzer::Fuzz();
1117 CHECK(info.This()->Equals(bottom));
1118 return v8::Handle<v8::Boolean>();
1119}
1120
1121
1122v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1123 uint32_t index,
1124 const AccessorInfo& info) {
1125 ApiTestFuzzer::Fuzz();
1126 CHECK(info.This()->Equals(bottom));
1127 return v8::Handle<v8::Boolean>();
1128}
1129
1130
1131v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1132 Local<String> property,
1133 const AccessorInfo& info) {
1134 ApiTestFuzzer::Fuzz();
1135 CHECK(info.This()->Equals(bottom));
1136 return v8::Handle<v8::Boolean>();
1137}
1138
1139
1140v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1141 const AccessorInfo& info) {
1142 ApiTestFuzzer::Fuzz();
1143 CHECK(info.This()->Equals(bottom));
1144 return v8::Handle<v8::Array>();
1145}
1146
1147
1148v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1149 const AccessorInfo& info) {
1150 ApiTestFuzzer::Fuzz();
1151 CHECK(info.This()->Equals(bottom));
1152 return v8::Handle<v8::Array>();
1153}
1154
1155
1156THREADED_TEST(PropertyHandlerInPrototype) {
1157 v8::HandleScope scope;
1158 LocalContext env;
1159
1160 // Set up a prototype chain with three interceptors.
1161 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1162 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1163 CheckThisIndexedPropertyHandler,
1164 CheckThisIndexedPropertySetter,
1165 CheckThisIndexedPropertyQuery,
1166 CheckThisIndexedPropertyDeleter,
1167 CheckThisIndexedPropertyEnumerator);
1168
1169 templ->InstanceTemplate()->SetNamedPropertyHandler(
1170 CheckThisNamedPropertyHandler,
1171 CheckThisNamedPropertySetter,
1172 CheckThisNamedPropertyQuery,
1173 CheckThisNamedPropertyDeleter,
1174 CheckThisNamedPropertyEnumerator);
1175
1176 bottom = templ->GetFunction()->NewInstance();
1177 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1178 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1179
1180 bottom->Set(v8_str("__proto__"), middle);
1181 middle->Set(v8_str("__proto__"), top);
1182 env->Global()->Set(v8_str("obj"), bottom);
1183
1184 // Indexed and named get.
1185 Script::Compile(v8_str("obj[0]"))->Run();
1186 Script::Compile(v8_str("obj.x"))->Run();
1187
1188 // Indexed and named set.
1189 Script::Compile(v8_str("obj[1] = 42"))->Run();
1190 Script::Compile(v8_str("obj.y = 42"))->Run();
1191
1192 // Indexed and named query.
1193 Script::Compile(v8_str("0 in obj"))->Run();
1194 Script::Compile(v8_str("'x' in obj"))->Run();
1195
1196 // Indexed and named deleter.
1197 Script::Compile(v8_str("delete obj[0]"))->Run();
1198 Script::Compile(v8_str("delete obj.x"))->Run();
1199
1200 // Enumerators.
1201 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1202}
1203
1204
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001205static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1206 const AccessorInfo& info) {
1207 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001208 if (v8_str("pre")->Equals(key)) {
1209 return v8_str("PrePropertyHandler: pre");
1210 }
1211 return v8::Handle<String>();
1212}
1213
1214
1215static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1216 const AccessorInfo&) {
1217 if (v8_str("pre")->Equals(key)) {
1218 return v8::True();
1219 }
1220
1221 return v8::Handle<v8::Boolean>(); // do not intercept the call
1222}
1223
1224
1225THREADED_TEST(PrePropertyHandler) {
1226 v8::HandleScope scope;
1227 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1228 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1229 0,
1230 PrePropertyHandlerHas);
1231 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001232 Script::Compile(v8_str(
1233 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1234 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1235 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1236 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1237 CHECK_EQ(v8_str("Object: on"), result_on);
1238 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1239 CHECK(result_post.IsEmpty());
1240}
1241
1242
ager@chromium.org870a0b62008-11-04 11:43:05 +00001243THREADED_TEST(UndefinedIsNotEnumerable) {
1244 v8::HandleScope scope;
1245 LocalContext env;
1246 v8::Handle<Value> result = Script::Compile(v8_str(
1247 "this.propertyIsEnumerable(undefined)"))->Run();
1248 CHECK(result->IsFalse());
1249}
1250
1251
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001252v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001253static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001254
1255
1256static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1257 ApiTestFuzzer::Fuzz();
1258 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1259 if (depth == kTargetRecursionDepth) return v8::Undefined();
1260 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1261 return call_recursively_script->Run();
1262}
1263
1264
1265static v8::Handle<Value> CallFunctionRecursivelyCall(
1266 const v8::Arguments& args) {
1267 ApiTestFuzzer::Fuzz();
1268 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1269 if (depth == kTargetRecursionDepth) {
1270 printf("[depth = %d]\n", depth);
1271 return v8::Undefined();
1272 }
1273 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1274 v8::Handle<Value> function =
1275 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001276 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001277}
1278
1279
1280THREADED_TEST(DeepCrossLanguageRecursion) {
1281 v8::HandleScope scope;
1282 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1283 global->Set(v8_str("callScriptRecursively"),
1284 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1285 global->Set(v8_str("callFunctionRecursively"),
1286 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1287 LocalContext env(NULL, global);
1288
1289 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1290 call_recursively_script = v8_compile("callScriptRecursively()");
1291 v8::Handle<Value> result = call_recursively_script->Run();
1292 call_recursively_script = v8::Handle<Script>();
1293
1294 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1295 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1296}
1297
1298
1299static v8::Handle<Value>
1300 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1301 ApiTestFuzzer::Fuzz();
1302 return v8::ThrowException(key);
1303}
1304
1305
1306static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1307 Local<Value>,
1308 const AccessorInfo&) {
1309 v8::ThrowException(key);
1310 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1311}
1312
1313
1314THREADED_TEST(CallbackExceptionRegression) {
1315 v8::HandleScope scope;
1316 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1317 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1318 ThrowingPropertyHandlerSet);
1319 LocalContext env;
1320 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1321 v8::Handle<Value> otto = Script::Compile(v8_str(
1322 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1323 CHECK_EQ(v8_str("otto"), otto);
1324 v8::Handle<Value> netto = Script::Compile(v8_str(
1325 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1326 CHECK_EQ(v8_str("netto"), netto);
1327}
1328
1329
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001330THREADED_TEST(FunctionPrototype) {
1331 v8::HandleScope scope;
1332 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1333 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1334 LocalContext env;
1335 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1336 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1337 CHECK_EQ(script->Run()->Int32Value(), 321);
1338}
1339
1340
1341THREADED_TEST(InternalFields) {
1342 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001343 LocalContext env;
1344
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001345 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1346 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1347 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001348 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1349 CHECK_EQ(1, obj->InternalFieldCount());
1350 CHECK(obj->GetInternalField(0)->IsUndefined());
1351 obj->SetInternalField(0, v8_num(17));
1352 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1353}
1354
1355
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001356THREADED_TEST(GlobalObjectInternalFields) {
1357 v8::HandleScope scope;
1358 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1359 global_template->SetInternalFieldCount(1);
1360 LocalContext env(NULL, global_template);
1361 v8::Handle<v8::Object> global_proxy = env->Global();
1362 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1363 CHECK_EQ(1, global->InternalFieldCount());
1364 CHECK(global->GetInternalField(0)->IsUndefined());
1365 global->SetInternalField(0, v8_num(17));
1366 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1367}
1368
1369
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001370THREADED_TEST(InternalFieldsNativePointers) {
1371 v8::HandleScope scope;
1372 LocalContext env;
1373
1374 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1375 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1376 instance_templ->SetInternalFieldCount(1);
1377 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1378 CHECK_EQ(1, obj->InternalFieldCount());
1379 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1380
1381 char* data = new char[100];
1382
1383 void* aligned = data;
1384 CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1385 void* unaligned = data + 1;
1386 CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1387
1388 // Check reading and writing aligned pointers.
1389 obj->SetPointerInInternalField(0, aligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001390 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001391 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1392
1393 // Check reading and writing unaligned pointers.
1394 obj->SetPointerInInternalField(0, unaligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001395 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001396 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1397
1398 delete[] data;
1399}
1400
1401
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001402THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1403 v8::HandleScope scope;
1404 LocalContext env;
1405
1406 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1407 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1408 instance_templ->SetInternalFieldCount(1);
1409 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1410 CHECK_EQ(1, obj->InternalFieldCount());
1411 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1412
1413 char* data = new char[100];
1414
1415 void* aligned = data;
1416 CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1417 void* unaligned = data + 1;
1418 CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1419
1420 obj->SetPointerInInternalField(0, aligned);
1421 i::Heap::CollectAllGarbage(false);
1422 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1423
1424 obj->SetPointerInInternalField(0, unaligned);
1425 i::Heap::CollectAllGarbage(false);
1426 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1427
1428 obj->SetInternalField(0, v8::External::Wrap(aligned));
1429 i::Heap::CollectAllGarbage(false);
1430 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1431
1432 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1433 i::Heap::CollectAllGarbage(false);
1434 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1435
1436 delete[] data;
1437}
1438
1439
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001440THREADED_TEST(IdentityHash) {
1441 v8::HandleScope scope;
1442 LocalContext env;
1443
1444 // Ensure that the test starts with an fresh heap to test whether the hash
1445 // code is based on the address.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001446 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001447 Local<v8::Object> obj = v8::Object::New();
1448 int hash = obj->GetIdentityHash();
1449 int hash1 = obj->GetIdentityHash();
1450 CHECK_EQ(hash, hash1);
1451 int hash2 = v8::Object::New()->GetIdentityHash();
1452 // Since the identity hash is essentially a random number two consecutive
1453 // objects should not be assigned the same hash code. If the test below fails
1454 // the random number generator should be evaluated.
1455 CHECK_NE(hash, hash2);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001456 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001457 int hash3 = v8::Object::New()->GetIdentityHash();
1458 // Make sure that the identity hash is not based on the initial address of
1459 // the object alone. If the test below fails the random number generator
1460 // should be evaluated.
1461 CHECK_NE(hash, hash3);
1462 int hash4 = obj->GetIdentityHash();
1463 CHECK_EQ(hash, hash4);
1464}
1465
1466
1467THREADED_TEST(HiddenProperties) {
1468 v8::HandleScope scope;
1469 LocalContext env;
1470
1471 v8::Local<v8::Object> obj = v8::Object::New();
1472 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1473 v8::Local<v8::String> empty = v8_str("");
1474 v8::Local<v8::String> prop_name = v8_str("prop_name");
1475
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001476 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001477
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001478 // Make sure delete of a non-existent hidden value works
1479 CHECK(obj->DeleteHiddenValue(key));
1480
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001481 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1482 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1483 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1484 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1485
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001486 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001487
1488 // Make sure we do not find the hidden property.
1489 CHECK(!obj->Has(empty));
1490 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1491 CHECK(obj->Get(empty)->IsUndefined());
1492 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1493 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1494 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1495 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1496
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001497 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001498
1499 // Add another property and delete it afterwards to force the object in
1500 // slow case.
1501 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1502 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1503 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1504 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1505 CHECK(obj->Delete(prop_name));
1506 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1507
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001508 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001509
1510 CHECK(obj->DeleteHiddenValue(key));
1511 CHECK(obj->GetHiddenValue(key).IsEmpty());
1512}
1513
1514
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001515static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001516static v8::Handle<Value> InterceptorForHiddenProperties(
1517 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001518 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001519 return v8::Handle<Value>();
1520}
1521
1522
1523THREADED_TEST(HiddenPropertiesWithInterceptors) {
1524 v8::HandleScope scope;
1525 LocalContext context;
1526
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001527 interceptor_for_hidden_properties_called = false;
1528
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001529 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1530
1531 // Associate an interceptor with an object and start setting hidden values.
1532 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1533 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1534 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1535 Local<v8::Function> function = fun_templ->GetFunction();
1536 Local<v8::Object> obj = function->NewInstance();
1537 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1538 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001539 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001540}
1541
1542
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001543THREADED_TEST(External) {
1544 v8::HandleScope scope;
1545 int x = 3;
1546 Local<v8::External> ext = v8::External::New(&x);
1547 LocalContext env;
1548 env->Global()->Set(v8_str("ext"), ext);
1549 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001550 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001551 int* ptr = static_cast<int*>(reext->Value());
1552 CHECK_EQ(x, 3);
1553 *ptr = 10;
1554 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001555
1556 // Make sure unaligned pointers are wrapped properly.
1557 char* data = i::StrDup("0123456789");
1558 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1559 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1560 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1561 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1562
1563 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1564 CHECK_EQ('0', *char_ptr);
1565 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1566 CHECK_EQ('1', *char_ptr);
1567 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1568 CHECK_EQ('2', *char_ptr);
1569 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1570 CHECK_EQ('3', *char_ptr);
1571 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001572}
1573
1574
1575THREADED_TEST(GlobalHandle) {
1576 v8::Persistent<String> global;
1577 {
1578 v8::HandleScope scope;
1579 Local<String> str = v8_str("str");
1580 global = v8::Persistent<String>::New(str);
1581 }
1582 CHECK_EQ(global->Length(), 3);
1583 global.Dispose();
1584}
1585
1586
1587THREADED_TEST(ScriptException) {
1588 v8::HandleScope scope;
1589 LocalContext env;
1590 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1591 v8::TryCatch try_catch;
1592 Local<Value> result = script->Run();
1593 CHECK(result.IsEmpty());
1594 CHECK(try_catch.HasCaught());
1595 String::AsciiValue exception_value(try_catch.Exception());
1596 CHECK_EQ(*exception_value, "panama!");
1597}
1598
1599
1600bool message_received;
1601
1602
1603static void check_message(v8::Handle<v8::Message> message,
1604 v8::Handle<Value> data) {
1605 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001606 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001607 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001608 message_received = true;
1609}
1610
1611
1612THREADED_TEST(MessageHandlerData) {
1613 message_received = false;
1614 v8::HandleScope scope;
1615 CHECK(!message_received);
1616 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1617 LocalContext context;
1618 v8::ScriptOrigin origin =
1619 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001620 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1621 &origin);
1622 script->SetData(v8_str("7.56"));
1623 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001624 CHECK(message_received);
1625 // clear out the message listener
1626 v8::V8::RemoveMessageListeners(check_message);
1627}
1628
1629
1630THREADED_TEST(GetSetProperty) {
1631 v8::HandleScope scope;
1632 LocalContext context;
1633 context->Global()->Set(v8_str("foo"), v8_num(14));
1634 context->Global()->Set(v8_str("12"), v8_num(92));
1635 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1636 context->Global()->Set(v8_num(13), v8_num(56));
1637 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1638 CHECK_EQ(14, foo->Int32Value());
1639 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1640 CHECK_EQ(92, twelve->Int32Value());
1641 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1642 CHECK_EQ(32, sixteen->Int32Value());
1643 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1644 CHECK_EQ(56, thirteen->Int32Value());
1645 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1646 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1647 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1648 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1649 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1650 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1651 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1652 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1653 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1654}
1655
1656
1657THREADED_TEST(PropertyAttributes) {
1658 v8::HandleScope scope;
1659 LocalContext context;
1660 // read-only
1661 Local<String> prop = v8_str("read_only");
1662 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1663 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1664 Script::Compile(v8_str("read_only = 9"))->Run();
1665 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1666 context->Global()->Set(prop, v8_num(10));
1667 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1668 // dont-delete
1669 prop = v8_str("dont_delete");
1670 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1671 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1672 Script::Compile(v8_str("delete dont_delete"))->Run();
1673 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1674}
1675
1676
1677THREADED_TEST(Array) {
1678 v8::HandleScope scope;
1679 LocalContext context;
1680 Local<v8::Array> array = v8::Array::New();
1681 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001682 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001683 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001684 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001685 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001686 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001687 CHECK_EQ(3, array->Length());
1688 CHECK(!array->Has(0));
1689 CHECK(!array->Has(1));
1690 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001691 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001692 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001693 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001695 CHECK_EQ(1, arr->Get(0)->Int32Value());
1696 CHECK_EQ(2, arr->Get(1)->Int32Value());
1697 CHECK_EQ(3, arr->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001698}
1699
1700
1701v8::Handle<Value> HandleF(const v8::Arguments& args) {
1702 v8::HandleScope scope;
1703 ApiTestFuzzer::Fuzz();
1704 Local<v8::Array> result = v8::Array::New(args.Length());
1705 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001706 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001707 return scope.Close(result);
1708}
1709
1710
1711THREADED_TEST(Vector) {
1712 v8::HandleScope scope;
1713 Local<ObjectTemplate> global = ObjectTemplate::New();
1714 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1715 LocalContext context(0, global);
1716
1717 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001718 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001719 CHECK_EQ(0, a0->Length());
1720
1721 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001722 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001723 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001724 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001725
1726 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001727 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001728 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001729 CHECK_EQ(12, a2->Get(0)->Int32Value());
1730 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001731
1732 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001733 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001734 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001735 CHECK_EQ(14, a3->Get(0)->Int32Value());
1736 CHECK_EQ(15, a3->Get(1)->Int32Value());
1737 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738
1739 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001740 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001741 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 CHECK_EQ(17, a4->Get(0)->Int32Value());
1743 CHECK_EQ(18, a4->Get(1)->Int32Value());
1744 CHECK_EQ(19, a4->Get(2)->Int32Value());
1745 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001746}
1747
1748
1749THREADED_TEST(FunctionCall) {
1750 v8::HandleScope scope;
1751 LocalContext context;
1752 CompileRun(
1753 "function Foo() {"
1754 " var result = [];"
1755 " for (var i = 0; i < arguments.length; i++) {"
1756 " result.push(arguments[i]);"
1757 " }"
1758 " return result;"
1759 "}");
1760 Local<Function> Foo =
1761 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1762
1763 v8::Handle<Value>* args0 = NULL;
1764 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1765 CHECK_EQ(0, a0->Length());
1766
1767 v8::Handle<Value> args1[] = { v8_num(1.1) };
1768 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1769 CHECK_EQ(1, a1->Length());
1770 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1771
1772 v8::Handle<Value> args2[] = { v8_num(2.2),
1773 v8_num(3.3) };
1774 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1775 CHECK_EQ(2, a2->Length());
1776 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1777 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1778
1779 v8::Handle<Value> args3[] = { v8_num(4.4),
1780 v8_num(5.5),
1781 v8_num(6.6) };
1782 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1783 CHECK_EQ(3, a3->Length());
1784 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1785 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1786 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1787
1788 v8::Handle<Value> args4[] = { v8_num(7.7),
1789 v8_num(8.8),
1790 v8_num(9.9),
1791 v8_num(10.11) };
1792 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1793 CHECK_EQ(4, a4->Length());
1794 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1795 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1796 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1797 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1798}
1799
1800
1801static const char* js_code_causing_out_of_memory =
1802 "var a = new Array(); while(true) a.push(a);";
1803
1804
1805// These tests run for a long time and prevent us from running tests
1806// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001807TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001808 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001809 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001810 // Set heap limits.
1811 static const int K = 1024;
1812 v8::ResourceConstraints constraints;
1813 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001814 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001815 v8::SetResourceConstraints(&constraints);
1816
1817 // Execute a script that causes out of memory.
1818 v8::HandleScope scope;
1819 LocalContext context;
1820 v8::V8::IgnoreOutOfMemoryException();
1821 Local<Script> script =
1822 Script::Compile(String::New(js_code_causing_out_of_memory));
1823 Local<Value> result = script->Run();
1824
1825 // Check for out of memory state.
1826 CHECK(result.IsEmpty());
1827 CHECK(context->HasOutOfMemoryException());
1828}
1829
1830
1831v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1832 ApiTestFuzzer::Fuzz();
1833
1834 v8::HandleScope scope;
1835 LocalContext context;
1836 Local<Script> script =
1837 Script::Compile(String::New(js_code_causing_out_of_memory));
1838 Local<Value> result = script->Run();
1839
1840 // Check for out of memory state.
1841 CHECK(result.IsEmpty());
1842 CHECK(context->HasOutOfMemoryException());
1843
1844 return result;
1845}
1846
1847
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001848TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001849 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001850 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001851 // Set heap limits.
1852 static const int K = 1024;
1853 v8::ResourceConstraints constraints;
1854 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001855 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001856 v8::SetResourceConstraints(&constraints);
1857
1858 v8::HandleScope scope;
1859 Local<ObjectTemplate> templ = ObjectTemplate::New();
1860 templ->Set(v8_str("ProvokeOutOfMemory"),
1861 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1862 LocalContext context(0, templ);
1863 v8::V8::IgnoreOutOfMemoryException();
1864 Local<Value> result = CompileRun(
1865 "var thrown = false;"
1866 "try {"
1867 " ProvokeOutOfMemory();"
1868 "} catch (e) {"
1869 " thrown = true;"
1870 "}");
1871 // Check for out of memory state.
1872 CHECK(result.IsEmpty());
1873 CHECK(context->HasOutOfMemoryException());
1874}
1875
1876
1877TEST(HugeConsStringOutOfMemory) {
1878 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001879 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 v8::HandleScope scope;
1881 LocalContext context;
1882 // Set heap limits.
1883 static const int K = 1024;
1884 v8::ResourceConstraints constraints;
1885 constraints.set_max_young_space_size(256 * K);
1886 constraints.set_max_old_space_size(2 * K * K);
1887 v8::SetResourceConstraints(&constraints);
1888
1889 // Execute a script that causes out of memory.
1890 v8::V8::IgnoreOutOfMemoryException();
1891
1892 // Build huge string. This should fail with out of memory exception.
1893 Local<Value> result = CompileRun(
1894 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001895 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001896
1897 // Check for out of memory state.
1898 CHECK(result.IsEmpty());
1899 CHECK(context->HasOutOfMemoryException());
1900}
1901
1902
1903THREADED_TEST(ConstructCall) {
1904 v8::HandleScope scope;
1905 LocalContext context;
1906 CompileRun(
1907 "function Foo() {"
1908 " var result = [];"
1909 " for (var i = 0; i < arguments.length; i++) {"
1910 " result.push(arguments[i]);"
1911 " }"
1912 " return result;"
1913 "}");
1914 Local<Function> Foo =
1915 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1916
1917 v8::Handle<Value>* args0 = NULL;
1918 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1919 CHECK_EQ(0, a0->Length());
1920
1921 v8::Handle<Value> args1[] = { v8_num(1.1) };
1922 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1923 CHECK_EQ(1, a1->Length());
1924 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1925
1926 v8::Handle<Value> args2[] = { v8_num(2.2),
1927 v8_num(3.3) };
1928 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1929 CHECK_EQ(2, a2->Length());
1930 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1931 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1932
1933 v8::Handle<Value> args3[] = { v8_num(4.4),
1934 v8_num(5.5),
1935 v8_num(6.6) };
1936 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1937 CHECK_EQ(3, a3->Length());
1938 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1939 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1940 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1941
1942 v8::Handle<Value> args4[] = { v8_num(7.7),
1943 v8_num(8.8),
1944 v8_num(9.9),
1945 v8_num(10.11) };
1946 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1947 CHECK_EQ(4, a4->Length());
1948 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1949 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1950 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1951 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1952}
1953
1954
1955static void CheckUncle(v8::TryCatch* try_catch) {
1956 CHECK(try_catch->HasCaught());
1957 String::AsciiValue str_value(try_catch->Exception());
1958 CHECK_EQ(*str_value, "uncle?");
1959 try_catch->Reset();
1960}
1961
1962
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001963THREADED_TEST(ConversionNumber) {
1964 v8::HandleScope scope;
1965 LocalContext env;
1966 // Very large number.
1967 CompileRun("var obj = Math.pow(2,32) * 1237;");
1968 Local<Value> obj = env->Global()->Get(v8_str("obj"));
1969 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
1970 CHECK_EQ(0, obj->ToInt32()->Value());
1971 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
1972 // Large number.
1973 CompileRun("var obj = -1234567890123;");
1974 obj = env->Global()->Get(v8_str("obj"));
1975 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
1976 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
1977 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
1978 // Small positive integer.
1979 CompileRun("var obj = 42;");
1980 obj = env->Global()->Get(v8_str("obj"));
1981 CHECK_EQ(42.0, obj->ToNumber()->Value());
1982 CHECK_EQ(42, obj->ToInt32()->Value());
1983 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
1984 // Negative integer.
1985 CompileRun("var obj = -37;");
1986 obj = env->Global()->Get(v8_str("obj"));
1987 CHECK_EQ(-37.0, obj->ToNumber()->Value());
1988 CHECK_EQ(-37, obj->ToInt32()->Value());
1989 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
1990 // Positive non-int32 integer.
1991 CompileRun("var obj = 0x81234567;");
1992 obj = env->Global()->Get(v8_str("obj"));
1993 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
1994 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
1995 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
1996 // Fraction.
1997 CompileRun("var obj = 42.3;");
1998 obj = env->Global()->Get(v8_str("obj"));
1999 CHECK_EQ(42.3, obj->ToNumber()->Value());
2000 CHECK_EQ(42, obj->ToInt32()->Value());
2001 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2002 // Large negative fraction.
2003 CompileRun("var obj = -5726623061.75;");
2004 obj = env->Global()->Get(v8_str("obj"));
2005 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2006 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2007 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2008}
2009
2010
2011THREADED_TEST(isNumberType) {
2012 v8::HandleScope scope;
2013 LocalContext env;
2014 // Very large number.
2015 CompileRun("var obj = Math.pow(2,32) * 1237;");
2016 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2017 CHECK(!obj->IsInt32());
2018 CHECK(!obj->IsUint32());
2019 // Large negative number.
2020 CompileRun("var obj = -1234567890123;");
2021 obj = env->Global()->Get(v8_str("obj"));
2022 CHECK(!obj->IsInt32());
2023 CHECK(!obj->IsUint32());
2024 // Small positive integer.
2025 CompileRun("var obj = 42;");
2026 obj = env->Global()->Get(v8_str("obj"));
2027 CHECK(obj->IsInt32());
2028 CHECK(obj->IsUint32());
2029 // Negative integer.
2030 CompileRun("var obj = -37;");
2031 obj = env->Global()->Get(v8_str("obj"));
2032 CHECK(obj->IsInt32());
2033 CHECK(!obj->IsUint32());
2034 // Positive non-int32 integer.
2035 CompileRun("var obj = 0x81234567;");
2036 obj = env->Global()->Get(v8_str("obj"));
2037 CHECK(!obj->IsInt32());
2038 CHECK(obj->IsUint32());
2039 // Fraction.
2040 CompileRun("var obj = 42.3;");
2041 obj = env->Global()->Get(v8_str("obj"));
2042 CHECK(!obj->IsInt32());
2043 CHECK(!obj->IsUint32());
2044 // Large negative fraction.
2045 CompileRun("var obj = -5726623061.75;");
2046 obj = env->Global()->Get(v8_str("obj"));
2047 CHECK(!obj->IsInt32());
2048 CHECK(!obj->IsUint32());
2049}
2050
2051
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002052THREADED_TEST(ConversionException) {
2053 v8::HandleScope scope;
2054 LocalContext env;
2055 CompileRun(
2056 "function TestClass() { };"
2057 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2058 "var obj = new TestClass();");
2059 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2060
2061 v8::TryCatch try_catch;
2062
2063 Local<Value> to_string_result = obj->ToString();
2064 CHECK(to_string_result.IsEmpty());
2065 CheckUncle(&try_catch);
2066
2067 Local<Value> to_number_result = obj->ToNumber();
2068 CHECK(to_number_result.IsEmpty());
2069 CheckUncle(&try_catch);
2070
2071 Local<Value> to_integer_result = obj->ToInteger();
2072 CHECK(to_integer_result.IsEmpty());
2073 CheckUncle(&try_catch);
2074
2075 Local<Value> to_uint32_result = obj->ToUint32();
2076 CHECK(to_uint32_result.IsEmpty());
2077 CheckUncle(&try_catch);
2078
2079 Local<Value> to_int32_result = obj->ToInt32();
2080 CHECK(to_int32_result.IsEmpty());
2081 CheckUncle(&try_catch);
2082
2083 Local<Value> to_object_result = v8::Undefined()->ToObject();
2084 CHECK(to_object_result.IsEmpty());
2085 CHECK(try_catch.HasCaught());
2086 try_catch.Reset();
2087
2088 int32_t int32_value = obj->Int32Value();
2089 CHECK_EQ(0, int32_value);
2090 CheckUncle(&try_catch);
2091
2092 uint32_t uint32_value = obj->Uint32Value();
2093 CHECK_EQ(0, uint32_value);
2094 CheckUncle(&try_catch);
2095
2096 double number_value = obj->NumberValue();
2097 CHECK_NE(0, IsNaN(number_value));
2098 CheckUncle(&try_catch);
2099
2100 int64_t integer_value = obj->IntegerValue();
2101 CHECK_EQ(0.0, static_cast<double>(integer_value));
2102 CheckUncle(&try_catch);
2103}
2104
2105
2106v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2107 ApiTestFuzzer::Fuzz();
2108 return v8::ThrowException(v8_str("konto"));
2109}
2110
2111
ager@chromium.org8bb60582008-12-11 12:02:20 +00002112v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2113 if (args.Length() < 1) return v8::Boolean::New(false);
2114 v8::HandleScope scope;
2115 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002116 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2117 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002118 return v8::Boolean::New(try_catch.HasCaught());
2119}
2120
2121
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002122THREADED_TEST(APICatch) {
2123 v8::HandleScope scope;
2124 Local<ObjectTemplate> templ = ObjectTemplate::New();
2125 templ->Set(v8_str("ThrowFromC"),
2126 v8::FunctionTemplate::New(ThrowFromC));
2127 LocalContext context(0, templ);
2128 CompileRun(
2129 "var thrown = false;"
2130 "try {"
2131 " ThrowFromC();"
2132 "} catch (e) {"
2133 " thrown = true;"
2134 "}");
2135 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2136 CHECK(thrown->BooleanValue());
2137}
2138
2139
ager@chromium.org8bb60582008-12-11 12:02:20 +00002140THREADED_TEST(APIThrowTryCatch) {
2141 v8::HandleScope scope;
2142 Local<ObjectTemplate> templ = ObjectTemplate::New();
2143 templ->Set(v8_str("ThrowFromC"),
2144 v8::FunctionTemplate::New(ThrowFromC));
2145 LocalContext context(0, templ);
2146 v8::TryCatch try_catch;
2147 CompileRun("ThrowFromC();");
2148 CHECK(try_catch.HasCaught());
2149}
2150
2151
2152// Test that a try-finally block doesn't shadow a try-catch block
2153// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002154//
2155// BUG(271): Some of the exception propagation does not work on the
2156// ARM simulator because the simulator separates the C++ stack and the
2157// JS stack. This test therefore fails on the simulator. The test is
2158// not threaded to allow the threading tests to run on the simulator.
2159TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002160 v8::HandleScope scope;
2161 Local<ObjectTemplate> templ = ObjectTemplate::New();
2162 templ->Set(v8_str("CCatcher"),
2163 v8::FunctionTemplate::New(CCatcher));
2164 LocalContext context(0, templ);
2165 Local<Value> result = CompileRun("try {"
2166 " try {"
2167 " CCatcher('throw 7;');"
2168 " } finally {"
2169 " }"
2170 "} catch (e) {"
2171 "}");
2172 CHECK(result->IsTrue());
2173}
2174
2175
2176static void receive_message(v8::Handle<v8::Message> message,
2177 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002178 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002179 message_received = true;
2180}
2181
2182
2183TEST(APIThrowMessage) {
2184 message_received = false;
2185 v8::HandleScope scope;
2186 v8::V8::AddMessageListener(receive_message);
2187 Local<ObjectTemplate> templ = ObjectTemplate::New();
2188 templ->Set(v8_str("ThrowFromC"),
2189 v8::FunctionTemplate::New(ThrowFromC));
2190 LocalContext context(0, templ);
2191 CompileRun("ThrowFromC();");
2192 CHECK(message_received);
2193 v8::V8::RemoveMessageListeners(check_message);
2194}
2195
2196
2197TEST(APIThrowMessageAndVerboseTryCatch) {
2198 message_received = false;
2199 v8::HandleScope scope;
2200 v8::V8::AddMessageListener(receive_message);
2201 Local<ObjectTemplate> templ = ObjectTemplate::New();
2202 templ->Set(v8_str("ThrowFromC"),
2203 v8::FunctionTemplate::New(ThrowFromC));
2204 LocalContext context(0, templ);
2205 v8::TryCatch try_catch;
2206 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002207 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002208 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002209 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002210 CHECK(message_received);
2211 v8::V8::RemoveMessageListeners(check_message);
2212}
2213
2214
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002215THREADED_TEST(ExternalScriptException) {
2216 v8::HandleScope scope;
2217 Local<ObjectTemplate> templ = ObjectTemplate::New();
2218 templ->Set(v8_str("ThrowFromC"),
2219 v8::FunctionTemplate::New(ThrowFromC));
2220 LocalContext context(0, templ);
2221
2222 v8::TryCatch try_catch;
2223 Local<Script> script
2224 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2225 Local<Value> result = script->Run();
2226 CHECK(result.IsEmpty());
2227 CHECK(try_catch.HasCaught());
2228 String::AsciiValue exception_value(try_catch.Exception());
2229 CHECK_EQ("konto", *exception_value);
2230}
2231
2232
2233
2234v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2235 ApiTestFuzzer::Fuzz();
2236 CHECK_EQ(4, args.Length());
2237 int count = args[0]->Int32Value();
2238 int cInterval = args[2]->Int32Value();
2239 if (count == 0) {
2240 return v8::ThrowException(v8_str("FromC"));
2241 } else {
2242 Local<v8::Object> global = Context::GetCurrent()->Global();
2243 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2244 v8::Handle<Value> argv[] = { v8_num(count - 1),
2245 args[1],
2246 args[2],
2247 args[3] };
2248 if (count % cInterval == 0) {
2249 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002250 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002251 int expected = args[3]->Int32Value();
2252 if (try_catch.HasCaught()) {
2253 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002254 CHECK(result.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002255 CHECK(!i::Top::has_scheduled_exception());
2256 } else {
2257 CHECK_NE(expected, count);
2258 }
2259 return result;
2260 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002261 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002262 }
2263 }
2264}
2265
2266
2267v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2268 ApiTestFuzzer::Fuzz();
2269 CHECK_EQ(3, args.Length());
2270 bool equality = args[0]->BooleanValue();
2271 int count = args[1]->Int32Value();
2272 int expected = args[2]->Int32Value();
2273 if (equality) {
2274 CHECK_EQ(count, expected);
2275 } else {
2276 CHECK_NE(count, expected);
2277 }
2278 return v8::Undefined();
2279}
2280
2281
ager@chromium.org8bb60582008-12-11 12:02:20 +00002282THREADED_TEST(EvalInTryFinally) {
2283 v8::HandleScope scope;
2284 LocalContext context;
2285 v8::TryCatch try_catch;
2286 CompileRun("(function() {"
2287 " try {"
2288 " eval('asldkf (*&^&*^');"
2289 " } finally {"
2290 " return;"
2291 " }"
2292 "})()");
2293 CHECK(!try_catch.HasCaught());
2294}
2295
2296
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002297// This test works by making a stack of alternating JavaScript and C
2298// activations. These activations set up exception handlers with regular
2299// intervals, one interval for C activations and another for JavaScript
2300// activations. When enough activations have been created an exception is
2301// thrown and we check that the right activation catches the exception and that
2302// no other activations do. The right activation is always the topmost one with
2303// a handler, regardless of whether it is in JavaScript or C.
2304//
2305// The notation used to describe a test case looks like this:
2306//
2307// *JS[4] *C[3] @JS[2] C[1] JS[0]
2308//
2309// Each entry is an activation, either JS or C. The index is the count at that
2310// level. Stars identify activations with exception handlers, the @ identifies
2311// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002312//
2313// BUG(271): Some of the exception propagation does not work on the
2314// ARM simulator because the simulator separates the C++ stack and the
2315// JS stack. This test therefore fails on the simulator. The test is
2316// not threaded to allow the threading tests to run on the simulator.
2317TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318 v8::HandleScope scope;
2319 Local<ObjectTemplate> templ = ObjectTemplate::New();
2320 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2321 templ->Set(v8_str("CThrowCountDown"),
2322 v8::FunctionTemplate::New(CThrowCountDown));
2323 LocalContext context(0, templ);
2324 CompileRun(
2325 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2326 " if (count == 0) throw 'FromJS';"
2327 " if (count % jsInterval == 0) {"
2328 " try {"
2329 " var value = CThrowCountDown(count - 1,"
2330 " jsInterval,"
2331 " cInterval,"
2332 " expected);"
2333 " check(false, count, expected);"
2334 " return value;"
2335 " } catch (e) {"
2336 " check(true, count, expected);"
2337 " }"
2338 " } else {"
2339 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2340 " }"
2341 "}");
2342 Local<Function> fun =
2343 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2344
2345 const int argc = 4;
2346 // count jsInterval cInterval expected
2347
2348 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2349 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2350 fun->Call(fun, argc, a0);
2351
2352 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2353 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2354 fun->Call(fun, argc, a1);
2355
2356 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2357 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2358 fun->Call(fun, argc, a2);
2359
2360 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2361 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2362 fun->Call(fun, argc, a3);
2363
2364 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2365 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2366 fun->Call(fun, argc, a4);
2367
2368 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2369 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2370 fun->Call(fun, argc, a5);
2371}
2372
2373
2374v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2375 ApiTestFuzzer::Fuzz();
2376 CHECK_EQ(1, args.Length());
2377 return v8::ThrowException(args[0]);
2378}
2379
2380
2381THREADED_TEST(ThrowValues) {
2382 v8::HandleScope scope;
2383 Local<ObjectTemplate> templ = ObjectTemplate::New();
2384 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2385 LocalContext context(0, templ);
2386 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2387 "function Run(obj) {"
2388 " try {"
2389 " Throw(obj);"
2390 " } catch (e) {"
2391 " return e;"
2392 " }"
2393 " return 'no exception';"
2394 "}"
2395 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2396 CHECK_EQ(5, result->Length());
2397 CHECK(result->Get(v8::Integer::New(0))->IsString());
2398 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2399 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2400 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2401 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2402 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2403 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2404}
2405
2406
2407THREADED_TEST(CatchZero) {
2408 v8::HandleScope scope;
2409 LocalContext context;
2410 v8::TryCatch try_catch;
2411 CHECK(!try_catch.HasCaught());
2412 Script::Compile(v8_str("throw 10"))->Run();
2413 CHECK(try_catch.HasCaught());
2414 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2415 try_catch.Reset();
2416 CHECK(!try_catch.HasCaught());
2417 Script::Compile(v8_str("throw 0"))->Run();
2418 CHECK(try_catch.HasCaught());
2419 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2420}
2421
2422
2423THREADED_TEST(CatchExceptionFromWith) {
2424 v8::HandleScope scope;
2425 LocalContext context;
2426 v8::TryCatch try_catch;
2427 CHECK(!try_catch.HasCaught());
2428 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2429 CHECK(try_catch.HasCaught());
2430}
2431
2432
2433THREADED_TEST(Equality) {
2434 v8::HandleScope scope;
2435 LocalContext context;
2436 // Check that equality works at all before relying on CHECK_EQ
2437 CHECK(v8_str("a")->Equals(v8_str("a")));
2438 CHECK(!v8_str("a")->Equals(v8_str("b")));
2439
2440 CHECK_EQ(v8_str("a"), v8_str("a"));
2441 CHECK_NE(v8_str("a"), v8_str("b"));
2442 CHECK_EQ(v8_num(1), v8_num(1));
2443 CHECK_EQ(v8_num(1.00), v8_num(1));
2444 CHECK_NE(v8_num(1), v8_num(2));
2445
2446 // Assume String is not symbol.
2447 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2448 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2449 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2450 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2451 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2452 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2453 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2454 CHECK(!not_a_number->StrictEquals(not_a_number));
2455 CHECK(v8::False()->StrictEquals(v8::False()));
2456 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2457
2458 v8::Handle<v8::Object> obj = v8::Object::New();
2459 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2460 CHECK(alias->StrictEquals(obj));
2461 alias.Dispose();
2462}
2463
2464
2465THREADED_TEST(MultiRun) {
2466 v8::HandleScope scope;
2467 LocalContext context;
2468 Local<Script> script = Script::Compile(v8_str("x"));
2469 for (int i = 0; i < 10; i++)
2470 script->Run();
2471}
2472
2473
2474static v8::Handle<Value> GetXValue(Local<String> name,
2475 const AccessorInfo& info) {
2476 ApiTestFuzzer::Fuzz();
2477 CHECK_EQ(info.Data(), v8_str("donut"));
2478 CHECK_EQ(name, v8_str("x"));
2479 return name;
2480}
2481
2482
2483THREADED_TEST(SimplePropertyRead) {
2484 v8::HandleScope scope;
2485 Local<ObjectTemplate> templ = ObjectTemplate::New();
2486 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2487 LocalContext context;
2488 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2489 Local<Script> script = Script::Compile(v8_str("obj.x"));
2490 for (int i = 0; i < 10; i++) {
2491 Local<Value> result = script->Run();
2492 CHECK_EQ(result, v8_str("x"));
2493 }
2494}
2495
ager@chromium.org5c838252010-02-19 08:53:10 +00002496THREADED_TEST(DefinePropertyOnAPIAccessor) {
2497 v8::HandleScope scope;
2498 Local<ObjectTemplate> templ = ObjectTemplate::New();
2499 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2500 LocalContext context;
2501 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2502
2503 // Uses getOwnPropertyDescriptor to check the configurable status
2504 Local<Script> script_desc
2505 = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
2506 "obj, 'x');"
2507 "prop.configurable;"));
2508 Local<Value> result = script_desc->Run();
2509 CHECK_EQ(result->BooleanValue(), true);
2510
2511 // Redefine get - but still configurable
2512 Local<Script> script_define
2513 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2514 " configurable: true };"
2515 "Object.defineProperty(obj, 'x', desc);"
2516 "obj.x"));
2517 result = script_define->Run();
2518 CHECK_EQ(result, v8_num(42));
2519
2520 // Check that the accessor is still configurable
2521 result = script_desc->Run();
2522 CHECK_EQ(result->BooleanValue(), true);
2523
2524 // Redefine to a non-configurable
2525 script_define
2526 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2527 " configurable: false };"
2528 "Object.defineProperty(obj, 'x', desc);"
2529 "obj.x"));
2530 result = script_define->Run();
2531 CHECK_EQ(result, v8_num(43));
2532 result = script_desc->Run();
2533 CHECK_EQ(result->BooleanValue(), false);
2534
2535 // Make sure that it is not possible to redefine again
2536 v8::TryCatch try_catch;
2537 result = script_define->Run();
2538 CHECK(try_catch.HasCaught());
2539 String::AsciiValue exception_value(try_catch.Exception());
2540 CHECK_EQ(*exception_value,
2541 "TypeError: Cannot redefine property: defineProperty");
2542}
2543
2544THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2545 v8::HandleScope scope;
2546 Local<ObjectTemplate> templ = ObjectTemplate::New();
2547 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2548 LocalContext context;
2549 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2550
2551 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2552 "Object.getOwnPropertyDescriptor( "
2553 "obj, 'x');"
2554 "prop.configurable;"));
2555 Local<Value> result = script_desc->Run();
2556 CHECK_EQ(result->BooleanValue(), true);
2557
2558 Local<Script> script_define =
2559 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2560 " configurable: true };"
2561 "Object.defineProperty(obj, 'x', desc);"
2562 "obj.x"));
2563 result = script_define->Run();
2564 CHECK_EQ(result, v8_num(42));
2565
2566
2567 result = script_desc->Run();
2568 CHECK_EQ(result->BooleanValue(), true);
2569
2570
2571 script_define =
2572 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2573 " configurable: false };"
2574 "Object.defineProperty(obj, 'x', desc);"
2575 "obj.x"));
2576 result = script_define->Run();
2577 CHECK_EQ(result, v8_num(43));
2578 result = script_desc->Run();
2579
2580 CHECK_EQ(result->BooleanValue(), false);
2581
2582 v8::TryCatch try_catch;
2583 result = script_define->Run();
2584 CHECK(try_catch.HasCaught());
2585 String::AsciiValue exception_value(try_catch.Exception());
2586 CHECK_EQ(*exception_value,
2587 "TypeError: Cannot redefine property: defineProperty");
2588}
2589
2590
2591
2592
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002593
2594v8::Persistent<Value> xValue;
2595
2596
2597static void SetXValue(Local<String> name,
2598 Local<Value> value,
2599 const AccessorInfo& info) {
2600 CHECK_EQ(value, v8_num(4));
2601 CHECK_EQ(info.Data(), v8_str("donut"));
2602 CHECK_EQ(name, v8_str("x"));
2603 CHECK(xValue.IsEmpty());
2604 xValue = v8::Persistent<Value>::New(value);
2605}
2606
2607
2608THREADED_TEST(SimplePropertyWrite) {
2609 v8::HandleScope scope;
2610 Local<ObjectTemplate> templ = ObjectTemplate::New();
2611 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2612 LocalContext context;
2613 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2614 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2615 for (int i = 0; i < 10; i++) {
2616 CHECK(xValue.IsEmpty());
2617 script->Run();
2618 CHECK_EQ(v8_num(4), xValue);
2619 xValue.Dispose();
2620 xValue = v8::Persistent<Value>();
2621 }
2622}
2623
2624
2625static v8::Handle<Value> XPropertyGetter(Local<String> property,
2626 const AccessorInfo& info) {
2627 ApiTestFuzzer::Fuzz();
2628 CHECK(info.Data()->IsUndefined());
2629 return property;
2630}
2631
2632
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002633THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002634 v8::HandleScope scope;
2635 Local<ObjectTemplate> templ = ObjectTemplate::New();
2636 templ->SetNamedPropertyHandler(XPropertyGetter);
2637 LocalContext context;
2638 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2639 Local<Script> script = Script::Compile(v8_str("obj.x"));
2640 for (int i = 0; i < 10; i++) {
2641 Local<Value> result = script->Run();
2642 CHECK_EQ(result, v8_str("x"));
2643 }
2644}
2645
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002646
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00002647THREADED_TEST(NamedInterceptorDictionaryIC) {
2648 v8::HandleScope scope;
2649 Local<ObjectTemplate> templ = ObjectTemplate::New();
2650 templ->SetNamedPropertyHandler(XPropertyGetter);
2651 LocalContext context;
2652 // Create an object with a named interceptor.
2653 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2654 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2655 for (int i = 0; i < 10; i++) {
2656 Local<Value> result = script->Run();
2657 CHECK_EQ(result, v8_str("x"));
2658 }
2659 // Create a slow case object and a function accessing a property in
2660 // that slow case object (with dictionary probing in generated
2661 // code). Then force object with a named interceptor into slow-case,
2662 // pass it to the function, and check that the interceptor is called
2663 // instead of accessing the local property.
2664 Local<Value> result =
2665 CompileRun("function get_x(o) { return o.x; };"
2666 "var obj = { x : 42, y : 0 };"
2667 "delete obj.y;"
2668 "for (var i = 0; i < 10; i++) get_x(obj);"
2669 "interceptor_obj.x = 42;"
2670 "interceptor_obj.y = 10;"
2671 "delete interceptor_obj.y;"
2672 "get_x(interceptor_obj)");
2673 CHECK_EQ(result, v8_str("x"));
2674}
2675
2676
ager@chromium.org5c838252010-02-19 08:53:10 +00002677static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2678 const AccessorInfo& info) {
2679 // Set x on the prototype object and do not handle the get request.
2680 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002681 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00002682 return v8::Handle<Value>();
2683}
2684
2685
2686// This is a regression test for http://crbug.com/20104. Map
2687// transitions should not interfere with post interceptor lookup.
2688THREADED_TEST(NamedInterceptorMapTransitionRead) {
2689 v8::HandleScope scope;
2690 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2691 Local<v8::ObjectTemplate> instance_template
2692 = function_template->InstanceTemplate();
2693 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2694 LocalContext context;
2695 context->Global()->Set(v8_str("F"), function_template->GetFunction());
2696 // Create an instance of F and introduce a map transition for x.
2697 CompileRun("var o = new F(); o.x = 23;");
2698 // Create an instance of F and invoke the getter. The result should be 23.
2699 Local<Value> result = CompileRun("o = new F(); o.x");
2700 CHECK_EQ(result->Int32Value(), 23);
2701}
2702
2703
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002704static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2705 const AccessorInfo& info) {
2706 ApiTestFuzzer::Fuzz();
2707 if (index == 37) {
2708 return v8::Handle<Value>(v8_num(625));
2709 }
2710 return v8::Handle<Value>();
2711}
2712
2713
2714static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2715 Local<Value> value,
2716 const AccessorInfo& info) {
2717 ApiTestFuzzer::Fuzz();
2718 if (index == 39) {
2719 return value;
2720 }
2721 return v8::Handle<Value>();
2722}
2723
2724
2725THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2726 v8::HandleScope scope;
2727 Local<ObjectTemplate> templ = ObjectTemplate::New();
2728 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2729 IndexedPropertySetter);
2730 LocalContext context;
2731 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2732 Local<Script> getter_script = Script::Compile(v8_str(
2733 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2734 Local<Script> setter_script = Script::Compile(v8_str(
2735 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2736 "obj[17] = 23;"
2737 "obj.foo;"));
2738 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2739 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2740 "obj[39] = 47;"
2741 "obj.foo;")); // This setter should not run, due to the interceptor.
2742 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2743 "obj[37];"));
2744 Local<Value> result = getter_script->Run();
2745 CHECK_EQ(v8_num(5), result);
2746 result = setter_script->Run();
2747 CHECK_EQ(v8_num(23), result);
2748 result = interceptor_setter_script->Run();
2749 CHECK_EQ(v8_num(23), result);
2750 result = interceptor_getter_script->Run();
2751 CHECK_EQ(v8_num(625), result);
2752}
2753
2754
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00002755static v8::Handle<Value> IdentityIndexedPropertyGetter(
2756 uint32_t index,
2757 const AccessorInfo& info) {
2758 return v8::Integer::New(index);
2759}
2760
2761
2762THREADED_TEST(IndexedInterceptorWithNoSetter) {
2763 v8::HandleScope scope;
2764 Local<ObjectTemplate> templ = ObjectTemplate::New();
2765 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2766
2767 LocalContext context;
2768 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2769
2770 const char* code =
2771 "try {"
2772 " obj[0] = 239;"
2773 " for (var i = 0; i < 100; i++) {"
2774 " var v = obj[0];"
2775 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
2776 " }"
2777 " 'PASSED'"
2778 "} catch(e) {"
2779 " e"
2780 "}";
2781 ExpectString(code, "PASSED");
2782}
2783
2784
ager@chromium.org5c838252010-02-19 08:53:10 +00002785THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
2786 v8::HandleScope scope;
2787 Local<ObjectTemplate> templ = ObjectTemplate::New();
2788 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2789
2790 LocalContext context;
2791 Local<v8::Object> obj = templ->NewInstance();
2792 obj->TurnOnAccessCheck();
2793 context->Global()->Set(v8_str("obj"), obj);
2794
2795 const char* code =
2796 "try {"
2797 " for (var i = 0; i < 100; i++) {"
2798 " var v = obj[0];"
2799 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
2800 " }"
2801 " 'PASSED'"
2802 "} catch(e) {"
2803 " e"
2804 "}";
2805 ExpectString(code, "PASSED");
2806}
2807
2808
2809THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
2810 i::FLAG_allow_natives_syntax = true;
2811 v8::HandleScope scope;
2812 Local<ObjectTemplate> templ = ObjectTemplate::New();
2813 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2814
2815 LocalContext context;
2816 Local<v8::Object> obj = templ->NewInstance();
2817 context->Global()->Set(v8_str("obj"), obj);
2818
2819 const char* code =
2820 "try {"
2821 " for (var i = 0; i < 100; i++) {"
2822 " var expected = i;"
2823 " if (i == 5) {"
2824 " %EnableAccessChecks(obj);"
2825 " expected = undefined;"
2826 " }"
2827 " var v = obj[i];"
2828 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2829 " if (i == 5) %DisableAccessChecks(obj);"
2830 " }"
2831 " 'PASSED'"
2832 "} catch(e) {"
2833 " e"
2834 "}";
2835 ExpectString(code, "PASSED");
2836}
2837
2838
2839THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
2840 v8::HandleScope scope;
2841 Local<ObjectTemplate> templ = ObjectTemplate::New();
2842 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2843
2844 LocalContext context;
2845 Local<v8::Object> obj = templ->NewInstance();
2846 context->Global()->Set(v8_str("obj"), obj);
2847
2848 const char* code =
2849 "try {"
2850 " for (var i = 0; i < 100; i++) {"
2851 " var v = obj[i];"
2852 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2853 " }"
2854 " 'PASSED'"
2855 "} catch(e) {"
2856 " e"
2857 "}";
2858 ExpectString(code, "PASSED");
2859}
2860
2861
2862THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
2863 v8::HandleScope scope;
2864 Local<ObjectTemplate> templ = ObjectTemplate::New();
2865 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2866
2867 LocalContext context;
2868 Local<v8::Object> obj = templ->NewInstance();
2869 context->Global()->Set(v8_str("obj"), obj);
2870
2871 const char* code =
2872 "try {"
2873 " for (var i = 0; i < 100; i++) {"
2874 " var expected = i;"
2875 " if (i == 50) {"
2876 " i = 'foobar';"
2877 " expected = undefined;"
2878 " }"
2879 " var v = obj[i];"
2880 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2881 " }"
2882 " 'PASSED'"
2883 "} catch(e) {"
2884 " e"
2885 "}";
2886 ExpectString(code, "PASSED");
2887}
2888
2889
2890THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
2891 v8::HandleScope scope;
2892 Local<ObjectTemplate> templ = ObjectTemplate::New();
2893 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2894
2895 LocalContext context;
2896 Local<v8::Object> obj = templ->NewInstance();
2897 context->Global()->Set(v8_str("obj"), obj);
2898
2899 const char* code =
2900 "var original = obj;"
2901 "try {"
2902 " for (var i = 0; i < 100; i++) {"
2903 " var expected = i;"
2904 " if (i == 50) {"
2905 " obj = {50: 'foobar'};"
2906 " expected = 'foobar';"
2907 " }"
2908 " var v = obj[i];"
2909 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2910 " if (i == 50) obj = original;"
2911 " }"
2912 " 'PASSED'"
2913 "} catch(e) {"
2914 " e"
2915 "}";
2916 ExpectString(code, "PASSED");
2917}
2918
2919
2920THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
2921 v8::HandleScope scope;
2922 Local<ObjectTemplate> templ = ObjectTemplate::New();
2923 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2924
2925 LocalContext context;
2926 Local<v8::Object> obj = templ->NewInstance();
2927 context->Global()->Set(v8_str("obj"), obj);
2928
2929 const char* code =
2930 "var original = obj;"
2931 "try {"
2932 " for (var i = 0; i < 100; i++) {"
2933 " var expected = i;"
2934 " if (i == 5) {"
2935 " obj = 239;"
2936 " expected = undefined;"
2937 " }"
2938 " var v = obj[i];"
2939 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2940 " if (i == 5) obj = original;"
2941 " }"
2942 " 'PASSED'"
2943 "} catch(e) {"
2944 " e"
2945 "}";
2946 ExpectString(code, "PASSED");
2947}
2948
2949
2950THREADED_TEST(IndexedInterceptorOnProto) {
2951 v8::HandleScope scope;
2952 Local<ObjectTemplate> templ = ObjectTemplate::New();
2953 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2954
2955 LocalContext context;
2956 Local<v8::Object> obj = templ->NewInstance();
2957 context->Global()->Set(v8_str("obj"), obj);
2958
2959 const char* code =
2960 "var o = {__proto__: obj};"
2961 "try {"
2962 " for (var i = 0; i < 100; i++) {"
2963 " var v = o[i];"
2964 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2965 " }"
2966 " 'PASSED'"
2967 "} catch(e) {"
2968 " e"
2969 "}";
2970 ExpectString(code, "PASSED");
2971}
2972
2973
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002974THREADED_TEST(MultiContexts) {
2975 v8::HandleScope scope;
2976 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2977 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2978
2979 Local<String> password = v8_str("Password");
2980
2981 // Create an environment
2982 LocalContext context0(0, templ);
2983 context0->SetSecurityToken(password);
2984 v8::Handle<v8::Object> global0 = context0->Global();
2985 global0->Set(v8_str("custom"), v8_num(1234));
2986 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2987
2988 // Create an independent environment
2989 LocalContext context1(0, templ);
2990 context1->SetSecurityToken(password);
2991 v8::Handle<v8::Object> global1 = context1->Global();
2992 global1->Set(v8_str("custom"), v8_num(1234));
2993 CHECK_NE(global0, global1);
2994 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2995 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2996
2997 // Now create a new context with the old global
2998 LocalContext context2(0, templ, global1);
2999 context2->SetSecurityToken(password);
3000 v8::Handle<v8::Object> global2 = context2->Global();
3001 CHECK_EQ(global1, global2);
3002 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3003 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3004}
3005
3006
3007THREADED_TEST(FunctionPrototypeAcrossContexts) {
3008 // Make sure that functions created by cloning boilerplates cannot
3009 // communicate through their __proto__ field.
3010
3011 v8::HandleScope scope;
3012
3013 LocalContext env0;
3014 v8::Handle<v8::Object> global0 =
3015 env0->Global();
3016 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003017 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003018 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003019 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003020 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003021 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003022 proto0->Set(v8_str("custom"), v8_num(1234));
3023
3024 LocalContext env1;
3025 v8::Handle<v8::Object> global1 =
3026 env1->Global();
3027 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003028 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003029 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003030 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003031 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003032 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003033 CHECK(!proto1->Has(v8_str("custom")));
3034}
3035
3036
3037THREADED_TEST(Regress892105) {
3038 // Make sure that object and array literals created by cloning
3039 // boilerplates cannot communicate through their __proto__
3040 // field. This is rather difficult to check, but we try to add stuff
3041 // to Object.prototype and Array.prototype and create a new
3042 // environment. This should succeed.
3043
3044 v8::HandleScope scope;
3045
3046 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3047 "Array.prototype.arr = 4567;"
3048 "8901");
3049
3050 LocalContext env0;
3051 Local<Script> script0 = Script::Compile(source);
3052 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3053
3054 LocalContext env1;
3055 Local<Script> script1 = Script::Compile(source);
3056 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3057}
3058
3059
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003060THREADED_TEST(UndetectableObject) {
3061 v8::HandleScope scope;
3062 LocalContext env;
3063
3064 Local<v8::FunctionTemplate> desc =
3065 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3066 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3067
3068 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3069 env->Global()->Set(v8_str("undetectable"), obj);
3070
3071 ExpectString("undetectable.toString()", "[object Object]");
3072 ExpectString("typeof undetectable", "undefined");
3073 ExpectString("typeof(undetectable)", "undefined");
3074 ExpectBoolean("typeof undetectable == 'undefined'", true);
3075 ExpectBoolean("typeof undetectable == 'object'", false);
3076 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3077 ExpectBoolean("!undetectable", true);
3078
3079 ExpectObject("true&&undetectable", obj);
3080 ExpectBoolean("false&&undetectable", false);
3081 ExpectBoolean("true||undetectable", true);
3082 ExpectObject("false||undetectable", obj);
3083
3084 ExpectObject("undetectable&&true", obj);
3085 ExpectObject("undetectable&&false", obj);
3086 ExpectBoolean("undetectable||true", true);
3087 ExpectBoolean("undetectable||false", false);
3088
3089 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003090 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003091 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003092 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003093 ExpectBoolean("undetectable==undetectable", true);
3094
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003095
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003096 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003097 ExpectBoolean("null===undetectable", false);
3098 ExpectBoolean("undetectable===undefined", false);
3099 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003100 ExpectBoolean("undetectable===undetectable", true);
3101}
3102
3103
3104THREADED_TEST(UndetectableString) {
3105 v8::HandleScope scope;
3106 LocalContext env;
3107
3108 Local<String> obj = String::NewUndetectable("foo");
3109 env->Global()->Set(v8_str("undetectable"), obj);
3110
3111 ExpectString("undetectable", "foo");
3112 ExpectString("typeof undetectable", "undefined");
3113 ExpectString("typeof(undetectable)", "undefined");
3114 ExpectBoolean("typeof undetectable == 'undefined'", true);
3115 ExpectBoolean("typeof undetectable == 'string'", false);
3116 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3117 ExpectBoolean("!undetectable", true);
3118
3119 ExpectObject("true&&undetectable", obj);
3120 ExpectBoolean("false&&undetectable", false);
3121 ExpectBoolean("true||undetectable", true);
3122 ExpectObject("false||undetectable", obj);
3123
3124 ExpectObject("undetectable&&true", obj);
3125 ExpectObject("undetectable&&false", obj);
3126 ExpectBoolean("undetectable||true", true);
3127 ExpectBoolean("undetectable||false", false);
3128
3129 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003130 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003131 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003132 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003133 ExpectBoolean("undetectable==undetectable", true);
3134
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003135
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003136 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003137 ExpectBoolean("null===undetectable", false);
3138 ExpectBoolean("undetectable===undefined", false);
3139 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003140 ExpectBoolean("undetectable===undetectable", true);
3141}
3142
3143
3144template <typename T> static void USE(T) { }
3145
3146
3147// This test is not intended to be run, just type checked.
3148static void PersistentHandles() {
3149 USE(PersistentHandles);
3150 Local<String> str = v8_str("foo");
3151 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3152 USE(p_str);
3153 Local<Script> scr = Script::Compile(v8_str(""));
3154 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3155 USE(p_scr);
3156 Local<ObjectTemplate> templ = ObjectTemplate::New();
3157 v8::Persistent<ObjectTemplate> p_templ =
3158 v8::Persistent<ObjectTemplate>::New(templ);
3159 USE(p_templ);
3160}
3161
3162
3163static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3164 ApiTestFuzzer::Fuzz();
3165 return v8::Undefined();
3166}
3167
3168
3169THREADED_TEST(GlobalObjectTemplate) {
3170 v8::HandleScope handle_scope;
3171 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3172 global_template->Set(v8_str("JSNI_Log"),
3173 v8::FunctionTemplate::New(HandleLogDelegator));
3174 v8::Persistent<Context> context = Context::New(0, global_template);
3175 Context::Scope context_scope(context);
3176 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3177 context.Dispose();
3178}
3179
3180
3181static const char* kSimpleExtensionSource =
3182 "function Foo() {"
3183 " return 4;"
3184 "}";
3185
3186
3187THREADED_TEST(SimpleExtensions) {
3188 v8::HandleScope handle_scope;
3189 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3190 const char* extension_names[] = { "simpletest" };
3191 v8::ExtensionConfiguration extensions(1, extension_names);
3192 v8::Handle<Context> context = Context::New(&extensions);
3193 Context::Scope lock(context);
3194 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3195 CHECK_EQ(result, v8::Integer::New(4));
3196}
3197
3198
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003199static const char* kEvalExtensionSource1 =
3200 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003201 " var x = 42;"
3202 " return eval('x');"
3203 "}";
3204
3205
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003206static const char* kEvalExtensionSource2 =
3207 "(function() {"
3208 " var x = 42;"
3209 " function e() {"
3210 " return eval('x');"
3211 " }"
3212 " this.UseEval2 = e;"
3213 "})()";
3214
3215
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003216THREADED_TEST(UseEvalFromExtension) {
3217 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003218 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3219 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3220 const char* extension_names[] = { "evaltest1", "evaltest2" };
3221 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003222 v8::Handle<Context> context = Context::New(&extensions);
3223 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003224 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3225 CHECK_EQ(result, v8::Integer::New(42));
3226 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003227 CHECK_EQ(result, v8::Integer::New(42));
3228}
3229
3230
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003231static const char* kWithExtensionSource1 =
3232 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003233 " var x = 42;"
3234 " with({x:87}) { return x; }"
3235 "}";
3236
3237
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003238
3239static const char* kWithExtensionSource2 =
3240 "(function() {"
3241 " var x = 42;"
3242 " function e() {"
3243 " with ({x:87}) { return x; }"
3244 " }"
3245 " this.UseWith2 = e;"
3246 "})()";
3247
3248
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003249THREADED_TEST(UseWithFromExtension) {
3250 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003251 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3252 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3253 const char* extension_names[] = { "withtest1", "withtest2" };
3254 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003255 v8::Handle<Context> context = Context::New(&extensions);
3256 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003257 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3258 CHECK_EQ(result, v8::Integer::New(87));
3259 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003260 CHECK_EQ(result, v8::Integer::New(87));
3261}
3262
3263
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003264THREADED_TEST(AutoExtensions) {
3265 v8::HandleScope handle_scope;
3266 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3267 extension->set_auto_enable(true);
3268 v8::RegisterExtension(extension);
3269 v8::Handle<Context> context = Context::New();
3270 Context::Scope lock(context);
3271 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3272 CHECK_EQ(result, v8::Integer::New(4));
3273}
3274
3275
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003276static const char* kSyntaxErrorInExtensionSource =
3277 "[";
3278
3279
3280// Test that a syntax error in an extension does not cause a fatal
3281// error but results in an empty context.
3282THREADED_TEST(SyntaxErrorExtensions) {
3283 v8::HandleScope handle_scope;
3284 v8::RegisterExtension(new Extension("syntaxerror",
3285 kSyntaxErrorInExtensionSource));
3286 const char* extension_names[] = { "syntaxerror" };
3287 v8::ExtensionConfiguration extensions(1, extension_names);
3288 v8::Handle<Context> context = Context::New(&extensions);
3289 CHECK(context.IsEmpty());
3290}
3291
3292
3293static const char* kExceptionInExtensionSource =
3294 "throw 42";
3295
3296
3297// Test that an exception when installing an extension does not cause
3298// a fatal error but results in an empty context.
3299THREADED_TEST(ExceptionExtensions) {
3300 v8::HandleScope handle_scope;
3301 v8::RegisterExtension(new Extension("exception",
3302 kExceptionInExtensionSource));
3303 const char* extension_names[] = { "exception" };
3304 v8::ExtensionConfiguration extensions(1, extension_names);
3305 v8::Handle<Context> context = Context::New(&extensions);
3306 CHECK(context.IsEmpty());
3307}
3308
3309
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003310static void CheckDependencies(const char* name, const char* expected) {
3311 v8::HandleScope handle_scope;
3312 v8::ExtensionConfiguration config(1, &name);
3313 LocalContext context(&config);
3314 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3315}
3316
3317
3318/*
3319 * Configuration:
3320 *
3321 * /-- B <--\
3322 * A <- -- D <-- E
3323 * \-- C <--/
3324 */
3325THREADED_TEST(ExtensionDependency) {
3326 static const char* kEDeps[] = { "D" };
3327 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3328 static const char* kDDeps[] = { "B", "C" };
3329 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3330 static const char* kBCDeps[] = { "A" };
3331 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3332 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3333 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3334 CheckDependencies("A", "undefinedA");
3335 CheckDependencies("B", "undefinedAB");
3336 CheckDependencies("C", "undefinedAC");
3337 CheckDependencies("D", "undefinedABCD");
3338 CheckDependencies("E", "undefinedABCDE");
3339 v8::HandleScope handle_scope;
3340 static const char* exts[2] = { "C", "E" };
3341 v8::ExtensionConfiguration config(2, exts);
3342 LocalContext context(&config);
3343 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3344}
3345
3346
3347static const char* kExtensionTestScript =
3348 "native function A();"
3349 "native function B();"
3350 "native function C();"
3351 "function Foo(i) {"
3352 " if (i == 0) return A();"
3353 " if (i == 1) return B();"
3354 " if (i == 2) return C();"
3355 "}";
3356
3357
3358static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3359 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003360 if (args.IsConstructCall()) {
3361 args.This()->Set(v8_str("data"), args.Data());
3362 return v8::Null();
3363 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003364 return args.Data();
3365}
3366
3367
3368class FunctionExtension : public Extension {
3369 public:
3370 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3371 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3372 v8::Handle<String> name);
3373};
3374
3375
3376static int lookup_count = 0;
3377v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3378 v8::Handle<String> name) {
3379 lookup_count++;
3380 if (name->Equals(v8_str("A"))) {
3381 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3382 } else if (name->Equals(v8_str("B"))) {
3383 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3384 } else if (name->Equals(v8_str("C"))) {
3385 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3386 } else {
3387 return v8::Handle<v8::FunctionTemplate>();
3388 }
3389}
3390
3391
3392THREADED_TEST(FunctionLookup) {
3393 v8::RegisterExtension(new FunctionExtension());
3394 v8::HandleScope handle_scope;
3395 static const char* exts[1] = { "functiontest" };
3396 v8::ExtensionConfiguration config(1, exts);
3397 LocalContext context(&config);
3398 CHECK_EQ(3, lookup_count);
3399 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3400 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3401 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3402}
3403
3404
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003405THREADED_TEST(NativeFunctionConstructCall) {
3406 v8::RegisterExtension(new FunctionExtension());
3407 v8::HandleScope handle_scope;
3408 static const char* exts[1] = { "functiontest" };
3409 v8::ExtensionConfiguration config(1, exts);
3410 LocalContext context(&config);
3411 for (int i = 0; i < 10; i++) {
3412 // Run a few times to ensure that allocation of objects doesn't
3413 // change behavior of a constructor function.
3414 CHECK_EQ(v8::Integer::New(8),
3415 Script::Compile(v8_str("(new A()).data"))->Run());
3416 CHECK_EQ(v8::Integer::New(7),
3417 Script::Compile(v8_str("(new B()).data"))->Run());
3418 CHECK_EQ(v8::Integer::New(6),
3419 Script::Compile(v8_str("(new C()).data"))->Run());
3420 }
3421}
3422
3423
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003424static const char* last_location;
3425static const char* last_message;
3426void StoringErrorCallback(const char* location, const char* message) {
3427 if (last_location == NULL) {
3428 last_location = location;
3429 last_message = message;
3430 }
3431}
3432
3433
3434// ErrorReporting creates a circular extensions configuration and
3435// tests that the fatal error handler gets called. This renders V8
3436// unusable and therefore this test cannot be run in parallel.
3437TEST(ErrorReporting) {
3438 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3439 static const char* aDeps[] = { "B" };
3440 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3441 static const char* bDeps[] = { "A" };
3442 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3443 last_location = NULL;
3444 v8::ExtensionConfiguration config(1, bDeps);
3445 v8::Handle<Context> context = Context::New(&config);
3446 CHECK(context.IsEmpty());
3447 CHECK_NE(last_location, NULL);
3448}
3449
3450
ager@chromium.org7c537e22008-10-16 08:43:32 +00003451static const char* js_code_causing_huge_string_flattening =
3452 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00003453 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00003454 " str = str + str;"
3455 "}"
3456 "str.match(/X/);";
3457
3458
3459void OOMCallback(const char* location, const char* message) {
3460 exit(0);
3461}
3462
3463
3464TEST(RegexpOutOfMemory) {
3465 // Execute a script that causes out of memory when flattening a string.
3466 v8::HandleScope scope;
3467 v8::V8::SetFatalErrorHandler(OOMCallback);
3468 LocalContext context;
3469 Local<Script> script =
3470 Script::Compile(String::New(js_code_causing_huge_string_flattening));
3471 last_location = NULL;
3472 Local<Value> result = script->Run();
3473
3474 CHECK(false); // Should not return.
3475}
3476
3477
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003478static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3479 v8::Handle<Value> data) {
3480 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003481 CHECK(message->GetScriptResourceName()->IsUndefined());
3482 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003483 message->GetLineNumber();
3484 message->GetSourceLine();
3485}
3486
3487
3488THREADED_TEST(ErrorWithMissingScriptInfo) {
3489 v8::HandleScope scope;
3490 LocalContext context;
3491 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3492 Script::Compile(v8_str("throw Error()"))->Run();
3493 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3494}
3495
3496
3497int global_index = 0;
3498
3499class Snorkel {
3500 public:
3501 Snorkel() { index_ = global_index++; }
3502 int index_;
3503};
3504
3505class Whammy {
3506 public:
3507 Whammy() {
3508 cursor_ = 0;
3509 }
3510 ~Whammy() {
3511 script_.Dispose();
3512 }
3513 v8::Handle<Script> getScript() {
3514 if (script_.IsEmpty())
3515 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3516 return Local<Script>(*script_);
3517 }
3518
3519 public:
3520 static const int kObjectCount = 256;
3521 int cursor_;
3522 v8::Persistent<v8::Object> objects_[kObjectCount];
3523 v8::Persistent<Script> script_;
3524};
3525
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003526static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003527 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3528 delete snorkel;
3529 obj.ClearWeak();
3530}
3531
3532v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3533 const AccessorInfo& info) {
3534 Whammy* whammy =
3535 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3536
3537 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3538
3539 v8::Handle<v8::Object> obj = v8::Object::New();
3540 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3541 if (!prev.IsEmpty()) {
3542 prev->Set(v8_str("next"), obj);
3543 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3544 whammy->objects_[whammy->cursor_].Clear();
3545 }
3546 whammy->objects_[whammy->cursor_] = global;
3547 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3548 return whammy->getScript()->Run();
3549}
3550
3551THREADED_TEST(WeakReference) {
3552 v8::HandleScope handle_scope;
3553 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3554 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3555 0, 0, 0, 0,
3556 v8::External::New(new Whammy()));
3557 const char* extension_list[] = { "v8/gc" };
3558 v8::ExtensionConfiguration extensions(1, extension_list);
3559 v8::Persistent<Context> context = Context::New(&extensions);
3560 Context::Scope context_scope(context);
3561
3562 v8::Handle<v8::Object> interceptor = templ->NewInstance();
3563 context->Global()->Set(v8_str("whammy"), interceptor);
3564 const char* code =
3565 "var last;"
3566 "for (var i = 0; i < 10000; i++) {"
3567 " var obj = whammy.length;"
3568 " if (last) last.next = obj;"
3569 " last = obj;"
3570 "}"
3571 "gc();"
3572 "4";
3573 v8::Handle<Value> result = CompileRun(code);
3574 CHECK_EQ(4.0, result->NumberValue());
3575
3576 context.Dispose();
3577}
3578
3579
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003580static bool in_scavenge = false;
3581static int last = -1;
3582
3583static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3584 CHECK_EQ(-1, last);
3585 last = 0;
3586 obj.Dispose();
3587 obj.Clear();
3588 in_scavenge = true;
3589 i::Heap::PerformScavenge();
3590 in_scavenge = false;
3591 *(reinterpret_cast<bool*>(data)) = true;
3592}
3593
3594static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3595 void* data) {
3596 CHECK_EQ(0, last);
3597 last = 1;
3598 *(reinterpret_cast<bool*>(data)) = in_scavenge;
3599 obj.Dispose();
3600 obj.Clear();
3601}
3602
3603THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3604 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3605 // Calling callbacks from scavenges is unsafe as objects held by those
3606 // handlers might have become strongly reachable, but scavenge doesn't
3607 // check that.
3608 v8::Persistent<Context> context = Context::New();
3609 Context::Scope context_scope(context);
3610
3611 v8::Persistent<v8::Object> object_a;
3612 v8::Persistent<v8::Object> object_b;
3613
3614 {
3615 v8::HandleScope handle_scope;
3616 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3617 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3618 }
3619
3620 bool object_a_disposed = false;
3621 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3622 bool released_in_scavenge = false;
3623 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3624
3625 while (!object_a_disposed) {
3626 i::Heap::CollectAllGarbage(false);
3627 }
3628 CHECK(!released_in_scavenge);
3629}
3630
3631
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003632v8::Handle<Function> args_fun;
3633
3634
3635static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3636 ApiTestFuzzer::Fuzz();
3637 CHECK_EQ(args_fun, args.Callee());
3638 CHECK_EQ(3, args.Length());
3639 CHECK_EQ(v8::Integer::New(1), args[0]);
3640 CHECK_EQ(v8::Integer::New(2), args[1]);
3641 CHECK_EQ(v8::Integer::New(3), args[2]);
3642 CHECK_EQ(v8::Undefined(), args[3]);
3643 v8::HandleScope scope;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00003644 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003645 return v8::Undefined();
3646}
3647
3648
3649THREADED_TEST(Arguments) {
3650 v8::HandleScope scope;
3651 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3652 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3653 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003654 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003655 v8_compile("f(1, 2, 3)")->Run();
3656}
3657
3658
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003659static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3660 const AccessorInfo&) {
3661 return v8::Handle<Value>();
3662}
3663
3664
3665static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3666 const AccessorInfo&) {
3667 return v8::Handle<Value>();
3668}
3669
3670
3671static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3672 const AccessorInfo&) {
3673 if (!name->Equals(v8_str("foo"))) {
3674 return v8::Handle<v8::Boolean>(); // not intercepted
3675 }
3676
3677 return v8::False(); // intercepted, and don't delete the property
3678}
3679
3680
3681static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3682 if (index != 2) {
3683 return v8::Handle<v8::Boolean>(); // not intercepted
3684 }
3685
3686 return v8::False(); // intercepted, and don't delete the property
3687}
3688
3689
3690THREADED_TEST(Deleter) {
3691 v8::HandleScope scope;
3692 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3693 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3694 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3695 LocalContext context;
3696 context->Global()->Set(v8_str("k"), obj->NewInstance());
3697 CompileRun(
3698 "k.foo = 'foo';"
3699 "k.bar = 'bar';"
3700 "k[2] = 2;"
3701 "k[4] = 4;");
3702 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3703 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3704
3705 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3706 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3707
3708 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3709 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3710
3711 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3712 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3713}
3714
3715
3716static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3717 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003718 if (name->Equals(v8_str("foo")) ||
3719 name->Equals(v8_str("bar")) ||
3720 name->Equals(v8_str("baz"))) {
3721 return v8::Undefined();
3722 }
3723 return v8::Handle<Value>();
3724}
3725
3726
3727static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3728 ApiTestFuzzer::Fuzz();
3729 if (index == 0 || index == 1) return v8::Undefined();
3730 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731}
3732
3733
3734static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3735 ApiTestFuzzer::Fuzz();
3736 v8::Handle<v8::Array> result = v8::Array::New(3);
3737 result->Set(v8::Integer::New(0), v8_str("foo"));
3738 result->Set(v8::Integer::New(1), v8_str("bar"));
3739 result->Set(v8::Integer::New(2), v8_str("baz"));
3740 return result;
3741}
3742
3743
3744static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3745 ApiTestFuzzer::Fuzz();
3746 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003747 result->Set(v8::Integer::New(0), v8_str("0"));
3748 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003749 return result;
3750}
3751
3752
3753THREADED_TEST(Enumerators) {
3754 v8::HandleScope scope;
3755 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3756 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003757 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003758 LocalContext context;
3759 context->Global()->Set(v8_str("k"), obj->NewInstance());
3760 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003761 "k[10] = 0;"
3762 "k.a = 0;"
3763 "k[5] = 0;"
3764 "k.b = 0;"
3765 "k[4294967295] = 0;"
3766 "k.c = 0;"
3767 "k[4294967296] = 0;"
3768 "k.d = 0;"
3769 "k[140000] = 0;"
3770 "k.e = 0;"
3771 "k[30000000000] = 0;"
3772 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003773 "var result = [];"
3774 "for (var prop in k) {"
3775 " result.push(prop);"
3776 "}"
3777 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003778 // Check that we get all the property names returned including the
3779 // ones from the enumerators in the right order: indexed properties
3780 // in numerical order, indexed interceptor properties, named
3781 // properties in insertion order, named interceptor properties.
3782 // This order is not mandated by the spec, so this test is just
3783 // documenting our behavior.
3784 CHECK_EQ(17, result->Length());
3785 // Indexed properties in numerical order.
3786 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3787 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3788 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3789 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3790 // Indexed interceptor properties in the order they are returned
3791 // from the enumerator interceptor.
3792 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3793 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3794 // Named properties in insertion order.
3795 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3796 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3797 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3798 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3799 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3800 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3801 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3802 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3803 // Named interceptor properties.
3804 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3805 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3806 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003807}
3808
3809
3810int p_getter_count;
3811int p_getter_count2;
3812
3813
3814static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3815 ApiTestFuzzer::Fuzz();
3816 p_getter_count++;
3817 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3818 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3819 if (name->Equals(v8_str("p1"))) {
3820 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3821 } else if (name->Equals(v8_str("p2"))) {
3822 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3823 } else if (name->Equals(v8_str("p3"))) {
3824 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3825 } else if (name->Equals(v8_str("p4"))) {
3826 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3827 }
3828 return v8::Undefined();
3829}
3830
3831
3832static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3833 ApiTestFuzzer::Fuzz();
3834 LocalContext context;
3835 context->Global()->Set(v8_str("o1"), obj->NewInstance());
3836 CompileRun(
3837 "o1.__proto__ = { };"
3838 "var o2 = { __proto__: o1 };"
3839 "var o3 = { __proto__: o2 };"
3840 "var o4 = { __proto__: o3 };"
3841 "for (var i = 0; i < 10; i++) o4.p4;"
3842 "for (var i = 0; i < 10; i++) o3.p3;"
3843 "for (var i = 0; i < 10; i++) o2.p2;"
3844 "for (var i = 0; i < 10; i++) o1.p1;");
3845}
3846
3847
3848static v8::Handle<Value> PGetter2(Local<String> name,
3849 const AccessorInfo& info) {
3850 ApiTestFuzzer::Fuzz();
3851 p_getter_count2++;
3852 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3853 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3854 if (name->Equals(v8_str("p1"))) {
3855 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3856 } else if (name->Equals(v8_str("p2"))) {
3857 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3858 } else if (name->Equals(v8_str("p3"))) {
3859 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3860 } else if (name->Equals(v8_str("p4"))) {
3861 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3862 }
3863 return v8::Undefined();
3864}
3865
3866
3867THREADED_TEST(GetterHolders) {
3868 v8::HandleScope scope;
3869 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3870 obj->SetAccessor(v8_str("p1"), PGetter);
3871 obj->SetAccessor(v8_str("p2"), PGetter);
3872 obj->SetAccessor(v8_str("p3"), PGetter);
3873 obj->SetAccessor(v8_str("p4"), PGetter);
3874 p_getter_count = 0;
3875 RunHolderTest(obj);
3876 CHECK_EQ(40, p_getter_count);
3877}
3878
3879
3880THREADED_TEST(PreInterceptorHolders) {
3881 v8::HandleScope scope;
3882 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3883 obj->SetNamedPropertyHandler(PGetter2);
3884 p_getter_count2 = 0;
3885 RunHolderTest(obj);
3886 CHECK_EQ(40, p_getter_count2);
3887}
3888
3889
3890THREADED_TEST(ObjectInstantiation) {
3891 v8::HandleScope scope;
3892 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3893 templ->SetAccessor(v8_str("t"), PGetter2);
3894 LocalContext context;
3895 context->Global()->Set(v8_str("o"), templ->NewInstance());
3896 for (int i = 0; i < 100; i++) {
3897 v8::HandleScope inner_scope;
3898 v8::Handle<v8::Object> obj = templ->NewInstance();
3899 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3900 context->Global()->Set(v8_str("o2"), obj);
3901 v8::Handle<Value> value =
3902 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3903 CHECK_EQ(v8::True(), value);
3904 context->Global()->Set(v8_str("o"), obj);
3905 }
3906}
3907
3908
3909THREADED_TEST(StringWrite) {
3910 v8::HandleScope scope;
3911 v8::Handle<String> str = v8_str("abcde");
3912
3913 char buf[100];
3914 int len;
3915
3916 memset(buf, 0x1, sizeof(buf));
3917 len = str->WriteAscii(buf);
3918 CHECK_EQ(len, 5);
3919 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3920
3921 memset(buf, 0x1, sizeof(buf));
3922 len = str->WriteAscii(buf, 0, 4);
3923 CHECK_EQ(len, 4);
3924 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3925
3926 memset(buf, 0x1, sizeof(buf));
3927 len = str->WriteAscii(buf, 0, 5);
3928 CHECK_EQ(len, 5);
3929 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3930
3931 memset(buf, 0x1, sizeof(buf));
3932 len = str->WriteAscii(buf, 0, 6);
3933 CHECK_EQ(len, 5);
3934 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3935
3936 memset(buf, 0x1, sizeof(buf));
3937 len = str->WriteAscii(buf, 4, -1);
3938 CHECK_EQ(len, 1);
3939 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3940
3941 memset(buf, 0x1, sizeof(buf));
3942 len = str->WriteAscii(buf, 4, 6);
3943 CHECK_EQ(len, 1);
3944 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3945
3946 memset(buf, 0x1, sizeof(buf));
3947 len = str->WriteAscii(buf, 4, 1);
3948 CHECK_EQ(len, 1);
3949 CHECK_EQ(strncmp("e\1", buf, 2), 0);
3950}
3951
3952
3953THREADED_TEST(ToArrayIndex) {
3954 v8::HandleScope scope;
3955 LocalContext context;
3956
3957 v8::Handle<String> str = v8_str("42");
3958 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3959 CHECK(!index.IsEmpty());
3960 CHECK_EQ(42.0, index->Uint32Value());
3961 str = v8_str("42asdf");
3962 index = str->ToArrayIndex();
3963 CHECK(index.IsEmpty());
3964 str = v8_str("-42");
3965 index = str->ToArrayIndex();
3966 CHECK(index.IsEmpty());
3967 str = v8_str("4294967295");
3968 index = str->ToArrayIndex();
3969 CHECK(!index.IsEmpty());
3970 CHECK_EQ(4294967295.0, index->Uint32Value());
3971 v8::Handle<v8::Number> num = v8::Number::New(1);
3972 index = num->ToArrayIndex();
3973 CHECK(!index.IsEmpty());
3974 CHECK_EQ(1.0, index->Uint32Value());
3975 num = v8::Number::New(-1);
3976 index = num->ToArrayIndex();
3977 CHECK(index.IsEmpty());
3978 v8::Handle<v8::Object> obj = v8::Object::New();
3979 index = obj->ToArrayIndex();
3980 CHECK(index.IsEmpty());
3981}
3982
3983
3984THREADED_TEST(ErrorConstruction) {
3985 v8::HandleScope scope;
3986 LocalContext context;
3987
3988 v8::Handle<String> foo = v8_str("foo");
3989 v8::Handle<String> message = v8_str("message");
3990 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3991 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003992 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
3993 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003994 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3995 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003996 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003997 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
3998 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003999 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004000 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4001 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004002 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004003 v8::Handle<Value> error = v8::Exception::Error(foo);
4004 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004005 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004006}
4007
4008
4009static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4010 ApiTestFuzzer::Fuzz();
4011 return v8_num(10);
4012}
4013
4014
4015static void YSetter(Local<String> name,
4016 Local<Value> value,
4017 const AccessorInfo& info) {
4018 if (info.This()->Has(name)) {
4019 info.This()->Delete(name);
4020 }
4021 info.This()->Set(name, value);
4022}
4023
4024
4025THREADED_TEST(DeleteAccessor) {
4026 v8::HandleScope scope;
4027 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4028 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4029 LocalContext context;
4030 v8::Handle<v8::Object> holder = obj->NewInstance();
4031 context->Global()->Set(v8_str("holder"), holder);
4032 v8::Handle<Value> result = CompileRun(
4033 "holder.y = 11; holder.y = 12; holder.y");
4034 CHECK_EQ(12, result->Uint32Value());
4035}
4036
4037
4038THREADED_TEST(TypeSwitch) {
4039 v8::HandleScope scope;
4040 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4041 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4042 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4043 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4044 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4045 LocalContext context;
4046 v8::Handle<v8::Object> obj0 = v8::Object::New();
4047 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4048 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4049 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4050 for (int i = 0; i < 10; i++) {
4051 CHECK_EQ(0, type_switch->match(obj0));
4052 CHECK_EQ(1, type_switch->match(obj1));
4053 CHECK_EQ(2, type_switch->match(obj2));
4054 CHECK_EQ(3, type_switch->match(obj3));
4055 CHECK_EQ(3, type_switch->match(obj3));
4056 CHECK_EQ(2, type_switch->match(obj2));
4057 CHECK_EQ(1, type_switch->match(obj1));
4058 CHECK_EQ(0, type_switch->match(obj0));
4059 }
4060}
4061
4062
4063// For use within the TestSecurityHandler() test.
4064static bool g_security_callback_result = false;
4065static bool NamedSecurityTestCallback(Local<v8::Object> global,
4066 Local<Value> name,
4067 v8::AccessType type,
4068 Local<Value> data) {
4069 // Always allow read access.
4070 if (type == v8::ACCESS_GET)
4071 return true;
4072
4073 // Sometimes allow other access.
4074 return g_security_callback_result;
4075}
4076
4077
4078static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4079 uint32_t key,
4080 v8::AccessType type,
4081 Local<Value> data) {
4082 // Always allow read access.
4083 if (type == v8::ACCESS_GET)
4084 return true;
4085
4086 // Sometimes allow other access.
4087 return g_security_callback_result;
4088}
4089
4090
4091static int trouble_nesting = 0;
4092static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4093 ApiTestFuzzer::Fuzz();
4094 trouble_nesting++;
4095
4096 // Call a JS function that throws an uncaught exception.
4097 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4098 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4099 arg_this->Get(v8_str("trouble_callee")) :
4100 arg_this->Get(v8_str("trouble_caller"));
4101 CHECK(trouble_callee->IsFunction());
4102 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4103}
4104
4105
4106static int report_count = 0;
4107static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4108 v8::Handle<Value>) {
4109 report_count++;
4110}
4111
4112
4113// Counts uncaught exceptions, but other tests running in parallel
4114// also have uncaught exceptions.
4115TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00004116 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004117 v8::HandleScope scope;
4118 LocalContext env;
4119 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4120
4121 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4122 v8::Local<v8::Object> global = env->Global();
4123 global->Set(v8_str("trouble"), fun->GetFunction());
4124
4125 Script::Compile(v8_str("function trouble_callee() {"
4126 " var x = null;"
4127 " return x.foo;"
4128 "};"
4129 "function trouble_caller() {"
4130 " trouble();"
4131 "};"))->Run();
4132 Local<Value> trouble = global->Get(v8_str("trouble"));
4133 CHECK(trouble->IsFunction());
4134 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4135 CHECK(trouble_callee->IsFunction());
4136 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4137 CHECK(trouble_caller->IsFunction());
4138 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4139 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004140 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4141}
4142
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004143static const char* script_resource_name = "ExceptionInNativeScript.js";
4144static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4145 v8::Handle<Value>) {
4146 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4147 CHECK(!name_val.IsEmpty() && name_val->IsString());
4148 v8::String::AsciiValue name(message->GetScriptResourceName());
4149 CHECK_EQ(script_resource_name, *name);
4150 CHECK_EQ(3, message->GetLineNumber());
4151 v8::String::AsciiValue source_line(message->GetSourceLine());
4152 CHECK_EQ(" new o.foo();", *source_line);
4153}
4154
4155TEST(ExceptionInNativeScript) {
4156 v8::HandleScope scope;
4157 LocalContext env;
4158 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4159
4160 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4161 v8::Local<v8::Object> global = env->Global();
4162 global->Set(v8_str("trouble"), fun->GetFunction());
4163
4164 Script::Compile(v8_str("function trouble() {\n"
4165 " var o = {};\n"
4166 " new o.foo();\n"
4167 "};"), v8::String::New(script_resource_name))->Run();
4168 Local<Value> trouble = global->Get(v8_str("trouble"));
4169 CHECK(trouble->IsFunction());
4170 Function::Cast(*trouble)->Call(global, 0, NULL);
4171 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4172}
4173
ager@chromium.org8bb60582008-12-11 12:02:20 +00004174
4175TEST(CompilationErrorUsingTryCatchHandler) {
4176 v8::HandleScope scope;
4177 LocalContext env;
4178 v8::TryCatch try_catch;
4179 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4180 CHECK_NE(NULL, *try_catch.Exception());
4181 CHECK(try_catch.HasCaught());
4182}
4183
4184
4185TEST(TryCatchFinallyUsingTryCatchHandler) {
4186 v8::HandleScope scope;
4187 LocalContext env;
4188 v8::TryCatch try_catch;
4189 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4190 CHECK(!try_catch.HasCaught());
4191 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4192 CHECK(try_catch.HasCaught());
4193 try_catch.Reset();
4194 Script::Compile(v8_str("(function() {"
4195 "try { throw ''; } finally { return; }"
4196 "})()"))->Run();
4197 CHECK(!try_catch.HasCaught());
4198 Script::Compile(v8_str("(function()"
4199 " { try { throw ''; } finally { throw 0; }"
4200 "})()"))->Run();
4201 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202}
4203
4204
4205// SecurityHandler can't be run twice
4206TEST(SecurityHandler) {
4207 v8::HandleScope scope0;
4208 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4209 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4210 IndexedSecurityTestCallback);
4211 // Create an environment
4212 v8::Persistent<Context> context0 =
4213 Context::New(NULL, global_template);
4214 context0->Enter();
4215
4216 v8::Handle<v8::Object> global0 = context0->Global();
4217 v8::Handle<Script> script0 = v8_compile("foo = 111");
4218 script0->Run();
4219 global0->Set(v8_str("0"), v8_num(999));
4220 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4221 CHECK_EQ(111, foo0->Int32Value());
4222 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4223 CHECK_EQ(999, z0->Int32Value());
4224
4225 // Create another environment, should fail security checks.
4226 v8::HandleScope scope1;
4227
4228 v8::Persistent<Context> context1 =
4229 Context::New(NULL, global_template);
4230 context1->Enter();
4231
4232 v8::Handle<v8::Object> global1 = context1->Global();
4233 global1->Set(v8_str("othercontext"), global0);
4234 // This set will fail the security check.
4235 v8::Handle<Script> script1 =
4236 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4237 script1->Run();
4238 // This read will pass the security check.
4239 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4240 CHECK_EQ(111, foo1->Int32Value());
4241 // This read will pass the security check.
4242 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4243 CHECK_EQ(999, z1->Int32Value());
4244
4245 // Create another environment, should pass security checks.
4246 { g_security_callback_result = true; // allow security handler to pass.
4247 v8::HandleScope scope2;
4248 LocalContext context2;
4249 v8::Handle<v8::Object> global2 = context2->Global();
4250 global2->Set(v8_str("othercontext"), global0);
4251 v8::Handle<Script> script2 =
4252 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4253 script2->Run();
4254 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4255 CHECK_EQ(333, foo2->Int32Value());
4256 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4257 CHECK_EQ(888, z2->Int32Value());
4258 }
4259
4260 context1->Exit();
4261 context1.Dispose();
4262
4263 context0->Exit();
4264 context0.Dispose();
4265}
4266
4267
4268THREADED_TEST(SecurityChecks) {
4269 v8::HandleScope handle_scope;
4270 LocalContext env1;
4271 v8::Persistent<Context> env2 = Context::New();
4272
4273 Local<Value> foo = v8_str("foo");
4274 Local<Value> bar = v8_str("bar");
4275
4276 // Set to the same domain.
4277 env1->SetSecurityToken(foo);
4278
4279 // Create a function in env1.
4280 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4281 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4282 CHECK(spy->IsFunction());
4283
4284 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004286 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4287 CHECK(spy2->IsFunction());
4288
4289 // Switch to env2 in the same domain and invoke spy on env2.
4290 {
4291 env2->SetSecurityToken(foo);
4292 // Enter env2
4293 Context::Scope scope_env2(env2);
4294 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4295 CHECK(result->IsFunction());
4296 }
4297
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004298 {
4299 env2->SetSecurityToken(bar);
4300 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004301
4302 // Call cross_domain_call, it should throw an exception
4303 v8::TryCatch try_catch;
4304 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4305 CHECK(try_catch.HasCaught());
4306 }
4307
4308 env2.Dispose();
4309}
4310
4311
4312// Regression test case for issue 1183439.
4313THREADED_TEST(SecurityChecksForPrototypeChain) {
4314 v8::HandleScope scope;
4315 LocalContext current;
4316 v8::Persistent<Context> other = Context::New();
4317
4318 // Change context to be able to get to the Object function in the
4319 // other context without hitting the security checks.
4320 v8::Local<Value> other_object;
4321 { Context::Scope scope(other);
4322 other_object = other->Global()->Get(v8_str("Object"));
4323 other->Global()->Set(v8_num(42), v8_num(87));
4324 }
4325
4326 current->Global()->Set(v8_str("other"), other->Global());
4327 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4328
4329 // Make sure the security check fails here and we get an undefined
4330 // result instead of getting the Object function. Repeat in a loop
4331 // to make sure to exercise the IC code.
4332 v8::Local<Script> access_other0 = v8_compile("other.Object");
4333 v8::Local<Script> access_other1 = v8_compile("other[42]");
4334 for (int i = 0; i < 5; i++) {
4335 CHECK(!access_other0->Run()->Equals(other_object));
4336 CHECK(access_other0->Run()->IsUndefined());
4337 CHECK(!access_other1->Run()->Equals(v8_num(87)));
4338 CHECK(access_other1->Run()->IsUndefined());
4339 }
4340
4341 // Create an object that has 'other' in its prototype chain and make
4342 // sure we cannot access the Object function indirectly through
4343 // that. Repeat in a loop to make sure to exercise the IC code.
4344 v8_compile("function F() { };"
4345 "F.prototype = other;"
4346 "var f = new F();")->Run();
4347 v8::Local<Script> access_f0 = v8_compile("f.Object");
4348 v8::Local<Script> access_f1 = v8_compile("f[42]");
4349 for (int j = 0; j < 5; j++) {
4350 CHECK(!access_f0->Run()->Equals(other_object));
4351 CHECK(access_f0->Run()->IsUndefined());
4352 CHECK(!access_f1->Run()->Equals(v8_num(87)));
4353 CHECK(access_f1->Run()->IsUndefined());
4354 }
4355
4356 // Now it gets hairy: Set the prototype for the other global object
4357 // to be the current global object. The prototype chain for 'f' now
4358 // goes through 'other' but ends up in the current global object.
4359 { Context::Scope scope(other);
4360 other->Global()->Set(v8_str("__proto__"), current->Global());
4361 }
4362 // Set a named and an index property on the current global
4363 // object. To force the lookup to go through the other global object,
4364 // the properties must not exist in the other global object.
4365 current->Global()->Set(v8_str("foo"), v8_num(100));
4366 current->Global()->Set(v8_num(99), v8_num(101));
4367 // Try to read the properties from f and make sure that the access
4368 // gets stopped by the security checks on the other global object.
4369 Local<Script> access_f2 = v8_compile("f.foo");
4370 Local<Script> access_f3 = v8_compile("f[99]");
4371 for (int k = 0; k < 5; k++) {
4372 CHECK(!access_f2->Run()->Equals(v8_num(100)));
4373 CHECK(access_f2->Run()->IsUndefined());
4374 CHECK(!access_f3->Run()->Equals(v8_num(101)));
4375 CHECK(access_f3->Run()->IsUndefined());
4376 }
4377 other.Dispose();
4378}
4379
4380
4381THREADED_TEST(CrossDomainDelete) {
4382 v8::HandleScope handle_scope;
4383 LocalContext env1;
4384 v8::Persistent<Context> env2 = Context::New();
4385
4386 Local<Value> foo = v8_str("foo");
4387 Local<Value> bar = v8_str("bar");
4388
4389 // Set to the same domain.
4390 env1->SetSecurityToken(foo);
4391 env2->SetSecurityToken(foo);
4392
4393 env1->Global()->Set(v8_str("prop"), v8_num(3));
4394 env2->Global()->Set(v8_str("env1"), env1->Global());
4395
4396 // Change env2 to a different domain and delete env1.prop.
4397 env2->SetSecurityToken(bar);
4398 {
4399 Context::Scope scope_env2(env2);
4400 Local<Value> result =
4401 Script::Compile(v8_str("delete env1.prop"))->Run();
4402 CHECK(result->IsFalse());
4403 }
4404
4405 // Check that env1.prop still exists.
4406 Local<Value> v = env1->Global()->Get(v8_str("prop"));
4407 CHECK(v->IsNumber());
4408 CHECK_EQ(3, v->Int32Value());
4409
4410 env2.Dispose();
4411}
4412
4413
ager@chromium.org870a0b62008-11-04 11:43:05 +00004414THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4415 v8::HandleScope handle_scope;
4416 LocalContext env1;
4417 v8::Persistent<Context> env2 = Context::New();
4418
4419 Local<Value> foo = v8_str("foo");
4420 Local<Value> bar = v8_str("bar");
4421
4422 // Set to the same domain.
4423 env1->SetSecurityToken(foo);
4424 env2->SetSecurityToken(foo);
4425
4426 env1->Global()->Set(v8_str("prop"), v8_num(3));
4427 env2->Global()->Set(v8_str("env1"), env1->Global());
4428
4429 // env1.prop is enumerable in env2.
4430 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4431 {
4432 Context::Scope scope_env2(env2);
4433 Local<Value> result = Script::Compile(test)->Run();
4434 CHECK(result->IsTrue());
4435 }
4436
4437 // Change env2 to a different domain and test again.
4438 env2->SetSecurityToken(bar);
4439 {
4440 Context::Scope scope_env2(env2);
4441 Local<Value> result = Script::Compile(test)->Run();
4442 CHECK(result->IsFalse());
4443 }
4444
4445 env2.Dispose();
4446}
4447
4448
ager@chromium.org236ad962008-09-25 09:45:57 +00004449THREADED_TEST(CrossDomainForIn) {
4450 v8::HandleScope handle_scope;
4451 LocalContext env1;
4452 v8::Persistent<Context> env2 = Context::New();
4453
4454 Local<Value> foo = v8_str("foo");
4455 Local<Value> bar = v8_str("bar");
4456
4457 // Set to the same domain.
4458 env1->SetSecurityToken(foo);
4459 env2->SetSecurityToken(foo);
4460
4461 env1->Global()->Set(v8_str("prop"), v8_num(3));
4462 env2->Global()->Set(v8_str("env1"), env1->Global());
4463
4464 // Change env2 to a different domain and set env1's global object
4465 // as the __proto__ of an object in env2 and enumerate properties
4466 // in for-in. It shouldn't enumerate properties on env1's global
4467 // object.
4468 env2->SetSecurityToken(bar);
4469 {
4470 Context::Scope scope_env2(env2);
4471 Local<Value> result =
4472 CompileRun("(function(){var obj = {'__proto__':env1};"
4473 "for (var p in obj)"
4474 " if (p == 'prop') return false;"
4475 "return true;})()");
4476 CHECK(result->IsTrue());
4477 }
4478 env2.Dispose();
4479}
4480
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004482TEST(ContextDetachGlobal) {
4483 v8::HandleScope handle_scope;
4484 LocalContext env1;
4485 v8::Persistent<Context> env2 = Context::New();
4486
4487 Local<v8::Object> global1 = env1->Global();
4488
4489 Local<Value> foo = v8_str("foo");
4490
4491 // Set to the same domain.
4492 env1->SetSecurityToken(foo);
4493 env2->SetSecurityToken(foo);
4494
4495 // Enter env2
4496 env2->Enter();
4497
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00004498 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004499 Local<v8::Object> global2 = env2->Global();
4500 global2->Set(v8_str("prop"), v8::Integer::New(1));
4501 CompileRun("function getProp() {return prop;}");
4502
4503 env1->Global()->Set(v8_str("getProp"),
4504 global2->Get(v8_str("getProp")));
4505
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00004506 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004507 env2->Exit();
4508 env2->DetachGlobal();
4509 // env2 has a new global object.
4510 CHECK(!env2->Global()->Equals(global2));
4511
4512 v8::Persistent<Context> env3 =
4513 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4514 env3->SetSecurityToken(v8_str("bar"));
4515 env3->Enter();
4516
4517 Local<v8::Object> global3 = env3->Global();
4518 CHECK_EQ(global2, global3);
4519 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4520 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4521 global3->Set(v8_str("prop"), v8::Integer::New(-1));
4522 global3->Set(v8_str("prop2"), v8::Integer::New(2));
4523 env3->Exit();
4524
4525 // Call getProp in env1, and it should return the value 1
4526 {
4527 Local<Value> get_prop = global1->Get(v8_str("getProp"));
4528 CHECK(get_prop->IsFunction());
4529 v8::TryCatch try_catch;
4530 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4531 CHECK(!try_catch.HasCaught());
4532 CHECK_EQ(1, r->Int32Value());
4533 }
4534
4535 // Check that env3 is not accessible from env1
4536 {
4537 Local<Value> r = global3->Get(v8_str("prop2"));
4538 CHECK(r->IsUndefined());
4539 }
4540
4541 env2.Dispose();
4542 env3.Dispose();
4543}
4544
4545
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00004546TEST(DetachAndReattachGlobal) {
4547 v8::HandleScope scope;
4548 LocalContext env1;
4549
4550 // Create second environment.
4551 v8::Persistent<Context> env2 = Context::New();
4552
4553 Local<Value> foo = v8_str("foo");
4554
4555 // Set same security token for env1 and env2.
4556 env1->SetSecurityToken(foo);
4557 env2->SetSecurityToken(foo);
4558
4559 // Create a property on the global object in env2.
4560 {
4561 v8::Context::Scope scope(env2);
4562 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4563 }
4564
4565 // Create a reference to env2 global from env1 global.
4566 env1->Global()->Set(v8_str("other"), env2->Global());
4567
4568 // Check that we have access to other.p in env2 from env1.
4569 Local<Value> result = CompileRun("other.p");
4570 CHECK(result->IsInt32());
4571 CHECK_EQ(42, result->Int32Value());
4572
4573 // Hold on to global from env2 and detach global from env2.
4574 Local<v8::Object> global2 = env2->Global();
4575 env2->DetachGlobal();
4576
4577 // Check that the global has been detached. No other.p property can
4578 // be found.
4579 result = CompileRun("other.p");
4580 CHECK(result->IsUndefined());
4581
4582 // Reuse global2 for env3.
4583 v8::Persistent<Context> env3 =
4584 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4585 CHECK_EQ(global2, env3->Global());
4586
4587 // Start by using the same security token for env3 as for env1 and env2.
4588 env3->SetSecurityToken(foo);
4589
4590 // Create a property on the global object in env3.
4591 {
4592 v8::Context::Scope scope(env3);
4593 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4594 }
4595
4596 // Check that other.p is now the property in env3 and that we have access.
4597 result = CompileRun("other.p");
4598 CHECK(result->IsInt32());
4599 CHECK_EQ(24, result->Int32Value());
4600
4601 // Change security token for env3 to something different from env1 and env2.
4602 env3->SetSecurityToken(v8_str("bar"));
4603
4604 // Check that we do not have access to other.p in env1. |other| is now
4605 // the global object for env3 which has a different security token,
4606 // so access should be blocked.
4607 result = CompileRun("other.p");
4608 CHECK(result->IsUndefined());
4609
4610 // Detach the global for env3 and reattach it to env2.
4611 env3->DetachGlobal();
4612 env2->ReattachGlobal(global2);
4613
4614 // Check that we have access to other.p again in env1. |other| is now
4615 // the global object for env2 which has the same security token as env1.
4616 result = CompileRun("other.p");
4617 CHECK(result->IsInt32());
4618 CHECK_EQ(42, result->Int32Value());
4619
4620 env2.Dispose();
4621 env3.Dispose();
4622}
4623
4624
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004625static bool NamedAccessBlocker(Local<v8::Object> global,
4626 Local<Value> name,
4627 v8::AccessType type,
4628 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004629 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004630}
4631
4632
4633static bool IndexedAccessBlocker(Local<v8::Object> global,
4634 uint32_t key,
4635 v8::AccessType type,
4636 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004637 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004638}
4639
4640
4641static int g_echo_value = -1;
4642static v8::Handle<Value> EchoGetter(Local<String> name,
4643 const AccessorInfo& info) {
4644 return v8_num(g_echo_value);
4645}
4646
4647
4648static void EchoSetter(Local<String> name,
4649 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004650 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004651 if (value->IsNumber())
4652 g_echo_value = value->Int32Value();
4653}
4654
4655
4656static v8::Handle<Value> UnreachableGetter(Local<String> name,
4657 const AccessorInfo& info) {
4658 CHECK(false); // This function should not be called..
4659 return v8::Undefined();
4660}
4661
4662
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004663static void UnreachableSetter(Local<String>, Local<Value>,
4664 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004665 CHECK(false); // This function should nto be called.
4666}
4667
4668
4669THREADED_TEST(AccessControl) {
4670 v8::HandleScope handle_scope;
4671 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4672
4673 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4674 IndexedAccessBlocker);
4675
4676 // Add an accessor accessible by cross-domain JS code.
4677 global_template->SetAccessor(
4678 v8_str("accessible_prop"),
4679 EchoGetter, EchoSetter,
4680 v8::Handle<Value>(),
4681 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4682
4683 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004684 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004685 UnreachableGetter, UnreachableSetter,
4686 v8::Handle<Value>(),
4687 v8::DEFAULT);
4688
4689 // Create an environment
4690 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4691 context0->Enter();
4692
4693 v8::Handle<v8::Object> global0 = context0->Global();
4694
4695 v8::HandleScope scope1;
4696
4697 v8::Persistent<Context> context1 = Context::New();
4698 context1->Enter();
4699
4700 v8::Handle<v8::Object> global1 = context1->Global();
4701 global1->Set(v8_str("other"), global0);
4702
4703 v8::Handle<Value> value;
4704
4705 // Access blocked property
4706 value = v8_compile("other.blocked_prop = 1")->Run();
4707 value = v8_compile("other.blocked_prop")->Run();
4708 CHECK(value->IsUndefined());
4709
ager@chromium.org870a0b62008-11-04 11:43:05 +00004710 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4711 CHECK(value->IsFalse());
4712
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004713 // Access accessible property
4714 value = v8_compile("other.accessible_prop = 3")->Run();
4715 CHECK(value->IsNumber());
4716 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004717 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004718
4719 value = v8_compile("other.accessible_prop")->Run();
4720 CHECK(value->IsNumber());
4721 CHECK_EQ(3, value->Int32Value());
4722
ager@chromium.org870a0b62008-11-04 11:43:05 +00004723 value =
4724 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4725 CHECK(value->IsTrue());
4726
4727 // Enumeration doesn't enumerate accessors from inaccessible objects in
4728 // the prototype chain even if the accessors are in themselves accessible.
4729 Local<Value> result =
4730 CompileRun("(function(){var obj = {'__proto__':other};"
4731 "for (var p in obj)"
4732 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
4733 " return false;"
4734 " }"
4735 "return true;})()");
4736 CHECK(result->IsTrue());
4737
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004738 context1->Exit();
4739 context0->Exit();
4740 context1.Dispose();
4741 context0.Dispose();
4742}
4743
4744
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004745static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4746 Local<Value> name,
4747 v8::AccessType type,
4748 Local<Value> data) {
4749 return false;
4750}
4751
4752
4753static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4754 uint32_t key,
4755 v8::AccessType type,
4756 Local<Value> data) {
4757 return false;
4758}
4759
4760
4761THREADED_TEST(AccessControlGetOwnPropertyNames) {
4762 v8::HandleScope handle_scope;
4763 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4764
4765 obj_template->Set(v8_str("x"), v8::Integer::New(42));
4766 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
4767 GetOwnPropertyNamesIndexedBlocker);
4768
4769 // Create an environment
4770 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
4771 context0->Enter();
4772
4773 v8::Handle<v8::Object> global0 = context0->Global();
4774
4775 v8::HandleScope scope1;
4776
4777 v8::Persistent<Context> context1 = Context::New();
4778 context1->Enter();
4779
4780 v8::Handle<v8::Object> global1 = context1->Global();
4781 global1->Set(v8_str("other"), global0);
4782 global1->Set(v8_str("object"), obj_template->NewInstance());
4783
4784 v8::Handle<Value> value;
4785
4786 // Attempt to get the property names of the other global object and
4787 // of an object that requires access checks. Accessing the other
4788 // global object should be blocked by access checks on the global
4789 // proxy object. Accessing the object that requires access checks
4790 // is blocked by the access checks on the object itself.
4791 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
4792 CHECK(value->IsTrue());
4793
4794 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
4795 CHECK(value->IsTrue());
4796
4797 context1->Exit();
4798 context0->Exit();
4799 context1.Dispose();
4800 context0.Dispose();
4801}
4802
4803
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004804static v8::Handle<Value> ConstTenGetter(Local<String> name,
4805 const AccessorInfo& info) {
4806 return v8_num(10);
4807}
4808
4809
4810THREADED_TEST(CrossDomainAccessors) {
4811 v8::HandleScope handle_scope;
4812
4813 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4814
4815 v8::Handle<v8::ObjectTemplate> global_template =
4816 func_template->InstanceTemplate();
4817
4818 v8::Handle<v8::ObjectTemplate> proto_template =
4819 func_template->PrototypeTemplate();
4820
4821 // Add an accessor to proto that's accessible by cross-domain JS code.
4822 proto_template->SetAccessor(v8_str("accessible"),
4823 ConstTenGetter, 0,
4824 v8::Handle<Value>(),
4825 v8::ALL_CAN_READ);
4826
4827 // Add an accessor that is not accessible by cross-domain JS code.
4828 global_template->SetAccessor(v8_str("unreachable"),
4829 UnreachableGetter, 0,
4830 v8::Handle<Value>(),
4831 v8::DEFAULT);
4832
4833 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4834 context0->Enter();
4835
4836 Local<v8::Object> global = context0->Global();
4837 // Add a normal property that shadows 'accessible'
4838 global->Set(v8_str("accessible"), v8_num(11));
4839
4840 // Enter a new context.
4841 v8::HandleScope scope1;
4842 v8::Persistent<Context> context1 = Context::New();
4843 context1->Enter();
4844
4845 v8::Handle<v8::Object> global1 = context1->Global();
4846 global1->Set(v8_str("other"), global);
4847
4848 // Should return 10, instead of 11
4849 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4850 CHECK(value->IsNumber());
4851 CHECK_EQ(10, value->Int32Value());
4852
4853 value = v8_compile("other.unreachable")->Run();
4854 CHECK(value->IsUndefined());
4855
4856 context1->Exit();
4857 context0->Exit();
4858 context1.Dispose();
4859 context0.Dispose();
4860}
4861
4862
4863static int named_access_count = 0;
4864static int indexed_access_count = 0;
4865
4866static bool NamedAccessCounter(Local<v8::Object> global,
4867 Local<Value> name,
4868 v8::AccessType type,
4869 Local<Value> data) {
4870 named_access_count++;
4871 return true;
4872}
4873
4874
4875static bool IndexedAccessCounter(Local<v8::Object> global,
4876 uint32_t key,
4877 v8::AccessType type,
4878 Local<Value> data) {
4879 indexed_access_count++;
4880 return true;
4881}
4882
4883
4884// This one is too easily disturbed by other tests.
4885TEST(AccessControlIC) {
4886 named_access_count = 0;
4887 indexed_access_count = 0;
4888
4889 v8::HandleScope handle_scope;
4890
4891 // Create an environment.
4892 v8::Persistent<Context> context0 = Context::New();
4893 context0->Enter();
4894
4895 // Create an object that requires access-check functions to be
4896 // called for cross-domain access.
4897 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4898 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4899 IndexedAccessCounter);
4900 Local<v8::Object> object = object_template->NewInstance();
4901
4902 v8::HandleScope scope1;
4903
4904 // Create another environment.
4905 v8::Persistent<Context> context1 = Context::New();
4906 context1->Enter();
4907
4908 // Make easy access to the object from the other environment.
4909 v8::Handle<v8::Object> global1 = context1->Global();
4910 global1->Set(v8_str("obj"), object);
4911
4912 v8::Handle<Value> value;
4913
4914 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004915 CompileRun("function testProp(obj) {"
4916 " for (var i = 0; i < 10; i++) obj.prop = 1;"
4917 " for (var j = 0; j < 10; j++) obj.prop;"
4918 " return obj.prop"
4919 "}");
4920 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004921 CHECK(value->IsNumber());
4922 CHECK_EQ(1, value->Int32Value());
4923 CHECK_EQ(21, named_access_count);
4924
4925 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004926 CompileRun("var p = 'prop';"
4927 "function testKeyed(obj) {"
4928 " for (var i = 0; i < 10; i++) obj[p] = 1;"
4929 " for (var j = 0; j < 10; j++) obj[p];"
4930 " return obj[p];"
4931 "}");
4932 // Use obj which requires access checks. No inline caching is used
4933 // in that case.
4934 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004935 CHECK(value->IsNumber());
4936 CHECK_EQ(1, value->Int32Value());
4937 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004938 // Force the inline caches into generic state and try again.
4939 CompileRun("testKeyed({ a: 0 })");
4940 CompileRun("testKeyed({ b: 0 })");
4941 value = CompileRun("testKeyed(obj)");
4942 CHECK(value->IsNumber());
4943 CHECK_EQ(1, value->Int32Value());
4944 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004945
4946 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004947 CompileRun("function testIndexed(obj) {"
4948 " for (var i = 0; i < 10; i++) obj[0] = 1;"
4949 " for (var j = 0; j < 10; j++) obj[0];"
4950 " return obj[0]"
4951 "}");
4952 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004953 CHECK(value->IsNumber());
4954 CHECK_EQ(1, value->Int32Value());
4955 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004956 // Force the inline caches into generic state.
4957 CompileRun("testIndexed(new Array(1))");
4958 // Test that the indexed access check is called.
4959 value = CompileRun("testIndexed(obj)");
4960 CHECK(value->IsNumber());
4961 CHECK_EQ(1, value->Int32Value());
4962 CHECK_EQ(42, indexed_access_count);
4963
4964 // Check that the named access check is called when invoking
4965 // functions on an object that requires access checks.
4966 CompileRun("obj.f = function() {}");
4967 CompileRun("function testCallNormal(obj) {"
4968 " for (var i = 0; i < 10; i++) obj.f();"
4969 "}");
4970 CompileRun("testCallNormal(obj)");
4971 CHECK_EQ(74, named_access_count);
4972
4973 // Force obj into slow case.
4974 value = CompileRun("delete obj.prop");
4975 CHECK(value->BooleanValue());
4976 // Force inline caches into dictionary probing mode.
4977 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4978 // Test that the named access check is called.
4979 value = CompileRun("testProp(obj);");
4980 CHECK(value->IsNumber());
4981 CHECK_EQ(1, value->Int32Value());
4982 CHECK_EQ(96, named_access_count);
4983
4984 // Force the call inline cache into dictionary probing mode.
4985 CompileRun("o.f = function() {}; testCallNormal(o)");
4986 // Test that the named access check is still called for each
4987 // invocation of the function.
4988 value = CompileRun("testCallNormal(obj)");
4989 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004990
4991 context1->Exit();
4992 context0->Exit();
4993 context1.Dispose();
4994 context0.Dispose();
4995}
4996
4997
4998static bool NamedAccessFlatten(Local<v8::Object> global,
4999 Local<Value> name,
5000 v8::AccessType type,
5001 Local<Value> data) {
5002 char buf[100];
5003 int len;
5004
5005 CHECK(name->IsString());
5006
5007 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005008 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005009 CHECK_EQ(4, len);
5010
5011 uint16_t buf2[100];
5012
5013 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005014 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005015 CHECK_EQ(4, len);
5016
5017 return true;
5018}
5019
5020
5021static bool IndexedAccessFlatten(Local<v8::Object> global,
5022 uint32_t key,
5023 v8::AccessType type,
5024 Local<Value> data) {
5025 return true;
5026}
5027
5028
5029// Regression test. In access checks, operations that may cause
5030// garbage collection are not allowed. It used to be the case that
5031// using the Write operation on a string could cause a garbage
5032// collection due to flattening of the string. This is no longer the
5033// case.
5034THREADED_TEST(AccessControlFlatten) {
5035 named_access_count = 0;
5036 indexed_access_count = 0;
5037
5038 v8::HandleScope handle_scope;
5039
5040 // Create an environment.
5041 v8::Persistent<Context> context0 = Context::New();
5042 context0->Enter();
5043
5044 // Create an object that requires access-check functions to be
5045 // called for cross-domain access.
5046 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5047 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5048 IndexedAccessFlatten);
5049 Local<v8::Object> object = object_template->NewInstance();
5050
5051 v8::HandleScope scope1;
5052
5053 // Create another environment.
5054 v8::Persistent<Context> context1 = Context::New();
5055 context1->Enter();
5056
5057 // Make easy access to the object from the other environment.
5058 v8::Handle<v8::Object> global1 = context1->Global();
5059 global1->Set(v8_str("obj"), object);
5060
5061 v8::Handle<Value> value;
5062
5063 value = v8_compile("var p = 'as' + 'df';")->Run();
5064 value = v8_compile("obj[p];")->Run();
5065
5066 context1->Exit();
5067 context0->Exit();
5068 context1.Dispose();
5069 context0.Dispose();
5070}
5071
5072
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005073static v8::Handle<Value> AccessControlNamedGetter(
5074 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005075 return v8::Integer::New(42);
5076}
5077
5078
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005079static v8::Handle<Value> AccessControlNamedSetter(
5080 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005081 return value;
5082}
5083
5084
5085static v8::Handle<Value> AccessControlIndexedGetter(
5086 uint32_t index,
5087 const AccessorInfo& info) {
5088 return v8_num(42);
5089}
5090
5091
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005092static v8::Handle<Value> AccessControlIndexedSetter(
5093 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005094 return value;
5095}
5096
5097
5098THREADED_TEST(AccessControlInterceptorIC) {
5099 named_access_count = 0;
5100 indexed_access_count = 0;
5101
5102 v8::HandleScope handle_scope;
5103
5104 // Create an environment.
5105 v8::Persistent<Context> context0 = Context::New();
5106 context0->Enter();
5107
5108 // Create an object that requires access-check functions to be
5109 // called for cross-domain access. The object also has interceptors
5110 // interceptor.
5111 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5112 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5113 IndexedAccessCounter);
5114 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5115 AccessControlNamedSetter);
5116 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5117 AccessControlIndexedSetter);
5118 Local<v8::Object> object = object_template->NewInstance();
5119
5120 v8::HandleScope scope1;
5121
5122 // Create another environment.
5123 v8::Persistent<Context> context1 = Context::New();
5124 context1->Enter();
5125
5126 // Make easy access to the object from the other environment.
5127 v8::Handle<v8::Object> global1 = context1->Global();
5128 global1->Set(v8_str("obj"), object);
5129
5130 v8::Handle<Value> value;
5131
5132 // Check that the named access-control function is called every time
5133 // eventhough there is an interceptor on the object.
5134 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5135 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5136 "obj.x")->Run();
5137 CHECK(value->IsNumber());
5138 CHECK_EQ(42, value->Int32Value());
5139 CHECK_EQ(21, named_access_count);
5140
5141 value = v8_compile("var p = 'x';")->Run();
5142 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5143 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5144 "obj[p]")->Run();
5145 CHECK(value->IsNumber());
5146 CHECK_EQ(42, value->Int32Value());
5147 CHECK_EQ(42, named_access_count);
5148
5149 // Check that the indexed access-control function is called every
5150 // time eventhough there is an interceptor on the object.
5151 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5152 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5153 "obj[0]")->Run();
5154 CHECK(value->IsNumber());
5155 CHECK_EQ(42, value->Int32Value());
5156 CHECK_EQ(21, indexed_access_count);
5157
5158 context1->Exit();
5159 context0->Exit();
5160 context1.Dispose();
5161 context0.Dispose();
5162}
5163
5164
5165THREADED_TEST(Version) {
5166 v8::V8::GetVersion();
5167}
5168
5169
5170static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5171 ApiTestFuzzer::Fuzz();
5172 return v8_num(12);
5173}
5174
5175
5176THREADED_TEST(InstanceProperties) {
5177 v8::HandleScope handle_scope;
5178 LocalContext context;
5179
5180 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5181 Local<ObjectTemplate> instance = t->InstanceTemplate();
5182
5183 instance->Set(v8_str("x"), v8_num(42));
5184 instance->Set(v8_str("f"),
5185 v8::FunctionTemplate::New(InstanceFunctionCallback));
5186
5187 Local<Value> o = t->GetFunction()->NewInstance();
5188
5189 context->Global()->Set(v8_str("i"), o);
5190 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5191 CHECK_EQ(42, value->Int32Value());
5192
5193 value = Script::Compile(v8_str("i.f()"))->Run();
5194 CHECK_EQ(12, value->Int32Value());
5195}
5196
5197
5198static v8::Handle<Value>
5199GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5200 ApiTestFuzzer::Fuzz();
5201 return v8::Handle<Value>();
5202}
5203
5204
5205THREADED_TEST(GlobalObjectInstanceProperties) {
5206 v8::HandleScope handle_scope;
5207
5208 Local<Value> global_object;
5209
5210 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5211 t->InstanceTemplate()->SetNamedPropertyHandler(
5212 GlobalObjectInstancePropertiesGet);
5213 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5214 instance_template->Set(v8_str("x"), v8_num(42));
5215 instance_template->Set(v8_str("f"),
5216 v8::FunctionTemplate::New(InstanceFunctionCallback));
5217
5218 {
5219 LocalContext env(NULL, instance_template);
5220 // Hold on to the global object so it can be used again in another
5221 // environment initialization.
5222 global_object = env->Global();
5223
5224 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5225 CHECK_EQ(42, value->Int32Value());
5226 value = Script::Compile(v8_str("f()"))->Run();
5227 CHECK_EQ(12, value->Int32Value());
5228 }
5229
5230 {
5231 // Create new environment reusing the global object.
5232 LocalContext env(NULL, instance_template, global_object);
5233 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5234 CHECK_EQ(42, value->Int32Value());
5235 value = Script::Compile(v8_str("f()"))->Run();
5236 CHECK_EQ(12, value->Int32Value());
5237 }
5238}
5239
5240
5241static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5242 ApiTestFuzzer::Fuzz();
5243 return v8_num(42);
5244}
5245
5246
5247static int shadow_y;
5248static int shadow_y_setter_call_count;
5249static int shadow_y_getter_call_count;
5250
5251
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005252static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005253 shadow_y_setter_call_count++;
5254 shadow_y = 42;
5255}
5256
5257
5258static v8::Handle<Value> ShadowYGetter(Local<String> name,
5259 const AccessorInfo& info) {
5260 ApiTestFuzzer::Fuzz();
5261 shadow_y_getter_call_count++;
5262 return v8_num(shadow_y);
5263}
5264
5265
5266static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5267 const AccessorInfo& info) {
5268 return v8::Handle<Value>();
5269}
5270
5271
5272static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5273 const AccessorInfo&) {
5274 return v8::Handle<Value>();
5275}
5276
5277
5278THREADED_TEST(ShadowObject) {
5279 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5280 v8::HandleScope handle_scope;
5281
5282 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5283 LocalContext context(NULL, global_template);
5284
5285 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5286 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5287 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5288 Local<ObjectTemplate> proto = t->PrototypeTemplate();
5289 Local<ObjectTemplate> instance = t->InstanceTemplate();
5290
5291 // Only allow calls of f on instances of t.
5292 Local<v8::Signature> signature = v8::Signature::New(t);
5293 proto->Set(v8_str("f"),
5294 v8::FunctionTemplate::New(ShadowFunctionCallback,
5295 Local<Value>(),
5296 signature));
5297 proto->Set(v8_str("x"), v8_num(12));
5298
5299 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5300
5301 Local<Value> o = t->GetFunction()->NewInstance();
5302 context->Global()->Set(v8_str("__proto__"), o);
5303
5304 Local<Value> value =
5305 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5306 CHECK(value->IsBoolean());
5307 CHECK(!value->BooleanValue());
5308
5309 value = Script::Compile(v8_str("x"))->Run();
5310 CHECK_EQ(12, value->Int32Value());
5311
5312 value = Script::Compile(v8_str("f()"))->Run();
5313 CHECK_EQ(42, value->Int32Value());
5314
5315 Script::Compile(v8_str("y = 42"))->Run();
5316 CHECK_EQ(1, shadow_y_setter_call_count);
5317 value = Script::Compile(v8_str("y"))->Run();
5318 CHECK_EQ(1, shadow_y_getter_call_count);
5319 CHECK_EQ(42, value->Int32Value());
5320}
5321
5322
5323THREADED_TEST(HiddenPrototype) {
5324 v8::HandleScope handle_scope;
5325 LocalContext context;
5326
5327 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5328 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5329 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5330 t1->SetHiddenPrototype(true);
5331 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5332 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5333 t2->SetHiddenPrototype(true);
5334 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5335 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5336 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5337
5338 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5339 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5340 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5341 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5342
5343 // Setting the prototype on an object skips hidden prototypes.
5344 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5345 o0->Set(v8_str("__proto__"), o1);
5346 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5347 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5348 o0->Set(v8_str("__proto__"), o2);
5349 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5350 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5351 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5352 o0->Set(v8_str("__proto__"), o3);
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 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5357
5358 // Getting the prototype of o0 should get the first visible one
5359 // which is o3. Therefore, z should not be defined on the prototype
5360 // object.
5361 Local<Value> proto = o0->Get(v8_str("__proto__"));
5362 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005363 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005364}
5365
5366
ager@chromium.org5c838252010-02-19 08:53:10 +00005367THREADED_TEST(SetPrototype) {
5368 v8::HandleScope handle_scope;
5369 LocalContext context;
5370
5371 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5372 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5373 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5374 t1->SetHiddenPrototype(true);
5375 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5376 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5377 t2->SetHiddenPrototype(true);
5378 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5379 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5380 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5381
5382 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5383 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5384 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5385 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5386
5387 // Setting the prototype on an object does not skip hidden prototypes.
5388 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5389 CHECK(o0->SetPrototype(o1));
5390 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5391 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5392 CHECK(o1->SetPrototype(o2));
5393 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5394 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5395 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5396 CHECK(o2->SetPrototype(o3));
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_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5401
5402 // Getting the prototype of o0 should get the first visible one
5403 // which is o3. Therefore, z should not be defined on the prototype
5404 // object.
5405 Local<Value> proto = o0->Get(v8_str("__proto__"));
5406 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005407 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00005408
5409 // However, Object::GetPrototype ignores hidden prototype.
5410 Local<Value> proto0 = o0->GetPrototype();
5411 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005412 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00005413
5414 Local<Value> proto1 = o1->GetPrototype();
5415 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005416 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00005417
5418 Local<Value> proto2 = o2->GetPrototype();
5419 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005420 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00005421}
5422
5423
5424THREADED_TEST(SetPrototypeThrows) {
5425 v8::HandleScope handle_scope;
5426 LocalContext context;
5427
5428 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5429
5430 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5431 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5432
5433 CHECK(o0->SetPrototype(o1));
5434 // If setting the prototype leads to the cycle, SetPrototype should
5435 // return false and keep VM in sane state.
5436 v8::TryCatch try_catch;
5437 CHECK(!o1->SetPrototype(o0));
5438 CHECK(!try_catch.HasCaught());
5439 ASSERT(!i::Top::has_pending_exception());
5440
5441 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5442}
5443
5444
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005445THREADED_TEST(GetterSetterExceptions) {
5446 v8::HandleScope handle_scope;
5447 LocalContext context;
5448 CompileRun(
5449 "function Foo() { };"
5450 "function Throw() { throw 5; };"
5451 "var x = { };"
5452 "x.__defineSetter__('set', Throw);"
5453 "x.__defineGetter__('get', Throw);");
5454 Local<v8::Object> x =
5455 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5456 v8::TryCatch try_catch;
5457 x->Set(v8_str("set"), v8::Integer::New(8));
5458 x->Get(v8_str("get"));
5459 x->Set(v8_str("set"), v8::Integer::New(8));
5460 x->Get(v8_str("get"));
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}
5466
5467
5468THREADED_TEST(Constructor) {
5469 v8::HandleScope handle_scope;
5470 LocalContext context;
5471 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5472 templ->SetClassName(v8_str("Fun"));
5473 Local<Function> cons = templ->GetFunction();
5474 context->Global()->Set(v8_str("Fun"), cons);
5475 Local<v8::Object> inst = cons->NewInstance();
5476 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5477 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5478 CHECK(value->BooleanValue());
5479}
5480
5481THREADED_TEST(FunctionDescriptorException) {
5482 v8::HandleScope handle_scope;
5483 LocalContext context;
5484 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5485 templ->SetClassName(v8_str("Fun"));
5486 Local<Function> cons = templ->GetFunction();
5487 context->Global()->Set(v8_str("Fun"), cons);
5488 Local<Value> value = CompileRun(
5489 "function test() {"
5490 " try {"
5491 " (new Fun()).blah()"
5492 " } catch (e) {"
5493 " var str = String(e);"
5494 " if (str.indexOf('TypeError') == -1) return 1;"
5495 " if (str.indexOf('[object Fun]') != -1) return 2;"
5496 " if (str.indexOf('#<a Fun>') == -1) return 3;"
5497 " return 0;"
5498 " }"
5499 " return 4;"
5500 "}"
5501 "test();");
5502 CHECK_EQ(0, value->Int32Value());
5503}
5504
5505
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005506THREADED_TEST(EvalAliasedDynamic) {
5507 v8::HandleScope scope;
5508 LocalContext current;
5509
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005510 // Tests where aliased eval can only be resolved dynamically.
5511 Local<Script> script =
5512 Script::Compile(v8_str("function f(x) { "
5513 " var foo = 2;"
5514 " with (x) { return eval('foo'); }"
5515 "}"
5516 "foo = 0;"
5517 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00005518 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005519 "var x = new Object();"
5520 "x.eval = function(x) { return 1; };"
5521 "result3 = f(x);"));
5522 script->Run();
5523 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5524 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5525 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5526
5527 v8::TryCatch try_catch;
5528 script =
5529 Script::Compile(v8_str("function f(x) { "
5530 " var bar = 2;"
5531 " with (x) { return eval('bar'); }"
5532 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00005533 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005534 script->Run();
5535 CHECK(try_catch.HasCaught());
5536 try_catch.Reset();
5537}
5538
5539
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005540THREADED_TEST(CrossEval) {
5541 v8::HandleScope scope;
5542 LocalContext other;
5543 LocalContext current;
5544
5545 Local<String> token = v8_str("<security token>");
5546 other->SetSecurityToken(token);
5547 current->SetSecurityToken(token);
5548
5549 // Setup reference from current to other.
5550 current->Global()->Set(v8_str("other"), other->Global());
5551
5552 // Check that new variables are introduced in other context.
5553 Local<Script> script =
5554 Script::Compile(v8_str("other.eval('var foo = 1234')"));
5555 script->Run();
5556 Local<Value> foo = other->Global()->Get(v8_str("foo"));
5557 CHECK_EQ(1234, foo->Int32Value());
5558 CHECK(!current->Global()->Has(v8_str("foo")));
5559
5560 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005561 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005562 script =
5563 Script::Compile(v8_str("other.eval('na = 1234')"));
5564 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005565 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5566 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005567
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005568 // Check that global variables in current context are not visible in other
5569 // context.
5570 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005571 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005572 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005573 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005574 CHECK(try_catch.HasCaught());
5575 try_catch.Reset();
5576
5577 // Check that local variables in current context are not visible in other
5578 // context.
5579 script =
5580 Script::Compile(v8_str("(function() { "
5581 " var baz = 87;"
5582 " return other.eval('baz');"
5583 "})();"));
5584 result = script->Run();
5585 CHECK(try_catch.HasCaught());
5586 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005587
5588 // Check that global variables in the other environment are visible
5589 // when evaluting code.
5590 other->Global()->Set(v8_str("bis"), v8_num(1234));
5591 script = Script::Compile(v8_str("other.eval('bis')"));
5592 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005593 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005594
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005595 // Check that the 'this' pointer points to the global object evaluating
5596 // code.
5597 other->Global()->Set(v8_str("t"), other->Global());
5598 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005599 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005600 CHECK(result->IsTrue());
5601 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005602
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005603 // Check that variables introduced in with-statement are not visible in
5604 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005605 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005606 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005607 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005608 CHECK(try_catch.HasCaught());
5609 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005610
5611 // Check that you cannot use 'eval.call' with another object than the
5612 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005613 script =
5614 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5615 result = script->Run();
5616 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005617}
5618
5619
ager@chromium.orge2902be2009-06-08 12:21:35 +00005620// Test that calling eval in a context which has been detached from
5621// its global throws an exception. This behavior is consistent with
5622// other JavaScript implementations.
5623THREADED_TEST(EvalInDetachedGlobal) {
5624 v8::HandleScope scope;
5625
5626 v8::Persistent<Context> context0 = Context::New();
5627 v8::Persistent<Context> context1 = Context::New();
5628
5629 // Setup function in context0 that uses eval from context0.
5630 context0->Enter();
5631 v8::Handle<v8::Value> fun =
5632 CompileRun("var x = 42;"
5633 "(function() {"
5634 " var e = eval;"
5635 " return function(s) { return e(s); }"
5636 "})()");
5637 context0->Exit();
5638
5639 // Put the function into context1 and call it before and after
5640 // detaching the global. Before detaching, the call succeeds and
5641 // after detaching and exception is thrown.
5642 context1->Enter();
5643 context1->Global()->Set(v8_str("fun"), fun);
5644 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5645 CHECK_EQ(42, x_value->Int32Value());
5646 context0->DetachGlobal();
5647 v8::TryCatch catcher;
5648 x_value = CompileRun("fun('x')");
5649 CHECK(x_value.IsEmpty());
5650 CHECK(catcher.HasCaught());
5651 context1->Exit();
5652
5653 context1.Dispose();
5654 context0.Dispose();
5655}
5656
5657
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005658THREADED_TEST(CrossLazyLoad) {
5659 v8::HandleScope scope;
5660 LocalContext other;
5661 LocalContext current;
5662
5663 Local<String> token = v8_str("<security token>");
5664 other->SetSecurityToken(token);
5665 current->SetSecurityToken(token);
5666
5667 // Setup reference from current to other.
5668 current->Global()->Set(v8_str("other"), other->Global());
5669
5670 // Trigger lazy loading in other context.
5671 Local<Script> script =
5672 Script::Compile(v8_str("other.eval('new Date(42)')"));
5673 Local<Value> value = script->Run();
5674 CHECK_EQ(42.0, value->NumberValue());
5675}
5676
5677
5678static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
5679 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00005680 if (args.IsConstructCall()) {
5681 if (args[0]->IsInt32()) {
5682 return v8_num(-args[0]->Int32Value());
5683 }
5684 }
5685
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005686 return args[0];
5687}
5688
5689
5690// Test that a call handler can be set for objects which will allow
5691// non-function objects created through the API to be called as
5692// functions.
5693THREADED_TEST(CallAsFunction) {
5694 v8::HandleScope scope;
5695 LocalContext context;
5696
5697 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5698 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5699 instance_template->SetCallAsFunctionHandler(call_as_function);
5700 Local<v8::Object> instance = t->GetFunction()->NewInstance();
5701 context->Global()->Set(v8_str("obj"), instance);
5702 v8::TryCatch try_catch;
5703 Local<Value> value;
5704 CHECK(!try_catch.HasCaught());
5705
ager@chromium.org9085a012009-05-11 19:22:57 +00005706 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005707 CHECK(!try_catch.HasCaught());
5708 CHECK_EQ(42, value->Int32Value());
5709
ager@chromium.org9085a012009-05-11 19:22:57 +00005710 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005711 CHECK(!try_catch.HasCaught());
5712 CHECK_EQ(49, value->Int32Value());
5713
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005714 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00005715 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005716 CHECK(!try_catch.HasCaught());
5717 CHECK_EQ(45, value->Int32Value());
5718
ager@chromium.org9085a012009-05-11 19:22:57 +00005719 value = CompileRun("obj.call = Function.prototype.call;"
5720 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005721 CHECK(!try_catch.HasCaught());
5722 CHECK_EQ(87, value->Int32Value());
5723
5724 // Regression tests for bug #1116356: Calling call through call/apply
5725 // must work for non-function receivers.
5726 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00005727 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005728 CHECK(!try_catch.HasCaught());
5729 CHECK_EQ(99, value->Int32Value());
5730
5731 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00005732 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005733 CHECK(!try_catch.HasCaught());
5734 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00005735
5736 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005737 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00005738 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00005739 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00005740 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005741}
5742
5743
5744static int CountHandles() {
5745 return v8::HandleScope::NumberOfHandles();
5746}
5747
5748
5749static int Recurse(int depth, int iterations) {
5750 v8::HandleScope scope;
5751 if (depth == 0) return CountHandles();
5752 for (int i = 0; i < iterations; i++) {
5753 Local<v8::Number> n = v8::Integer::New(42);
5754 }
5755 return Recurse(depth - 1, iterations);
5756}
5757
5758
5759THREADED_TEST(HandleIteration) {
5760 static const int kIterations = 500;
5761 static const int kNesting = 200;
5762 CHECK_EQ(0, CountHandles());
5763 {
5764 v8::HandleScope scope1;
5765 CHECK_EQ(0, CountHandles());
5766 for (int i = 0; i < kIterations; i++) {
5767 Local<v8::Number> n = v8::Integer::New(42);
5768 CHECK_EQ(i + 1, CountHandles());
5769 }
5770
5771 CHECK_EQ(kIterations, CountHandles());
5772 {
5773 v8::HandleScope scope2;
5774 for (int j = 0; j < kIterations; j++) {
5775 Local<v8::Number> n = v8::Integer::New(42);
5776 CHECK_EQ(j + 1 + kIterations, CountHandles());
5777 }
5778 }
5779 CHECK_EQ(kIterations, CountHandles());
5780 }
5781 CHECK_EQ(0, CountHandles());
5782 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
5783}
5784
5785
5786static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5787 Local<String> name,
5788 const AccessorInfo& info) {
5789 ApiTestFuzzer::Fuzz();
5790 return v8::Handle<Value>();
5791}
5792
5793
5794THREADED_TEST(InterceptorHasOwnProperty) {
5795 v8::HandleScope scope;
5796 LocalContext context;
5797 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5798 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5799 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5800 Local<Function> function = fun_templ->GetFunction();
5801 context->Global()->Set(v8_str("constructor"), function);
5802 v8::Handle<Value> value = CompileRun(
5803 "var o = new constructor();"
5804 "o.hasOwnProperty('ostehaps');");
5805 CHECK_EQ(false, value->BooleanValue());
5806 value = CompileRun(
5807 "o.ostehaps = 42;"
5808 "o.hasOwnProperty('ostehaps');");
5809 CHECK_EQ(true, value->BooleanValue());
5810 value = CompileRun(
5811 "var p = new constructor();"
5812 "p.hasOwnProperty('ostehaps');");
5813 CHECK_EQ(false, value->BooleanValue());
5814}
5815
5816
ager@chromium.org9085a012009-05-11 19:22:57 +00005817static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5818 Local<String> name,
5819 const AccessorInfo& info) {
5820 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00005821 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00005822 return v8::Handle<Value>();
5823}
5824
5825
5826THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5827 v8::HandleScope scope;
5828 LocalContext context;
5829 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5830 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5831 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5832 Local<Function> function = fun_templ->GetFunction();
5833 context->Global()->Set(v8_str("constructor"), function);
5834 // Let's first make some stuff so we can be sure to get a good GC.
5835 CompileRun(
5836 "function makestr(size) {"
5837 " switch (size) {"
5838 " case 1: return 'f';"
5839 " case 2: return 'fo';"
5840 " case 3: return 'foo';"
5841 " }"
5842 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
5843 "}"
5844 "var x = makestr(12345);"
5845 "x = makestr(31415);"
5846 "x = makestr(23456);");
5847 v8::Handle<Value> value = CompileRun(
5848 "var o = new constructor();"
5849 "o.__proto__ = new String(x);"
5850 "o.hasOwnProperty('ostehaps');");
5851 CHECK_EQ(false, value->BooleanValue());
5852}
5853
5854
ager@chromium.orge2902be2009-06-08 12:21:35 +00005855typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5856 const AccessorInfo& info);
5857
5858
5859static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5860 const char* source,
5861 int expected) {
5862 v8::HandleScope scope;
5863 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5864 templ->SetNamedPropertyHandler(getter);
5865 LocalContext context;
5866 context->Global()->Set(v8_str("o"), templ->NewInstance());
5867 v8::Handle<Value> value = CompileRun(source);
5868 CHECK_EQ(expected, value->Int32Value());
5869}
5870
5871
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005872static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5873 const AccessorInfo& info) {
5874 ApiTestFuzzer::Fuzz();
5875 CHECK(v8_str("x")->Equals(name));
5876 return v8::Integer::New(42);
5877}
5878
5879
5880// This test should hit the load IC for the interceptor case.
5881THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00005882 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005883 "var result = 0;"
5884 "for (var i = 0; i < 1000; i++) {"
5885 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00005886 "}",
5887 42);
5888}
5889
5890
5891// Below go several tests which verify that JITing for various
5892// configurations of interceptor and explicit fields works fine
5893// (those cases are special cased to get better performance).
5894
5895static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5896 const AccessorInfo& info) {
5897 ApiTestFuzzer::Fuzz();
5898 return v8_str("x")->Equals(name)
5899 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5900}
5901
5902
5903THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5904 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5905 "var result = 0;"
5906 "o.y = 239;"
5907 "for (var i = 0; i < 1000; i++) {"
5908 " result = o.y;"
5909 "}",
5910 239);
5911}
5912
5913
5914THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5915 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5916 "var result = 0;"
5917 "o.__proto__ = { 'y': 239 };"
5918 "for (var i = 0; i < 1000; i++) {"
5919 " result = o.y + o.x;"
5920 "}",
5921 239 + 42);
5922}
5923
5924
5925THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5926 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5927 "var result = 0;"
5928 "o.__proto__.y = 239;"
5929 "for (var i = 0; i < 1000; i++) {"
5930 " result = o.y + o.x;"
5931 "}",
5932 239 + 42);
5933}
5934
5935
5936THREADED_TEST(InterceptorLoadICUndefined) {
5937 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5938 "var result = 0;"
5939 "for (var i = 0; i < 1000; i++) {"
5940 " result = (o.y == undefined) ? 239 : 42;"
5941 "}",
5942 239);
5943}
5944
5945
5946THREADED_TEST(InterceptorLoadICWithOverride) {
5947 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5948 "fst = new Object(); fst.__proto__ = o;"
5949 "snd = new Object(); snd.__proto__ = fst;"
5950 "var result1 = 0;"
5951 "for (var i = 0; i < 1000; i++) {"
5952 " result1 = snd.x;"
5953 "}"
5954 "fst.x = 239;"
5955 "var result = 0;"
5956 "for (var i = 0; i < 1000; i++) {"
5957 " result = snd.x;"
5958 "}"
5959 "result + result1",
5960 239 + 42);
5961}
5962
5963
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005964// Test the case when we stored field into
5965// a stub, but interceptor produced value on its own.
5966THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5967 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5968 "proto = new Object();"
5969 "o.__proto__ = proto;"
5970 "proto.x = 239;"
5971 "for (var i = 0; i < 1000; i++) {"
5972 " o.x;"
5973 // Now it should be ICed and keep a reference to x defined on proto
5974 "}"
5975 "var result = 0;"
5976 "for (var i = 0; i < 1000; i++) {"
5977 " result += o.x;"
5978 "}"
5979 "result;",
5980 42 * 1000);
5981}
5982
5983
5984// Test the case when we stored field into
5985// a stub, but it got invalidated later on.
5986THREADED_TEST(InterceptorLoadICInvalidatedField) {
5987 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5988 "proto1 = new Object();"
5989 "proto2 = new Object();"
5990 "o.__proto__ = proto1;"
5991 "proto1.__proto__ = proto2;"
5992 "proto2.y = 239;"
5993 "for (var i = 0; i < 1000; i++) {"
5994 " o.y;"
5995 // Now it should be ICed and keep a reference to y defined on proto2
5996 "}"
5997 "proto1.y = 42;"
5998 "var result = 0;"
5999 "for (var i = 0; i < 1000; i++) {"
6000 " result += o.y;"
6001 "}"
6002 "result;",
6003 42 * 1000);
6004}
6005
6006
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00006007static int interceptor_load_not_handled_calls = 0;
6008static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6009 const AccessorInfo& info) {
6010 ++interceptor_load_not_handled_calls;
6011 return v8::Handle<v8::Value>();
6012}
6013
6014
6015// Test how post-interceptor lookups are done in the non-cacheable
6016// case: the interceptor should not be invoked during this lookup.
6017THREADED_TEST(InterceptorLoadICPostInterceptor) {
6018 interceptor_load_not_handled_calls = 0;
6019 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6020 "receiver = new Object();"
6021 "receiver.__proto__ = o;"
6022 "proto = new Object();"
6023 "/* Make proto a slow-case object. */"
6024 "for (var i = 0; i < 1000; i++) {"
6025 " proto[\"xxxxxxxx\" + i] = [];"
6026 "}"
6027 "proto.x = 17;"
6028 "o.__proto__ = proto;"
6029 "var result = 0;"
6030 "for (var i = 0; i < 1000; i++) {"
6031 " result += receiver.x;"
6032 "}"
6033 "result;",
6034 17 * 1000);
6035 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6036}
6037
6038
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006039// Test the case when we stored field into
6040// a stub, but it got invalidated later on due to override on
6041// global object which is between interceptor and fields' holders.
6042THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6043 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6044 "o.__proto__ = this;" // set a global to be a proto of o.
6045 "this.__proto__.y = 239;"
6046 "for (var i = 0; i < 10; i++) {"
6047 " if (o.y != 239) throw 'oops: ' + o.y;"
6048 // Now it should be ICed and keep a reference to y defined on field_holder.
6049 "}"
6050 "this.y = 42;" // Assign on a global.
6051 "var result = 0;"
6052 "for (var i = 0; i < 10; i++) {"
6053 " result += o.y;"
6054 "}"
6055 "result;",
6056 42 * 10);
6057}
6058
6059
6060static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
6061 ApiTestFuzzer::Fuzz();
6062 return v8_num(239);
6063}
6064
6065
6066static void SetOnThis(Local<String> name,
6067 Local<Value> value,
6068 const AccessorInfo& info) {
6069 info.This()->ForceSet(name, value);
6070}
6071
6072
6073THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6074 v8::HandleScope scope;
6075 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6076 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6077 templ->SetAccessor(v8_str("y"), Return239);
6078 LocalContext context;
6079 context->Global()->Set(v8_str("o"), templ->NewInstance());
6080 v8::Handle<Value> value = CompileRun(
6081 "var result = 0;"
6082 "for (var i = 0; i < 7; i++) {"
6083 " result = o.y;"
6084 "}");
6085 CHECK_EQ(239, value->Int32Value());
6086}
6087
6088
6089THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6090 v8::HandleScope scope;
6091 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6092 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6093 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6094 templ_p->SetAccessor(v8_str("y"), Return239);
6095
6096 LocalContext context;
6097 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6098 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6099
6100 v8::Handle<Value> value = CompileRun(
6101 "o.__proto__ = p;"
6102 "var result = 0;"
6103 "for (var i = 0; i < 7; i++) {"
6104 " result = o.x + o.y;"
6105 "}");
6106 CHECK_EQ(239 + 42, value->Int32Value());
6107}
6108
6109
6110THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6111 v8::HandleScope scope;
6112 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6113 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6114 templ->SetAccessor(v8_str("y"), Return239);
6115
6116 LocalContext context;
6117 context->Global()->Set(v8_str("o"), templ->NewInstance());
6118
6119 v8::Handle<Value> value = CompileRun(
6120 "fst = new Object(); fst.__proto__ = o;"
6121 "snd = new Object(); snd.__proto__ = fst;"
6122 "var result1 = 0;"
6123 "for (var i = 0; i < 7; i++) {"
6124 " result1 = snd.x;"
6125 "}"
6126 "fst.x = 239;"
6127 "var result = 0;"
6128 "for (var i = 0; i < 7; i++) {"
6129 " result = snd.x;"
6130 "}"
6131 "result + result1");
6132 CHECK_EQ(239 + 42, value->Int32Value());
6133}
6134
6135
6136// Test the case when we stored callback into
6137// a stub, but interceptor produced value on its own.
6138THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6139 v8::HandleScope scope;
6140 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6141 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6142 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6143 templ_p->SetAccessor(v8_str("y"), Return239);
6144
6145 LocalContext context;
6146 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6147 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6148
6149 v8::Handle<Value> value = CompileRun(
6150 "o.__proto__ = p;"
6151 "for (var i = 0; i < 7; i++) {"
6152 " o.x;"
6153 // Now it should be ICed and keep a reference to x defined on p
6154 "}"
6155 "var result = 0;"
6156 "for (var i = 0; i < 7; i++) {"
6157 " result += o.x;"
6158 "}"
6159 "result");
6160 CHECK_EQ(42 * 7, value->Int32Value());
6161}
6162
6163
6164// Test the case when we stored callback into
6165// a stub, but it got invalidated later on.
6166THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6167 v8::HandleScope scope;
6168 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6169 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6170 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6171 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6172
6173 LocalContext context;
6174 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6175 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6176
6177 v8::Handle<Value> value = CompileRun(
6178 "inbetween = new Object();"
6179 "o.__proto__ = inbetween;"
6180 "inbetween.__proto__ = p;"
6181 "for (var i = 0; i < 10; i++) {"
6182 " o.y;"
6183 // Now it should be ICed and keep a reference to y defined on p
6184 "}"
6185 "inbetween.y = 42;"
6186 "var result = 0;"
6187 "for (var i = 0; i < 10; i++) {"
6188 " result += o.y;"
6189 "}"
6190 "result");
6191 CHECK_EQ(42 * 10, value->Int32Value());
6192}
6193
6194
6195// Test the case when we stored callback into
6196// a stub, but it got invalidated later on due to override on
6197// global object which is between interceptor and callbacks' holders.
6198THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6199 v8::HandleScope scope;
6200 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6201 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6202 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6203 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6204
6205 LocalContext context;
6206 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6207 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6208
6209 v8::Handle<Value> value = CompileRun(
6210 "o.__proto__ = this;"
6211 "this.__proto__ = p;"
6212 "for (var i = 0; i < 10; i++) {"
6213 " if (o.y != 239) throw 'oops: ' + o.y;"
6214 // Now it should be ICed and keep a reference to y defined on p
6215 "}"
6216 "this.y = 42;"
6217 "var result = 0;"
6218 "for (var i = 0; i < 10; i++) {"
6219 " result += o.y;"
6220 "}"
6221 "result");
6222 CHECK_EQ(42 * 10, value->Int32Value());
6223}
6224
6225
ager@chromium.orge2902be2009-06-08 12:21:35 +00006226static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6227 const AccessorInfo& info) {
6228 ApiTestFuzzer::Fuzz();
6229 CHECK(v8_str("x")->Equals(name));
6230 return v8::Integer::New(0);
6231}
6232
6233
6234THREADED_TEST(InterceptorReturningZero) {
6235 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6236 "o.x == undefined ? 1 : 0",
6237 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006238}
6239
6240
6241static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006242 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006243 CHECK(v8_str("x")->Equals(key));
6244 CHECK_EQ(42, value->Int32Value());
6245 return value;
6246}
6247
6248
6249// This test should hit the store IC for the interceptor case.
6250THREADED_TEST(InterceptorStoreIC) {
6251 v8::HandleScope scope;
6252 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6253 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6254 InterceptorStoreICSetter);
6255 LocalContext context;
6256 context->Global()->Set(v8_str("o"), templ->NewInstance());
6257 v8::Handle<Value> value = CompileRun(
6258 "for (var i = 0; i < 1000; i++) {"
6259 " o.x = 42;"
6260 "}");
6261}
6262
6263
ager@chromium.orgeadaf222009-06-16 09:43:10 +00006264THREADED_TEST(InterceptorStoreICWithNoSetter) {
6265 v8::HandleScope scope;
6266 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6267 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6268 LocalContext context;
6269 context->Global()->Set(v8_str("o"), templ->NewInstance());
6270 v8::Handle<Value> value = CompileRun(
6271 "for (var i = 0; i < 1000; i++) {"
6272 " o.y = 239;"
6273 "}"
6274 "42 + o.y");
6275 CHECK_EQ(239 + 42, value->Int32Value());
6276}
6277
6278
6279
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006280
6281v8::Handle<Value> call_ic_function;
6282v8::Handle<Value> call_ic_function2;
6283v8::Handle<Value> call_ic_function3;
6284
6285static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6286 const AccessorInfo& info) {
6287 ApiTestFuzzer::Fuzz();
6288 CHECK(v8_str("x")->Equals(name));
6289 return call_ic_function;
6290}
6291
6292
6293// This test should hit the call IC for the interceptor case.
6294THREADED_TEST(InterceptorCallIC) {
6295 v8::HandleScope scope;
6296 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6297 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6298 LocalContext context;
6299 context->Global()->Set(v8_str("o"), templ->NewInstance());
6300 call_ic_function =
6301 v8_compile("function f(x) { return x + 1; }; f")->Run();
6302 v8::Handle<Value> value = CompileRun(
6303 "var result = 0;"
6304 "for (var i = 0; i < 1000; i++) {"
6305 " result = o.x(41);"
6306 "}");
6307 CHECK_EQ(42, value->Int32Value());
6308}
6309
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006310
6311// This test checks that if interceptor doesn't provide
6312// a value, we can fetch regular value.
6313THREADED_TEST(InterceptorCallICSeesOthers) {
6314 v8::HandleScope scope;
6315 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6316 templ->SetNamedPropertyHandler(NoBlockGetterX);
6317 LocalContext context;
6318 context->Global()->Set(v8_str("o"), templ->NewInstance());
6319 v8::Handle<Value> value = CompileRun(
6320 "o.x = function f(x) { return x + 1; };"
6321 "var result = 0;"
6322 "for (var i = 0; i < 7; i++) {"
6323 " result = o.x(41);"
6324 "}");
6325 CHECK_EQ(42, value->Int32Value());
6326}
6327
6328
6329static v8::Handle<Value> call_ic_function4;
6330static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6331 const AccessorInfo& info) {
6332 ApiTestFuzzer::Fuzz();
6333 CHECK(v8_str("x")->Equals(name));
6334 return call_ic_function4;
6335}
6336
6337
6338// This test checks that if interceptor provides a function,
6339// even if we cached shadowed variant, interceptor's function
6340// is invoked
6341THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6342 v8::HandleScope scope;
6343 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6344 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6345 LocalContext context;
6346 context->Global()->Set(v8_str("o"), templ->NewInstance());
6347 call_ic_function4 =
6348 v8_compile("function f(x) { return x - 1; }; f")->Run();
6349 v8::Handle<Value> value = CompileRun(
6350 "o.__proto__.x = function(x) { return x + 1; };"
6351 "var result = 0;"
6352 "for (var i = 0; i < 1000; i++) {"
6353 " result = o.x(42);"
6354 "}");
6355 CHECK_EQ(41, value->Int32Value());
6356}
6357
6358
6359// Test the case when we stored cacheable lookup into
6360// a stub, but it got invalidated later on
6361THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6362 v8::HandleScope scope;
6363 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6364 templ->SetNamedPropertyHandler(NoBlockGetterX);
6365 LocalContext context;
6366 context->Global()->Set(v8_str("o"), templ->NewInstance());
6367 v8::Handle<Value> value = CompileRun(
6368 "proto1 = new Object();"
6369 "proto2 = new Object();"
6370 "o.__proto__ = proto1;"
6371 "proto1.__proto__ = proto2;"
6372 "proto2.y = function(x) { return x + 1; };"
6373 // Invoke it many times to compile a stub
6374 "for (var i = 0; i < 7; i++) {"
6375 " o.y(42);"
6376 "}"
6377 "proto1.y = function(x) { return x - 1; };"
6378 "var result = 0;"
6379 "for (var i = 0; i < 7; i++) {"
6380 " result += o.y(42);"
6381 "}");
6382 CHECK_EQ(41 * 7, value->Int32Value());
6383}
6384
6385
6386static v8::Handle<Value> call_ic_function5;
6387static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6388 const AccessorInfo& info) {
6389 ApiTestFuzzer::Fuzz();
6390 if (v8_str("x")->Equals(name))
6391 return call_ic_function5;
6392 else
6393 return Local<Value>();
6394}
6395
6396
6397// This test checks that if interceptor doesn't provide a function,
6398// cached constant function is used
6399THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6400 v8::HandleScope scope;
6401 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6402 templ->SetNamedPropertyHandler(NoBlockGetterX);
6403 LocalContext context;
6404 context->Global()->Set(v8_str("o"), templ->NewInstance());
6405 v8::Handle<Value> value = CompileRun(
6406 "function inc(x) { return x + 1; };"
6407 "inc(1);"
6408 "o.x = inc;"
6409 "var result = 0;"
6410 "for (var i = 0; i < 1000; i++) {"
6411 " result = o.x(42);"
6412 "}");
6413 CHECK_EQ(43, value->Int32Value());
6414}
6415
6416
6417// This test checks that if interceptor provides a function,
6418// even if we cached constant function, interceptor's function
6419// is invoked
6420THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6421 v8::HandleScope scope;
6422 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6423 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6424 LocalContext context;
6425 context->Global()->Set(v8_str("o"), templ->NewInstance());
6426 call_ic_function5 =
6427 v8_compile("function f(x) { return x - 1; }; f")->Run();
6428 v8::Handle<Value> value = CompileRun(
6429 "function inc(x) { return x + 1; };"
6430 "inc(1);"
6431 "o.x = inc;"
6432 "var result = 0;"
6433 "for (var i = 0; i < 1000; i++) {"
6434 " result = o.x(42);"
6435 "}");
6436 CHECK_EQ(41, value->Int32Value());
6437}
6438
6439
6440// Test the case when we stored constant function into
6441// a stub, but it got invalidated later on
6442THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6443 v8::HandleScope scope;
6444 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6445 templ->SetNamedPropertyHandler(NoBlockGetterX);
6446 LocalContext context;
6447 context->Global()->Set(v8_str("o"), templ->NewInstance());
6448 v8::Handle<Value> value = CompileRun(
6449 "function inc(x) { return x + 1; };"
6450 "inc(1);"
6451 "proto1 = new Object();"
6452 "proto2 = new Object();"
6453 "o.__proto__ = proto1;"
6454 "proto1.__proto__ = proto2;"
6455 "proto2.y = inc;"
6456 // Invoke it many times to compile a stub
6457 "for (var i = 0; i < 7; i++) {"
6458 " o.y(42);"
6459 "}"
6460 "proto1.y = function(x) { return x - 1; };"
6461 "var result = 0;"
6462 "for (var i = 0; i < 7; i++) {"
6463 " result += o.y(42);"
6464 "}");
6465 CHECK_EQ(41 * 7, value->Int32Value());
6466}
6467
6468
6469// Test the case when we stored constant function into
6470// a stub, but it got invalidated later on due to override on
6471// global object which is between interceptor and constant function' holders.
6472THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6473 v8::HandleScope scope;
6474 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6475 templ->SetNamedPropertyHandler(NoBlockGetterX);
6476 LocalContext context;
6477 context->Global()->Set(v8_str("o"), templ->NewInstance());
6478 v8::Handle<Value> value = CompileRun(
6479 "function inc(x) { return x + 1; };"
6480 "inc(1);"
6481 "o.__proto__ = this;"
6482 "this.__proto__.y = inc;"
6483 // Invoke it many times to compile a stub
6484 "for (var i = 0; i < 7; i++) {"
6485 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6486 "}"
6487 "this.y = function(x) { return x - 1; };"
6488 "var result = 0;"
6489 "for (var i = 0; i < 7; i++) {"
6490 " result += o.y(42);"
6491 "}");
6492 CHECK_EQ(41 * 7, value->Int32Value());
6493}
6494
6495
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006496// Test the case when actual function to call sits on global object.
6497THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6498 v8::HandleScope scope;
6499 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6500 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6501
6502 LocalContext context;
6503 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6504
6505 v8::Handle<Value> value = CompileRun(
6506 "try {"
6507 " o.__proto__ = this;"
6508 " for (var i = 0; i < 10; i++) {"
6509 " var v = o.parseFloat('239');"
6510 " if (v != 239) throw v;"
6511 // Now it should be ICed and keep a reference to parseFloat.
6512 " }"
6513 " var result = 0;"
6514 " for (var i = 0; i < 10; i++) {"
6515 " result += o.parseFloat('239');"
6516 " }"
6517 " result"
6518 "} catch(e) {"
6519 " e"
6520 "};");
6521 CHECK_EQ(239 * 10, value->Int32Value());
6522}
6523
ager@chromium.org5c838252010-02-19 08:53:10 +00006524static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6525 const AccessorInfo& info) {
6526 ApiTestFuzzer::Fuzz();
6527 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6528 ++(*call_count);
6529 if ((*call_count) % 20 == 0) {
6530 v8::internal::Heap::CollectAllGarbage(true);
6531 }
6532 return v8::Handle<Value>();
6533}
6534
6535static v8::Handle<Value> FastApiCallback_TrivialSignature(
6536 const v8::Arguments& args) {
6537 ApiTestFuzzer::Fuzz();
6538 CHECK_EQ(args.This(), args.Holder());
6539 CHECK(args.Data()->Equals(v8_str("method_data")));
6540 return v8::Integer::New(args[0]->Int32Value() + 1);
6541}
6542
6543static v8::Handle<Value> FastApiCallback_SimpleSignature(
6544 const v8::Arguments& args) {
6545 ApiTestFuzzer::Fuzz();
6546 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6547 CHECK(args.Data()->Equals(v8_str("method_data")));
6548 // Note, we're using HasRealNamedProperty instead of Has to avoid
6549 // invoking the interceptor again.
6550 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6551 return v8::Integer::New(args[0]->Int32Value() + 1);
6552}
6553
6554// Helper to maximize the odds of object moving.
6555static void GenerateSomeGarbage() {
6556 CompileRun(
6557 "var garbage;"
6558 "for (var i = 0; i < 1000; i++) {"
6559 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6560 "}"
6561 "garbage = undefined;");
6562}
6563
6564THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6565 int interceptor_call_count = 0;
6566 v8::HandleScope scope;
6567 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6568 v8::Handle<v8::FunctionTemplate> method_templ =
6569 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6570 v8_str("method_data"),
6571 v8::Handle<v8::Signature>());
6572 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6573 proto_templ->Set(v8_str("method"), method_templ);
6574 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6575 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6576 NULL, NULL, NULL, NULL,
6577 v8::External::Wrap(&interceptor_call_count));
6578 LocalContext context;
6579 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6580 GenerateSomeGarbage();
6581 context->Global()->Set(v8_str("o"), fun->NewInstance());
6582 v8::Handle<Value> value = CompileRun(
6583 "var result = 0;"
6584 "for (var i = 0; i < 100; i++) {"
6585 " result = o.method(41);"
6586 "}");
6587 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6588 CHECK_EQ(100, interceptor_call_count);
6589}
6590
6591THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6592 int interceptor_call_count = 0;
6593 v8::HandleScope scope;
6594 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6595 v8::Handle<v8::FunctionTemplate> method_templ =
6596 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6597 v8_str("method_data"),
6598 v8::Signature::New(fun_templ));
6599 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6600 proto_templ->Set(v8_str("method"), method_templ);
6601 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6602 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6603 NULL, NULL, NULL, NULL,
6604 v8::External::Wrap(&interceptor_call_count));
6605 LocalContext context;
6606 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6607 GenerateSomeGarbage();
6608 context->Global()->Set(v8_str("o"), fun->NewInstance());
6609 v8::Handle<Value> value = CompileRun(
6610 "o.foo = 17;"
6611 "var receiver = {};"
6612 "receiver.__proto__ = o;"
6613 "var result = 0;"
6614 "for (var i = 0; i < 100; i++) {"
6615 " result = receiver.method(41);"
6616 "}");
6617 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6618 CHECK_EQ(100, interceptor_call_count);
6619}
6620
6621THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6622 int interceptor_call_count = 0;
6623 v8::HandleScope scope;
6624 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6625 v8::Handle<v8::FunctionTemplate> method_templ =
6626 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6627 v8_str("method_data"),
6628 v8::Signature::New(fun_templ));
6629 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6630 proto_templ->Set(v8_str("method"), method_templ);
6631 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6632 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6633 NULL, NULL, NULL, NULL,
6634 v8::External::Wrap(&interceptor_call_count));
6635 LocalContext context;
6636 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6637 GenerateSomeGarbage();
6638 context->Global()->Set(v8_str("o"), fun->NewInstance());
6639 v8::Handle<Value> value = CompileRun(
6640 "o.foo = 17;"
6641 "var receiver = {};"
6642 "receiver.__proto__ = o;"
6643 "var result = 0;"
6644 "var saved_result = 0;"
6645 "for (var i = 0; i < 100; i++) {"
6646 " result = receiver.method(41);"
6647 " if (i == 50) {"
6648 " saved_result = result;"
6649 " receiver = {method: function(x) { return x - 1 }};"
6650 " }"
6651 "}");
6652 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6653 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6654 CHECK_GE(interceptor_call_count, 50);
6655}
6656
6657THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6658 int interceptor_call_count = 0;
6659 v8::HandleScope scope;
6660 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6661 v8::Handle<v8::FunctionTemplate> method_templ =
6662 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6663 v8_str("method_data"),
6664 v8::Signature::New(fun_templ));
6665 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6666 proto_templ->Set(v8_str("method"), method_templ);
6667 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6668 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6669 NULL, NULL, NULL, NULL,
6670 v8::External::Wrap(&interceptor_call_count));
6671 LocalContext context;
6672 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6673 GenerateSomeGarbage();
6674 context->Global()->Set(v8_str("o"), fun->NewInstance());
6675 v8::Handle<Value> value = CompileRun(
6676 "o.foo = 17;"
6677 "var receiver = {};"
6678 "receiver.__proto__ = o;"
6679 "var result = 0;"
6680 "var saved_result = 0;"
6681 "for (var i = 0; i < 100; i++) {"
6682 " result = receiver.method(41);"
6683 " if (i == 50) {"
6684 " saved_result = result;"
6685 " o.method = function(x) { return x - 1 };"
6686 " }"
6687 "}");
6688 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6689 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6690 CHECK_GE(interceptor_call_count, 50);
6691}
6692
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00006693THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
6694 int interceptor_call_count = 0;
6695 v8::HandleScope scope;
6696 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6697 v8::Handle<v8::FunctionTemplate> method_templ =
6698 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6699 v8_str("method_data"),
6700 v8::Signature::New(fun_templ));
6701 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6702 proto_templ->Set(v8_str("method"), method_templ);
6703 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6704 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6705 NULL, NULL, NULL, NULL,
6706 v8::External::Wrap(&interceptor_call_count));
6707 LocalContext context;
6708 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6709 GenerateSomeGarbage();
6710 context->Global()->Set(v8_str("o"), fun->NewInstance());
6711 v8::TryCatch try_catch;
6712 v8::Handle<Value> value = CompileRun(
6713 "o.foo = 17;"
6714 "var receiver = {};"
6715 "receiver.__proto__ = o;"
6716 "var result = 0;"
6717 "var saved_result = 0;"
6718 "for (var i = 0; i < 100; i++) {"
6719 " result = receiver.method(41);"
6720 " if (i == 50) {"
6721 " saved_result = result;"
6722 " receiver = 333;"
6723 " }"
6724 "}");
6725 CHECK(try_catch.HasCaught());
6726 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6727 try_catch.Exception()->ToString());
6728 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6729 CHECK_GE(interceptor_call_count, 50);
6730}
6731
ager@chromium.org5c838252010-02-19 08:53:10 +00006732THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6733 int interceptor_call_count = 0;
6734 v8::HandleScope scope;
6735 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6736 v8::Handle<v8::FunctionTemplate> method_templ =
6737 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6738 v8_str("method_data"),
6739 v8::Signature::New(fun_templ));
6740 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6741 proto_templ->Set(v8_str("method"), method_templ);
6742 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6743 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6744 NULL, NULL, NULL, NULL,
6745 v8::External::Wrap(&interceptor_call_count));
6746 LocalContext context;
6747 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6748 GenerateSomeGarbage();
6749 context->Global()->Set(v8_str("o"), fun->NewInstance());
6750 v8::TryCatch try_catch;
6751 v8::Handle<Value> value = CompileRun(
6752 "o.foo = 17;"
6753 "var receiver = {};"
6754 "receiver.__proto__ = o;"
6755 "var result = 0;"
6756 "var saved_result = 0;"
6757 "for (var i = 0; i < 100; i++) {"
6758 " result = receiver.method(41);"
6759 " if (i == 50) {"
6760 " saved_result = result;"
6761 " receiver = {method: receiver.method};"
6762 " }"
6763 "}");
6764 CHECK(try_catch.HasCaught());
6765 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
6766 try_catch.Exception()->ToString());
6767 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6768 CHECK_GE(interceptor_call_count, 50);
6769}
6770
6771THREADED_TEST(CallICFastApi_TrivialSignature) {
6772 v8::HandleScope scope;
6773 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6774 v8::Handle<v8::FunctionTemplate> method_templ =
6775 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6776 v8_str("method_data"),
6777 v8::Handle<v8::Signature>());
6778 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6779 proto_templ->Set(v8_str("method"), method_templ);
6780 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6781 LocalContext context;
6782 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6783 GenerateSomeGarbage();
6784 context->Global()->Set(v8_str("o"), fun->NewInstance());
6785 v8::Handle<Value> value = CompileRun(
6786 "var result = 0;"
6787 "for (var i = 0; i < 100; i++) {"
6788 " result = o.method(41);"
6789 "}");
6790
6791 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6792}
6793
6794THREADED_TEST(CallICFastApi_SimpleSignature) {
6795 v8::HandleScope scope;
6796 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6797 v8::Handle<v8::FunctionTemplate> method_templ =
6798 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6799 v8_str("method_data"),
6800 v8::Signature::New(fun_templ));
6801 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6802 proto_templ->Set(v8_str("method"), method_templ);
6803 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6804 LocalContext context;
6805 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6806 GenerateSomeGarbage();
6807 context->Global()->Set(v8_str("o"), fun->NewInstance());
6808 v8::Handle<Value> value = CompileRun(
6809 "o.foo = 17;"
6810 "var receiver = {};"
6811 "receiver.__proto__ = o;"
6812 "var result = 0;"
6813 "for (var i = 0; i < 100; i++) {"
6814 " result = receiver.method(41);"
6815 "}");
6816
6817 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6818}
6819
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00006820THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006821 v8::HandleScope scope;
6822 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6823 v8::Handle<v8::FunctionTemplate> method_templ =
6824 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6825 v8_str("method_data"),
6826 v8::Signature::New(fun_templ));
6827 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6828 proto_templ->Set(v8_str("method"), method_templ);
6829 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6830 LocalContext context;
6831 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6832 GenerateSomeGarbage();
6833 context->Global()->Set(v8_str("o"), fun->NewInstance());
6834 v8::Handle<Value> value = CompileRun(
6835 "o.foo = 17;"
6836 "var receiver = {};"
6837 "receiver.__proto__ = o;"
6838 "var result = 0;"
6839 "var saved_result = 0;"
6840 "for (var i = 0; i < 100; i++) {"
6841 " result = receiver.method(41);"
6842 " if (i == 50) {"
6843 " saved_result = result;"
6844 " receiver = {method: function(x) { return x - 1 }};"
6845 " }"
6846 "}");
6847 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6848 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6849}
6850
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00006851THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
6852 v8::HandleScope scope;
6853 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6854 v8::Handle<v8::FunctionTemplate> method_templ =
6855 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6856 v8_str("method_data"),
6857 v8::Signature::New(fun_templ));
6858 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6859 proto_templ->Set(v8_str("method"), method_templ);
6860 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6861 LocalContext context;
6862 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6863 GenerateSomeGarbage();
6864 context->Global()->Set(v8_str("o"), fun->NewInstance());
6865 v8::TryCatch try_catch;
6866 v8::Handle<Value> value = CompileRun(
6867 "o.foo = 17;"
6868 "var receiver = {};"
6869 "receiver.__proto__ = o;"
6870 "var result = 0;"
6871 "var saved_result = 0;"
6872 "for (var i = 0; i < 100; i++) {"
6873 " result = receiver.method(41);"
6874 " if (i == 50) {"
6875 " saved_result = result;"
6876 " receiver = 333;"
6877 " }"
6878 "}");
6879 CHECK(try_catch.HasCaught());
6880 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
6881 try_catch.Exception()->ToString());
6882 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6883}
6884
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006885
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006886static int interceptor_call_count = 0;
6887
6888static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
6889 const AccessorInfo& info) {
6890 ApiTestFuzzer::Fuzz();
6891 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
6892 return call_ic_function2;
6893 }
6894 return v8::Handle<Value>();
6895}
6896
6897
6898// This test should hit load and call ICs for the interceptor case.
6899// Once in a while, the interceptor will reply that a property was not
6900// found in which case we should get a reference error.
6901THREADED_TEST(InterceptorICReferenceErrors) {
6902 v8::HandleScope scope;
6903 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6904 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
6905 LocalContext context(0, templ, v8::Handle<Value>());
6906 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
6907 v8::Handle<Value> value = CompileRun(
6908 "function f() {"
6909 " for (var i = 0; i < 1000; i++) {"
6910 " try { x; } catch(e) { return true; }"
6911 " }"
6912 " return false;"
6913 "};"
6914 "f();");
6915 CHECK_EQ(true, value->BooleanValue());
6916 interceptor_call_count = 0;
6917 value = CompileRun(
6918 "function g() {"
6919 " for (var i = 0; i < 1000; i++) {"
6920 " try { x(42); } catch(e) { return true; }"
6921 " }"
6922 " return false;"
6923 "};"
6924 "g();");
6925 CHECK_EQ(true, value->BooleanValue());
6926}
6927
6928
6929static int interceptor_ic_exception_get_count = 0;
6930
6931static v8::Handle<Value> InterceptorICExceptionGetter(
6932 Local<String> name,
6933 const AccessorInfo& info) {
6934 ApiTestFuzzer::Fuzz();
6935 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
6936 return call_ic_function3;
6937 }
6938 if (interceptor_ic_exception_get_count == 20) {
6939 return v8::ThrowException(v8_num(42));
6940 }
6941 // Do not handle get for properties other than x.
6942 return v8::Handle<Value>();
6943}
6944
6945// Test interceptor load/call IC where the interceptor throws an
6946// exception once in a while.
6947THREADED_TEST(InterceptorICGetterExceptions) {
6948 interceptor_ic_exception_get_count = 0;
6949 v8::HandleScope scope;
6950 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6951 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
6952 LocalContext context(0, templ, v8::Handle<Value>());
6953 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
6954 v8::Handle<Value> value = CompileRun(
6955 "function f() {"
6956 " for (var i = 0; i < 100; i++) {"
6957 " try { x; } catch(e) { return true; }"
6958 " }"
6959 " return false;"
6960 "};"
6961 "f();");
6962 CHECK_EQ(true, value->BooleanValue());
6963 interceptor_ic_exception_get_count = 0;
6964 value = CompileRun(
6965 "function f() {"
6966 " for (var i = 0; i < 100; i++) {"
6967 " try { x(42); } catch(e) { return true; }"
6968 " }"
6969 " return false;"
6970 "};"
6971 "f();");
6972 CHECK_EQ(true, value->BooleanValue());
6973}
6974
6975
6976static int interceptor_ic_exception_set_count = 0;
6977
6978static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006979 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006980 ApiTestFuzzer::Fuzz();
6981 if (++interceptor_ic_exception_set_count > 20) {
6982 return v8::ThrowException(v8_num(42));
6983 }
6984 // Do not actually handle setting.
6985 return v8::Handle<Value>();
6986}
6987
6988// Test interceptor store IC where the interceptor throws an exception
6989// once in a while.
6990THREADED_TEST(InterceptorICSetterExceptions) {
6991 interceptor_ic_exception_set_count = 0;
6992 v8::HandleScope scope;
6993 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6994 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
6995 LocalContext context(0, templ, v8::Handle<Value>());
6996 v8::Handle<Value> value = CompileRun(
6997 "function f() {"
6998 " for (var i = 0; i < 100; i++) {"
6999 " try { x = 42; } catch(e) { return true; }"
7000 " }"
7001 " return false;"
7002 "};"
7003 "f();");
7004 CHECK_EQ(true, value->BooleanValue());
7005}
7006
7007
7008// Test that we ignore null interceptors.
7009THREADED_TEST(NullNamedInterceptor) {
7010 v8::HandleScope scope;
7011 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7012 templ->SetNamedPropertyHandler(0);
7013 LocalContext context;
7014 templ->Set("x", v8_num(42));
7015 v8::Handle<v8::Object> obj = templ->NewInstance();
7016 context->Global()->Set(v8_str("obj"), obj);
7017 v8::Handle<Value> value = CompileRun("obj.x");
7018 CHECK(value->IsInt32());
7019 CHECK_EQ(42, value->Int32Value());
7020}
7021
7022
7023// Test that we ignore null interceptors.
7024THREADED_TEST(NullIndexedInterceptor) {
7025 v8::HandleScope scope;
7026 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7027 templ->SetIndexedPropertyHandler(0);
7028 LocalContext context;
7029 templ->Set("42", v8_num(42));
7030 v8::Handle<v8::Object> obj = templ->NewInstance();
7031 context->Global()->Set(v8_str("obj"), obj);
7032 v8::Handle<Value> value = CompileRun("obj[42]");
7033 CHECK(value->IsInt32());
7034 CHECK_EQ(42, value->Int32Value());
7035}
7036
7037
7038static v8::Handle<Value> ParentGetter(Local<String> name,
7039 const AccessorInfo& info) {
7040 ApiTestFuzzer::Fuzz();
7041 return v8_num(1);
7042}
7043
7044
7045static v8::Handle<Value> ChildGetter(Local<String> name,
7046 const AccessorInfo& info) {
7047 ApiTestFuzzer::Fuzz();
7048 return v8_num(42);
7049}
7050
7051
7052THREADED_TEST(Overriding) {
7053 v8::HandleScope scope;
7054 LocalContext context;
7055
7056 // Parent template.
7057 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7058 Local<ObjectTemplate> parent_instance_templ =
7059 parent_templ->InstanceTemplate();
7060 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7061
7062 // Template that inherits from the parent template.
7063 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7064 Local<ObjectTemplate> child_instance_templ =
7065 child_templ->InstanceTemplate();
7066 child_templ->Inherit(parent_templ);
7067 // Override 'f'. The child version of 'f' should get called for child
7068 // instances.
7069 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7070 // Add 'g' twice. The 'g' added last should get called for instances.
7071 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7072 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7073
7074 // Add 'h' as an accessor to the proto template with ReadOnly attributes
7075 // so 'h' can be shadowed on the instance object.
7076 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7077 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7078 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7079
7080 // Add 'i' as an accessor to the instance template with ReadOnly attributes
7081 // but the attribute does not have effect because it is duplicated with
7082 // NULL setter.
7083 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7084 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7085
7086
7087
7088 // Instantiate the child template.
7089 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7090
7091 // Check that the child function overrides the parent one.
7092 context->Global()->Set(v8_str("o"), instance);
7093 Local<Value> value = v8_compile("o.f")->Run();
7094 // Check that the 'g' that was added last is hit.
7095 CHECK_EQ(42, value->Int32Value());
7096 value = v8_compile("o.g")->Run();
7097 CHECK_EQ(42, value->Int32Value());
7098
7099 // Check 'h' can be shadowed.
7100 value = v8_compile("o.h = 3; o.h")->Run();
7101 CHECK_EQ(3, value->Int32Value());
7102
7103 // Check 'i' is cannot be shadowed or changed.
7104 value = v8_compile("o.i = 3; o.i")->Run();
7105 CHECK_EQ(42, value->Int32Value());
7106}
7107
7108
7109static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7110 ApiTestFuzzer::Fuzz();
7111 if (args.IsConstructCall()) {
7112 return v8::Boolean::New(true);
7113 }
7114 return v8::Boolean::New(false);
7115}
7116
7117
7118THREADED_TEST(IsConstructCall) {
7119 v8::HandleScope scope;
7120
7121 // Function template with call handler.
7122 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7123 templ->SetCallHandler(IsConstructHandler);
7124
7125 LocalContext context;
7126
7127 context->Global()->Set(v8_str("f"), templ->GetFunction());
7128 Local<Value> value = v8_compile("f()")->Run();
7129 CHECK(!value->BooleanValue());
7130 value = v8_compile("new f()")->Run();
7131 CHECK(value->BooleanValue());
7132}
7133
7134
7135THREADED_TEST(ObjectProtoToString) {
7136 v8::HandleScope scope;
7137 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7138 templ->SetClassName(v8_str("MyClass"));
7139
7140 LocalContext context;
7141
7142 Local<String> customized_tostring = v8_str("customized toString");
7143
7144 // Replace Object.prototype.toString
7145 v8_compile("Object.prototype.toString = function() {"
7146 " return 'customized toString';"
7147 "}")->Run();
7148
7149 // Normal ToString call should call replaced Object.prototype.toString
7150 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7151 Local<String> value = instance->ToString();
7152 CHECK(value->IsString() && value->Equals(customized_tostring));
7153
7154 // ObjectProtoToString should not call replace toString function.
7155 value = instance->ObjectProtoToString();
7156 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7157
7158 // Check global
7159 value = context->Global()->ObjectProtoToString();
7160 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7161
7162 // Check ordinary object
7163 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007164 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007165 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7166}
7167
7168
7169bool ApiTestFuzzer::fuzzing_ = false;
7170v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
7171 v8::internal::OS::CreateSemaphore(0);
7172int ApiTestFuzzer::active_tests_;
7173int ApiTestFuzzer::tests_being_run_;
7174int ApiTestFuzzer::current_;
7175
7176
7177// We are in a callback and want to switch to another thread (if we
7178// are currently running the thread fuzzing test).
7179void ApiTestFuzzer::Fuzz() {
7180 if (!fuzzing_) return;
7181 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
7182 test->ContextSwitch();
7183}
7184
7185
7186// Let the next thread go. Since it is also waiting on the V8 lock it may
7187// not start immediately.
7188bool ApiTestFuzzer::NextThread() {
7189 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007190 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007191 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007192 if (kLogThreading)
7193 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007194 return false;
7195 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007196 if (kLogThreading) {
7197 printf("Switch from %s to %s\n",
7198 test_name,
7199 RegisterThreadedTest::nth(test_position)->name());
7200 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007201 current_ = test_position;
7202 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
7203 return true;
7204}
7205
7206
7207void ApiTestFuzzer::Run() {
7208 // When it is our turn...
7209 gate_->Wait();
7210 {
7211 // ... get the V8 lock and start running the test.
7212 v8::Locker locker;
7213 CallTest();
7214 }
7215 // This test finished.
7216 active_ = false;
7217 active_tests_--;
7218 // If it was the last then signal that fact.
7219 if (active_tests_ == 0) {
7220 all_tests_done_->Signal();
7221 } else {
7222 // Otherwise select a new test and start that.
7223 NextThread();
7224 }
7225}
7226
7227
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007228static unsigned linear_congruential_generator;
7229
7230
7231void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007232 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007233 fuzzing_ = true;
7234 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
7235 int end = (part == FIRST_PART)
7236 ? (RegisterThreadedTest::count() >> 1)
7237 : RegisterThreadedTest::count();
7238 active_tests_ = tests_being_run_ = end - start;
7239 for (int i = 0; i < tests_being_run_; i++) {
7240 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
7241 }
7242 for (int i = 0; i < active_tests_; i++) {
7243 RegisterThreadedTest::nth(i)->fuzzer_->Start();
7244 }
7245}
7246
7247
7248static void CallTestNumber(int test_number) {
7249 (RegisterThreadedTest::nth(test_number)->callback())();
7250}
7251
7252
7253void ApiTestFuzzer::RunAllTests() {
7254 // Set off the first test.
7255 current_ = -1;
7256 NextThread();
7257 // Wait till they are all done.
7258 all_tests_done_->Wait();
7259}
7260
7261
7262int ApiTestFuzzer::GetNextTestNumber() {
7263 int next_test;
7264 do {
7265 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7266 linear_congruential_generator *= 1664525u;
7267 linear_congruential_generator += 1013904223u;
7268 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7269 return next_test;
7270}
7271
7272
7273void ApiTestFuzzer::ContextSwitch() {
7274 // If the new thread is the same as the current thread there is nothing to do.
7275 if (NextThread()) {
7276 // Now it can start.
7277 v8::Unlocker unlocker;
7278 // Wait till someone starts us again.
7279 gate_->Wait();
7280 // And we're off.
7281 }
7282}
7283
7284
7285void ApiTestFuzzer::TearDown() {
7286 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00007287 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7288 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7289 if (fuzzer != NULL) fuzzer->Join();
7290 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007291}
7292
7293
7294// Lets not be needlessly self-referential.
7295TEST(Threading) {
7296 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7297 ApiTestFuzzer::RunAllTests();
7298 ApiTestFuzzer::TearDown();
7299}
7300
7301TEST(Threading2) {
7302 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7303 ApiTestFuzzer::RunAllTests();
7304 ApiTestFuzzer::TearDown();
7305}
7306
7307
7308void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007309 if (kLogThreading)
7310 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007311 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007312 if (kLogThreading)
7313 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007314}
7315
7316
7317static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007318 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007319 ApiTestFuzzer::Fuzz();
7320 v8::Unlocker unlocker;
7321 const char* code = "throw 7;";
7322 {
7323 v8::Locker nested_locker;
7324 v8::HandleScope scope;
7325 v8::Handle<Value> exception;
7326 { v8::TryCatch try_catch;
7327 v8::Handle<Value> value = CompileRun(code);
7328 CHECK(value.IsEmpty());
7329 CHECK(try_catch.HasCaught());
7330 // Make sure to wrap the exception in a new handle because
7331 // the handle returned from the TryCatch is destroyed
7332 // when the TryCatch is destroyed.
7333 exception = Local<Value>::New(try_catch.Exception());
7334 }
7335 return v8::ThrowException(exception);
7336 }
7337}
7338
7339
7340static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007341 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007342 ApiTestFuzzer::Fuzz();
7343 v8::Unlocker unlocker;
7344 const char* code = "throw 7;";
7345 {
7346 v8::Locker nested_locker;
7347 v8::HandleScope scope;
7348 v8::Handle<Value> value = CompileRun(code);
7349 CHECK(value.IsEmpty());
7350 return v8_str("foo");
7351 }
7352}
7353
7354
7355// These are locking tests that don't need to be run again
7356// as part of the locking aggregation tests.
7357TEST(NestedLockers) {
7358 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007359 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007360 v8::HandleScope scope;
7361 LocalContext env;
7362 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7363 Local<Function> fun = fun_templ->GetFunction();
7364 env->Global()->Set(v8_str("throw_in_js"), fun);
7365 Local<Script> script = v8_compile("(function () {"
7366 " try {"
7367 " throw_in_js();"
7368 " return 42;"
7369 " } catch (e) {"
7370 " return e * 13;"
7371 " }"
7372 "})();");
7373 CHECK_EQ(91, script->Run()->Int32Value());
7374}
7375
7376
7377// These are locking tests that don't need to be run again
7378// as part of the locking aggregation tests.
7379TEST(NestedLockersNoTryCatch) {
7380 v8::Locker locker;
7381 v8::HandleScope scope;
7382 LocalContext env;
7383 Local<v8::FunctionTemplate> fun_templ =
7384 v8::FunctionTemplate::New(ThrowInJSNoCatch);
7385 Local<Function> fun = fun_templ->GetFunction();
7386 env->Global()->Set(v8_str("throw_in_js"), fun);
7387 Local<Script> script = v8_compile("(function () {"
7388 " try {"
7389 " throw_in_js();"
7390 " return 42;"
7391 " } catch (e) {"
7392 " return e * 13;"
7393 " }"
7394 "})();");
7395 CHECK_EQ(91, script->Run()->Int32Value());
7396}
7397
7398
7399THREADED_TEST(RecursiveLocking) {
7400 v8::Locker locker;
7401 {
7402 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007403 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007404 }
7405}
7406
7407
7408static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7409 ApiTestFuzzer::Fuzz();
7410 v8::Unlocker unlocker;
7411 return v8::Undefined();
7412}
7413
7414
7415THREADED_TEST(LockUnlockLock) {
7416 {
7417 v8::Locker locker;
7418 v8::HandleScope scope;
7419 LocalContext env;
7420 Local<v8::FunctionTemplate> fun_templ =
7421 v8::FunctionTemplate::New(UnlockForAMoment);
7422 Local<Function> fun = fun_templ->GetFunction();
7423 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7424 Local<Script> script = v8_compile("(function () {"
7425 " unlock_for_a_moment();"
7426 " return 42;"
7427 "})();");
7428 CHECK_EQ(42, script->Run()->Int32Value());
7429 }
7430 {
7431 v8::Locker locker;
7432 v8::HandleScope scope;
7433 LocalContext env;
7434 Local<v8::FunctionTemplate> fun_templ =
7435 v8::FunctionTemplate::New(UnlockForAMoment);
7436 Local<Function> fun = fun_templ->GetFunction();
7437 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7438 Local<Script> script = v8_compile("(function () {"
7439 " unlock_for_a_moment();"
7440 " return 42;"
7441 "})();");
7442 CHECK_EQ(42, script->Run()->Int32Value());
7443 }
7444}
7445
7446
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007447static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007448 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007449 v8::internal::HeapIterator it;
7450 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7451 if (object->IsJSGlobalObject()) count++;
7452 return count;
7453}
7454
7455
7456static int GetSurvivingGlobalObjectsCount() {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007457 // We need to collect all garbage twice to be sure that everything
7458 // has been collected. This is because inline caches are cleared in
7459 // the first garbage collection but some of the maps have already
7460 // been marked at that point. Therefore some of the maps are not
7461 // collected until the second garbage collection.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007462 v8::internal::Heap::CollectAllGarbage(false);
7463 v8::internal::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007464 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007465#ifdef DEBUG
7466 if (count > 0) v8::internal::Heap::TracePathToGlobal();
7467#endif
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007468 return count;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007469}
7470
7471
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007472TEST(DontLeakGlobalObjects) {
7473 // Regression test for issues 1139850 and 1174891.
7474
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007475 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007476
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007477 int count = GetSurvivingGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007478
7479 for (int i = 0; i < 5; i++) {
7480 { v8::HandleScope scope;
7481 LocalContext context;
7482 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007483 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007484
7485 { v8::HandleScope scope;
7486 LocalContext context;
7487 v8_compile("Date")->Run();
7488 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007489 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007490
7491 { v8::HandleScope scope;
7492 LocalContext context;
7493 v8_compile("/aaa/")->Run();
7494 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007495 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007496
7497 { v8::HandleScope scope;
7498 const char* extension_list[] = { "v8/gc" };
7499 v8::ExtensionConfiguration extensions(1, extension_list);
7500 LocalContext context(&extensions);
7501 v8_compile("gc();")->Run();
7502 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007503 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007504 }
7505}
7506
7507
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007508v8::Persistent<v8::Object> some_object;
7509v8::Persistent<v8::Object> bad_handle;
7510
7511void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7512 v8::HandleScope scope;
7513 bad_handle = v8::Persistent<v8::Object>::New(some_object);
7514}
7515
7516
7517THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7518 LocalContext context;
7519
7520 v8::Persistent<v8::Object> handle1, handle2;
7521 {
7522 v8::HandleScope scope;
7523 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7524 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7525 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7526 }
7527 // Note: order is implementation dependent alas: currently
7528 // global handle nodes are processed by PostGarbageCollectionProcessing
7529 // in reverse allocation order, so if second allocated handle is deleted,
7530 // weak callback of the first handle would be able to 'reallocate' it.
7531 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7532 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007533 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007534}
7535
7536
7537v8::Persistent<v8::Object> to_be_disposed;
7538
7539void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7540 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007541 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007542}
7543
7544
7545THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7546 LocalContext context;
7547
7548 v8::Persistent<v8::Object> handle1, handle2;
7549 {
7550 v8::HandleScope scope;
7551 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7552 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7553 }
7554 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7555 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007556 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007557}
7558
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007559void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7560 handle.Dispose();
7561}
7562
7563void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7564 v8::HandleScope scope;
7565 v8::Persistent<v8::Object>::New(v8::Object::New());
7566}
7567
7568
7569THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
7570 LocalContext context;
7571
7572 v8::Persistent<v8::Object> handle1, handle2, handle3;
7573 {
7574 v8::HandleScope scope;
7575 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
7576 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7577 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7578 }
7579 handle2.MakeWeak(NULL, DisposingCallback);
7580 handle3.MakeWeak(NULL, HandleCreatingCallback);
7581 i::Heap::CollectAllGarbage(false);
7582}
7583
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007584
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007585THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007586 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007587
7588 const int nof = 2;
7589 const char* sources[nof] = {
7590 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
7591 "Object()"
7592 };
7593
7594 for (int i = 0; i < nof; i++) {
7595 const char* source = sources[i];
7596 { v8::HandleScope scope;
7597 LocalContext context;
7598 CompileRun(source);
7599 }
7600 { v8::HandleScope scope;
7601 LocalContext context;
7602 CompileRun(source);
7603 }
7604 }
7605}
7606
7607
7608static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
7609 v8::HandleScope inner;
7610 env->Enter();
7611 v8::Handle<Value> three = v8_num(3);
7612 v8::Handle<Value> value = inner.Close(three);
7613 env->Exit();
7614 return value;
7615}
7616
7617
7618THREADED_TEST(NestedHandleScopeAndContexts) {
7619 v8::HandleScope outer;
7620 v8::Persistent<Context> env = Context::New();
7621 env->Enter();
7622 v8::Handle<Value> value = NestedScope(env);
7623 v8::Handle<String> str = value->ToString();
7624 env->Exit();
7625 env.Dispose();
7626}
7627
7628
7629THREADED_TEST(ExternalAllocatedMemory) {
7630 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007631 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007632 const int kSize = 1024*1024;
7633 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
7634 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
7635}
7636
7637
7638THREADED_TEST(DisposeEnteredContext) {
7639 v8::HandleScope scope;
7640 LocalContext outer;
7641 { v8::Persistent<v8::Context> inner = v8::Context::New();
7642 inner->Enter();
7643 inner.Dispose();
7644 inner.Clear();
7645 inner->Exit();
7646 }
7647}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007648
7649
7650// Regression test for issue 54, object templates with internal fields
7651// but no accessors or interceptors did not get their internal field
7652// count set on instances.
7653THREADED_TEST(Regress54) {
7654 v8::HandleScope outer;
7655 LocalContext context;
7656 static v8::Persistent<v8::ObjectTemplate> templ;
7657 if (templ.IsEmpty()) {
7658 v8::HandleScope inner;
7659 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
7660 local->SetInternalFieldCount(1);
7661 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
7662 }
7663 v8::Handle<v8::Object> result = templ->NewInstance();
7664 CHECK_EQ(1, result->InternalFieldCount());
7665}
7666
7667
7668// If part of the threaded tests, this test makes ThreadingTest fail
7669// on mac.
7670TEST(CatchStackOverflow) {
7671 v8::HandleScope scope;
7672 LocalContext context;
7673 v8::TryCatch try_catch;
7674 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
7675 "function f() {"
7676 " return f();"
7677 "}"
7678 ""
7679 "f();"));
7680 v8::Handle<v8::Value> result = script->Run();
7681 CHECK(result.IsEmpty());
7682}
7683
7684
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007685static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
7686 const char* resource_name,
7687 int line_offset) {
7688 v8::HandleScope scope;
7689 v8::TryCatch try_catch;
7690 v8::Handle<v8::Value> result = script->Run();
7691 CHECK(result.IsEmpty());
7692 CHECK(try_catch.HasCaught());
7693 v8::Handle<v8::Message> message = try_catch.Message();
7694 CHECK(!message.IsEmpty());
7695 CHECK_EQ(10 + line_offset, message->GetLineNumber());
7696 CHECK_EQ(91, message->GetStartPosition());
7697 CHECK_EQ(92, message->GetEndPosition());
7698 CHECK_EQ(2, message->GetStartColumn());
7699 CHECK_EQ(3, message->GetEndColumn());
7700 v8::String::AsciiValue line(message->GetSourceLine());
7701 CHECK_EQ(" throw 'nirk';", *line);
7702 v8::String::AsciiValue name(message->GetScriptResourceName());
7703 CHECK_EQ(resource_name, *name);
7704}
7705
7706
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007707THREADED_TEST(TryCatchSourceInfo) {
7708 v8::HandleScope scope;
7709 LocalContext context;
7710 v8::Handle<v8::String> source = v8::String::New(
7711 "function Foo() {\n"
7712 " return Bar();\n"
7713 "}\n"
7714 "\n"
7715 "function Bar() {\n"
7716 " return Baz();\n"
7717 "}\n"
7718 "\n"
7719 "function Baz() {\n"
7720 " throw 'nirk';\n"
7721 "}\n"
7722 "\n"
7723 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007724
7725 const char* resource_name;
7726 v8::Handle<v8::Script> script;
7727 resource_name = "test.js";
7728 script = v8::Script::Compile(source, v8::String::New(resource_name));
7729 CheckTryCatchSourceInfo(script, resource_name, 0);
7730
7731 resource_name = "test1.js";
7732 v8::ScriptOrigin origin1(v8::String::New(resource_name));
7733 script = v8::Script::Compile(source, &origin1);
7734 CheckTryCatchSourceInfo(script, resource_name, 0);
7735
7736 resource_name = "test2.js";
7737 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
7738 script = v8::Script::Compile(source, &origin2);
7739 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007740}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007741
7742
7743THREADED_TEST(CompilationCache) {
7744 v8::HandleScope scope;
7745 LocalContext context;
7746 v8::Handle<v8::String> source0 = v8::String::New("1234");
7747 v8::Handle<v8::String> source1 = v8::String::New("1234");
7748 v8::Handle<v8::Script> script0 =
7749 v8::Script::Compile(source0, v8::String::New("test.js"));
7750 v8::Handle<v8::Script> script1 =
7751 v8::Script::Compile(source1, v8::String::New("test.js"));
7752 v8::Handle<v8::Script> script2 =
7753 v8::Script::Compile(source0); // different origin
7754 CHECK_EQ(1234, script0->Run()->Int32Value());
7755 CHECK_EQ(1234, script1->Run()->Int32Value());
7756 CHECK_EQ(1234, script2->Run()->Int32Value());
7757}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007758
7759
7760static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
7761 ApiTestFuzzer::Fuzz();
7762 return v8_num(42);
7763}
7764
7765
7766THREADED_TEST(CallbackFunctionName) {
7767 v8::HandleScope scope;
7768 LocalContext context;
7769 Local<ObjectTemplate> t = ObjectTemplate::New();
7770 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
7771 context->Global()->Set(v8_str("obj"), t->NewInstance());
7772 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
7773 CHECK(value->IsString());
7774 v8::String::AsciiValue name(value);
7775 CHECK_EQ("asdf", *name);
7776}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007777
7778
7779THREADED_TEST(DateAccess) {
7780 v8::HandleScope scope;
7781 LocalContext context;
7782 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
7783 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007784 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007785}
7786
7787
7788void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007789 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007790 v8::Handle<v8::Array> props = obj->GetPropertyNames();
7791 CHECK_EQ(elmc, props->Length());
7792 for (int i = 0; i < elmc; i++) {
7793 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
7794 CHECK_EQ(elmv[i], *elm);
7795 }
7796}
7797
7798
7799THREADED_TEST(PropertyEnumeration) {
7800 v8::HandleScope scope;
7801 LocalContext context;
7802 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
7803 "var result = [];"
7804 "result[0] = {};"
7805 "result[1] = {a: 1, b: 2};"
7806 "result[2] = [1, 2, 3];"
7807 "var proto = {x: 1, y: 2, z: 3};"
7808 "var x = { __proto__: proto, w: 0, z: 1 };"
7809 "result[3] = x;"
7810 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007811 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007812 CHECK_EQ(4, elms->Length());
7813 int elmc0 = 0;
7814 const char** elmv0 = NULL;
7815 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
7816 int elmc1 = 2;
7817 const char* elmv1[] = {"a", "b"};
7818 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
7819 int elmc2 = 3;
7820 const char* elmv2[] = {"0", "1", "2"};
7821 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
7822 int elmc3 = 4;
7823 const char* elmv3[] = {"w", "z", "x", "y"};
7824 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
7825}
ager@chromium.org870a0b62008-11-04 11:43:05 +00007826
7827
ager@chromium.org870a0b62008-11-04 11:43:05 +00007828static bool NamedSetAccessBlocker(Local<v8::Object> obj,
7829 Local<Value> name,
7830 v8::AccessType type,
7831 Local<Value> data) {
7832 return type != v8::ACCESS_SET;
7833}
7834
7835
7836static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
7837 uint32_t key,
7838 v8::AccessType type,
7839 Local<Value> data) {
7840 return type != v8::ACCESS_SET;
7841}
7842
7843
7844THREADED_TEST(DisableAccessChecksWhileConfiguring) {
7845 v8::HandleScope scope;
7846 LocalContext context;
7847 Local<ObjectTemplate> templ = ObjectTemplate::New();
7848 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7849 IndexedSetAccessBlocker);
7850 templ->Set(v8_str("x"), v8::True());
7851 Local<v8::Object> instance = templ->NewInstance();
7852 context->Global()->Set(v8_str("obj"), instance);
7853 Local<Value> value = CompileRun("obj.x");
7854 CHECK(value->BooleanValue());
7855}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007856
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007857
ager@chromium.org32912102009-01-16 10:38:43 +00007858static bool NamedGetAccessBlocker(Local<v8::Object> obj,
7859 Local<Value> name,
7860 v8::AccessType type,
7861 Local<Value> data) {
7862 return false;
7863}
7864
7865
7866static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
7867 uint32_t key,
7868 v8::AccessType type,
7869 Local<Value> data) {
7870 return false;
7871}
7872
7873
7874
7875THREADED_TEST(AccessChecksReenabledCorrectly) {
7876 v8::HandleScope scope;
7877 LocalContext context;
7878 Local<ObjectTemplate> templ = ObjectTemplate::New();
7879 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7880 IndexedGetAccessBlocker);
7881 templ->Set(v8_str("a"), v8_str("a"));
7882 // Add more than 8 (see kMaxFastProperties) properties
7883 // so that the constructor will force copying map.
7884 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007885 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00007886 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007887 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00007888 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007889 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00007890 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007891 buf[2] = k;
7892 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00007893 templ->Set(v8_str(buf), v8::Number::New(k));
7894 }
7895 }
7896 }
7897
7898 Local<v8::Object> instance_1 = templ->NewInstance();
7899 context->Global()->Set(v8_str("obj_1"), instance_1);
7900
7901 Local<Value> value_1 = CompileRun("obj_1.a");
7902 CHECK(value_1->IsUndefined());
7903
7904 Local<v8::Object> instance_2 = templ->NewInstance();
7905 context->Global()->Set(v8_str("obj_2"), instance_2);
7906
7907 Local<Value> value_2 = CompileRun("obj_2.a");
7908 CHECK(value_2->IsUndefined());
7909}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007910
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007911
ager@chromium.org8bb60582008-12-11 12:02:20 +00007912// This tests that access check information remains on the global
7913// object template when creating contexts.
7914THREADED_TEST(AccessControlRepeatedContextCreation) {
7915 v8::HandleScope handle_scope;
7916 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7917 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7918 IndexedSetAccessBlocker);
7919 i::Handle<i::ObjectTemplateInfo> internal_template =
7920 v8::Utils::OpenHandle(*global_template);
7921 CHECK(!internal_template->constructor()->IsUndefined());
7922 i::Handle<i::FunctionTemplateInfo> constructor(
7923 i::FunctionTemplateInfo::cast(internal_template->constructor()));
7924 CHECK(!constructor->access_check_info()->IsUndefined());
7925 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7926 CHECK(!constructor->access_check_info()->IsUndefined());
7927}
7928
7929
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007930THREADED_TEST(TurnOnAccessCheck) {
7931 v8::HandleScope handle_scope;
7932
7933 // Create an environment with access check to the global object disabled by
7934 // default.
7935 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7936 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7937 IndexedGetAccessBlocker,
7938 v8::Handle<v8::Value>(),
7939 false);
7940 v8::Persistent<Context> context = Context::New(NULL, global_template);
7941 Context::Scope context_scope(context);
7942
7943 // Set up a property and a number of functions.
7944 context->Global()->Set(v8_str("a"), v8_num(1));
7945 CompileRun("function f1() {return a;}"
7946 "function f2() {return a;}"
7947 "function g1() {return h();}"
7948 "function g2() {return h();}"
7949 "function h() {return 1;}");
7950 Local<Function> f1 =
7951 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
7952 Local<Function> f2 =
7953 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
7954 Local<Function> g1 =
7955 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
7956 Local<Function> g2 =
7957 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
7958 Local<Function> h =
7959 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
7960
7961 // Get the global object.
7962 v8::Handle<v8::Object> global = context->Global();
7963
7964 // Call f1 one time and f2 a number of times. This will ensure that f1 still
7965 // uses the runtime system to retreive property a whereas f2 uses global load
7966 // inline cache.
7967 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
7968 for (int i = 0; i < 4; i++) {
7969 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
7970 }
7971
7972 // Same for g1 and g2.
7973 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
7974 for (int i = 0; i < 4; i++) {
7975 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
7976 }
7977
7978 // Detach the global and turn on access check.
7979 context->DetachGlobal();
7980 context->Global()->TurnOnAccessCheck();
7981
7982 // Failing access check to property get results in undefined.
7983 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
7984 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
7985
7986 // Failing access check to function call results in exception.
7987 CHECK(g1->Call(global, 0, NULL).IsEmpty());
7988 CHECK(g2->Call(global, 0, NULL).IsEmpty());
7989
7990 // No failing access check when just returning a constant.
7991 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
7992}
7993
7994
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007995// This test verifies that pre-compilation (aka preparsing) can be called
7996// without initializing the whole VM. Thus we cannot run this test in a
7997// multi-threaded setup.
7998TEST(PreCompile) {
7999 // TODO(155): This test would break without the initialization of V8. This is
8000 // a workaround for now to make this test not fail.
8001 v8::V8::Initialize();
8002 const char *script = "function foo(a) { return a+1; }";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008003 v8::ScriptData *sd =
8004 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008005 CHECK_NE(sd->Length(), 0);
8006 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008007 CHECK(!sd->HasError());
8008 delete sd;
8009}
8010
8011
8012TEST(PreCompileWithError) {
8013 v8::V8::Initialize();
8014 const char *script = "function foo(a) { return 1 * * 2; }";
8015 v8::ScriptData *sd =
8016 v8::ScriptData::PreCompile(script, i::StrLength(script));
8017 CHECK(sd->HasError());
8018 delete sd;
8019}
8020
8021
8022TEST(Regress31661) {
8023 v8::V8::Initialize();
8024 const char *script = " The Definintive Guide";
8025 v8::ScriptData *sd =
8026 v8::ScriptData::PreCompile(script, i::StrLength(script));
8027 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008028 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008029}
8030
8031
8032// This tests that we do not allow dictionary load/call inline caches
8033// to use functions that have not yet been compiled. The potential
8034// problem of loading a function that has not yet been compiled can
8035// arise because we share code between contexts via the compilation
8036// cache.
8037THREADED_TEST(DictionaryICLoadedFunction) {
8038 v8::HandleScope scope;
8039 // Test LoadIC.
8040 for (int i = 0; i < 2; i++) {
8041 LocalContext context;
8042 context->Global()->Set(v8_str("tmp"), v8::True());
8043 context->Global()->Delete(v8_str("tmp"));
8044 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
8045 }
8046 // Test CallIC.
8047 for (int i = 0; i < 2; i++) {
8048 LocalContext context;
8049 context->Global()->Set(v8_str("tmp"), v8::True());
8050 context->Global()->Delete(v8_str("tmp"));
8051 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
8052 }
8053}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008054
8055
8056// Test that cross-context new calls use the context of the callee to
8057// create the new JavaScript object.
8058THREADED_TEST(CrossContextNew) {
8059 v8::HandleScope scope;
8060 v8::Persistent<Context> context0 = Context::New();
8061 v8::Persistent<Context> context1 = Context::New();
8062
8063 // Allow cross-domain access.
8064 Local<String> token = v8_str("<security token>");
8065 context0->SetSecurityToken(token);
8066 context1->SetSecurityToken(token);
8067
8068 // Set an 'x' property on the Object prototype and define a
8069 // constructor function in context0.
8070 context0->Enter();
8071 CompileRun("Object.prototype.x = 42; function C() {};");
8072 context0->Exit();
8073
8074 // Call the constructor function from context0 and check that the
8075 // result has the 'x' property.
8076 context1->Enter();
8077 context1->Global()->Set(v8_str("other"), context0->Global());
8078 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
8079 CHECK(value->IsInt32());
8080 CHECK_EQ(42, value->Int32Value());
8081 context1->Exit();
8082
8083 // Dispose the contexts to allow them to be garbage collected.
8084 context0.Dispose();
8085 context1.Dispose();
8086}
ager@chromium.org381abbb2009-02-25 13:23:22 +00008087
8088
8089class RegExpInterruptTest {
8090 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008091 RegExpInterruptTest() : block_(NULL) {}
8092 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00008093 void RunTest() {
8094 block_ = i::OS::CreateSemaphore(0);
8095 gc_count_ = 0;
8096 gc_during_regexp_ = 0;
8097 regexp_success_ = false;
8098 gc_success_ = false;
8099 GCThread gc_thread(this);
8100 gc_thread.Start();
8101 v8::Locker::StartPreemption(1);
8102
8103 LongRunningRegExp();
8104 {
8105 v8::Unlocker unlock;
8106 gc_thread.Join();
8107 }
8108 v8::Locker::StopPreemption();
8109 CHECK(regexp_success_);
8110 CHECK(gc_success_);
8111 }
8112 private:
8113 // Number of garbage collections required.
8114 static const int kRequiredGCs = 5;
8115
8116 class GCThread : public i::Thread {
8117 public:
8118 explicit GCThread(RegExpInterruptTest* test)
8119 : test_(test) {}
8120 virtual void Run() {
8121 test_->CollectGarbage();
8122 }
8123 private:
8124 RegExpInterruptTest* test_;
8125 };
8126
8127 void CollectGarbage() {
8128 block_->Wait();
8129 while (gc_during_regexp_ < kRequiredGCs) {
8130 {
8131 v8::Locker lock;
8132 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008133 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00008134 gc_count_++;
8135 }
8136 i::OS::Sleep(1);
8137 }
8138 gc_success_ = true;
8139 }
8140
8141 void LongRunningRegExp() {
8142 block_->Signal(); // Enable garbage collection thread on next preemption.
8143 int rounds = 0;
8144 while (gc_during_regexp_ < kRequiredGCs) {
8145 int gc_before = gc_count_;
8146 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008147 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00008148 const char* c_source =
8149 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8150 ".exec('aaaaaaaaaaaaaaab') === null";
8151 Local<String> source = String::New(c_source);
8152 Local<Script> script = Script::Compile(source);
8153 Local<Value> result = script->Run();
8154 if (!result->BooleanValue()) {
8155 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
8156 return;
8157 }
8158 }
8159 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008160 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00008161 const char* c_source =
8162 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8163 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
8164 Local<String> source = String::New(c_source);
8165 Local<Script> script = Script::Compile(source);
8166 Local<Value> result = script->Run();
8167 if (!result->BooleanValue()) {
8168 gc_during_regexp_ = kRequiredGCs;
8169 return;
8170 }
8171 }
8172 int gc_after = gc_count_;
8173 gc_during_regexp_ += gc_after - gc_before;
8174 rounds++;
8175 i::OS::Sleep(1);
8176 }
8177 regexp_success_ = true;
8178 }
8179
8180 i::Semaphore* block_;
8181 int gc_count_;
8182 int gc_during_regexp_;
8183 bool regexp_success_;
8184 bool gc_success_;
8185};
8186
8187
8188// Test that a regular expression execution can be interrupted and
8189// survive a garbage collection.
8190TEST(RegExpInterruption) {
8191 v8::Locker lock;
8192 v8::V8::Initialize();
8193 v8::HandleScope scope;
8194 Local<Context> local_env;
8195 {
8196 LocalContext env;
8197 local_env = env.local();
8198 }
8199
8200 // Local context should still be live.
8201 CHECK(!local_env.IsEmpty());
8202 local_env->Enter();
8203
8204 // Should complete without problems.
8205 RegExpInterruptTest().RunTest();
8206
8207 local_env->Exit();
8208}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008209
8210
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008211class ApplyInterruptTest {
8212 public:
8213 ApplyInterruptTest() : block_(NULL) {}
8214 ~ApplyInterruptTest() { delete block_; }
8215 void RunTest() {
8216 block_ = i::OS::CreateSemaphore(0);
8217 gc_count_ = 0;
8218 gc_during_apply_ = 0;
8219 apply_success_ = false;
8220 gc_success_ = false;
8221 GCThread gc_thread(this);
8222 gc_thread.Start();
8223 v8::Locker::StartPreemption(1);
8224
8225 LongRunningApply();
8226 {
8227 v8::Unlocker unlock;
8228 gc_thread.Join();
8229 }
8230 v8::Locker::StopPreemption();
8231 CHECK(apply_success_);
8232 CHECK(gc_success_);
8233 }
8234 private:
8235 // Number of garbage collections required.
8236 static const int kRequiredGCs = 2;
8237
8238 class GCThread : public i::Thread {
8239 public:
8240 explicit GCThread(ApplyInterruptTest* test)
8241 : test_(test) {}
8242 virtual void Run() {
8243 test_->CollectGarbage();
8244 }
8245 private:
8246 ApplyInterruptTest* test_;
8247 };
8248
8249 void CollectGarbage() {
8250 block_->Wait();
8251 while (gc_during_apply_ < kRequiredGCs) {
8252 {
8253 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008254 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008255 gc_count_++;
8256 }
8257 i::OS::Sleep(1);
8258 }
8259 gc_success_ = true;
8260 }
8261
8262 void LongRunningApply() {
8263 block_->Signal();
8264 int rounds = 0;
8265 while (gc_during_apply_ < kRequiredGCs) {
8266 int gc_before = gc_count_;
8267 {
8268 const char* c_source =
8269 "function do_very_little(bar) {"
8270 " this.foo = bar;"
8271 "}"
8272 "for (var i = 0; i < 100000; i++) {"
8273 " do_very_little.apply(this, ['bar']);"
8274 "}";
8275 Local<String> source = String::New(c_source);
8276 Local<Script> script = Script::Compile(source);
8277 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00008278 // Check that no exception was thrown.
8279 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008280 }
8281 int gc_after = gc_count_;
8282 gc_during_apply_ += gc_after - gc_before;
8283 rounds++;
8284 }
8285 apply_success_ = true;
8286 }
8287
8288 i::Semaphore* block_;
8289 int gc_count_;
8290 int gc_during_apply_;
8291 bool apply_success_;
8292 bool gc_success_;
8293};
8294
8295
8296// Test that nothing bad happens if we get a preemption just when we were
8297// about to do an apply().
8298TEST(ApplyInterruption) {
8299 v8::Locker lock;
8300 v8::V8::Initialize();
8301 v8::HandleScope scope;
8302 Local<Context> local_env;
8303 {
8304 LocalContext env;
8305 local_env = env.local();
8306 }
8307
8308 // Local context should still be live.
8309 CHECK(!local_env.IsEmpty());
8310 local_env->Enter();
8311
8312 // Should complete without problems.
8313 ApplyInterruptTest().RunTest();
8314
8315 local_env->Exit();
8316}
8317
8318
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008319// Verify that we can clone an object
8320TEST(ObjectClone) {
8321 v8::HandleScope scope;
8322 LocalContext env;
8323
8324 const char* sample =
8325 "var rv = {};" \
8326 "rv.alpha = 'hello';" \
8327 "rv.beta = 123;" \
8328 "rv;";
8329
8330 // Create an object, verify basics.
8331 Local<Value> val = CompileRun(sample);
8332 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008333 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008334 obj->Set(v8_str("gamma"), v8_str("cloneme"));
8335
8336 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8337 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8338 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8339
8340 // Clone it.
8341 Local<v8::Object> clone = obj->Clone();
8342 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8343 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8344 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8345
8346 // Set a property on the clone, verify each object.
8347 clone->Set(v8_str("beta"), v8::Integer::New(456));
8348 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8349 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8350}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008351
8352
ager@chromium.org5ec48922009-05-05 07:25:34 +00008353class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8354 public:
8355 explicit AsciiVectorResource(i::Vector<const char> vector)
8356 : data_(vector) {}
8357 virtual ~AsciiVectorResource() {}
8358 virtual size_t length() const { return data_.length(); }
8359 virtual const char* data() const { return data_.start(); }
8360 private:
8361 i::Vector<const char> data_;
8362};
8363
8364
8365class UC16VectorResource : public v8::String::ExternalStringResource {
8366 public:
8367 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8368 : data_(vector) {}
8369 virtual ~UC16VectorResource() {}
8370 virtual size_t length() const { return data_.length(); }
8371 virtual const i::uc16* data() const { return data_.start(); }
8372 private:
8373 i::Vector<const i::uc16> data_;
8374};
8375
8376
8377static void MorphAString(i::String* string,
8378 AsciiVectorResource* ascii_resource,
8379 UC16VectorResource* uc16_resource) {
8380 CHECK(i::StringShape(string).IsExternal());
8381 if (string->IsAsciiRepresentation()) {
8382 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008383 CHECK(string->map() == i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008384 // Morph external string to be TwoByte string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008385 string->set_map(i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008386 i::ExternalTwoByteString* morphed =
8387 i::ExternalTwoByteString::cast(string);
8388 morphed->set_resource(uc16_resource);
8389 } else {
8390 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008391 CHECK(string->map() == i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008392 // Morph external string to be ASCII string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008393 string->set_map(i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008394 i::ExternalAsciiString* morphed =
8395 i::ExternalAsciiString::cast(string);
8396 morphed->set_resource(ascii_resource);
8397 }
8398}
8399
8400
8401// Test that we can still flatten a string if the components it is built up
8402// from have been turned into 16 bit strings in the mean time.
8403THREADED_TEST(MorphCompositeStringTest) {
8404 const char* c_string = "Now is the time for all good men"
8405 " to come to the aid of the party";
8406 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8407 {
8408 v8::HandleScope scope;
8409 LocalContext env;
8410 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008411 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00008412 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008413 i::Vector<const uint16_t>(two_byte_string,
8414 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00008415
8416 Local<String> lhs(v8::Utils::ToLocal(
8417 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8418 Local<String> rhs(v8::Utils::ToLocal(
8419 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8420
8421 env->Global()->Set(v8_str("lhs"), lhs);
8422 env->Global()->Set(v8_str("rhs"), rhs);
8423
8424 CompileRun(
8425 "var cons = lhs + rhs;"
8426 "var slice = lhs.substring(1, lhs.length - 1);"
8427 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8428
8429 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8430 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8431
8432 // Now do some stuff to make sure the strings are flattened, etc.
8433 CompileRun(
8434 "/[^a-z]/.test(cons);"
8435 "/[^a-z]/.test(slice);"
8436 "/[^a-z]/.test(slice_on_cons);");
8437 const char* expected_cons =
8438 "Now is the time for all good men to come to the aid of the party"
8439 "Now is the time for all good men to come to the aid of the party";
8440 const char* expected_slice =
8441 "ow is the time for all good men to come to the aid of the part";
8442 const char* expected_slice_on_cons =
8443 "ow is the time for all good men to come to the aid of the party"
8444 "Now is the time for all good men to come to the aid of the part";
8445 CHECK_EQ(String::New(expected_cons),
8446 env->Global()->Get(v8_str("cons")));
8447 CHECK_EQ(String::New(expected_slice),
8448 env->Global()->Get(v8_str("slice")));
8449 CHECK_EQ(String::New(expected_slice_on_cons),
8450 env->Global()->Get(v8_str("slice_on_cons")));
8451 }
8452}
8453
8454
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008455TEST(CompileExternalTwoByteSource) {
8456 v8::HandleScope scope;
8457 LocalContext context;
8458
8459 // This is a very short list of sources, which currently is to check for a
8460 // regression caused by r2703.
8461 const char* ascii_sources[] = {
8462 "0.5",
8463 "-0.5", // This mainly testes PushBack in the Scanner.
8464 "--0.5", // This mainly testes PushBack in the Scanner.
8465 NULL
8466 };
8467
8468 // Compile the sources as external two byte strings.
8469 for (int i = 0; ascii_sources[i] != NULL; i++) {
8470 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8471 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008472 i::Vector<const uint16_t>(two_byte_string,
8473 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008474 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8475 v8::Script::Compile(source);
8476 }
8477}
8478
8479
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008480class RegExpStringModificationTest {
8481 public:
8482 RegExpStringModificationTest()
8483 : block_(i::OS::CreateSemaphore(0)),
8484 morphs_(0),
8485 morphs_during_regexp_(0),
8486 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8487 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
8488 ~RegExpStringModificationTest() { delete block_; }
8489 void RunTest() {
8490 regexp_success_ = false;
8491 morph_success_ = false;
8492
8493 // Initialize the contents of two_byte_content_ to be a uc16 representation
8494 // of "aaaaaaaaaaaaaab".
8495 for (int i = 0; i < 14; i++) {
8496 two_byte_content_[i] = 'a';
8497 }
8498 two_byte_content_[14] = 'b';
8499
8500 // Create the input string for the regexp - the one we are going to change
8501 // properties of.
8502 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8503
8504 // Inject the input as a global variable.
8505 i::Handle<i::String> input_name =
8506 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
8507 i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
8508
8509
8510 MorphThread morph_thread(this);
8511 morph_thread.Start();
8512 v8::Locker::StartPreemption(1);
8513 LongRunningRegExp();
8514 {
8515 v8::Unlocker unlock;
8516 morph_thread.Join();
8517 }
8518 v8::Locker::StopPreemption();
8519 CHECK(regexp_success_);
8520 CHECK(morph_success_);
8521 }
8522 private:
8523
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008524 // Number of string modifications required.
8525 static const int kRequiredModifications = 5;
8526 static const int kMaxModifications = 100;
8527
8528 class MorphThread : public i::Thread {
8529 public:
8530 explicit MorphThread(RegExpStringModificationTest* test)
8531 : test_(test) {}
8532 virtual void Run() {
8533 test_->MorphString();
8534 }
8535 private:
8536 RegExpStringModificationTest* test_;
8537 };
8538
8539 void MorphString() {
8540 block_->Wait();
8541 while (morphs_during_regexp_ < kRequiredModifications &&
8542 morphs_ < kMaxModifications) {
8543 {
8544 v8::Locker lock;
8545 // Swap string between ascii and two-byte representation.
8546 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008547 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008548 morphs_++;
8549 }
8550 i::OS::Sleep(1);
8551 }
8552 morph_success_ = true;
8553 }
8554
8555 void LongRunningRegExp() {
8556 block_->Signal(); // Enable morphing thread on next preemption.
8557 while (morphs_during_regexp_ < kRequiredModifications &&
8558 morphs_ < kMaxModifications) {
8559 int morphs_before = morphs_;
8560 {
8561 // Match 15-30 "a"'s against 14 and a "b".
8562 const char* c_source =
8563 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8564 ".exec(input) === null";
8565 Local<String> source = String::New(c_source);
8566 Local<Script> script = Script::Compile(source);
8567 Local<Value> result = script->Run();
8568 CHECK(result->IsTrue());
8569 }
8570 int morphs_after = morphs_;
8571 morphs_during_regexp_ += morphs_after - morphs_before;
8572 }
8573 regexp_success_ = true;
8574 }
8575
8576 i::uc16 two_byte_content_[15];
8577 i::Semaphore* block_;
8578 int morphs_;
8579 int morphs_during_regexp_;
8580 bool regexp_success_;
8581 bool morph_success_;
8582 i::Handle<i::String> input_;
8583 AsciiVectorResource ascii_resource_;
8584 UC16VectorResource uc16_resource_;
8585};
8586
8587
8588// Test that a regular expression execution can be interrupted and
8589// the string changed without failing.
8590TEST(RegExpStringModification) {
8591 v8::Locker lock;
8592 v8::V8::Initialize();
8593 v8::HandleScope scope;
8594 Local<Context> local_env;
8595 {
8596 LocalContext env;
8597 local_env = env.local();
8598 }
8599
8600 // Local context should still be live.
8601 CHECK(!local_env.IsEmpty());
8602 local_env->Enter();
8603
8604 // Should complete without problems.
8605 RegExpStringModificationTest().RunTest();
8606
8607 local_env->Exit();
8608}
8609
8610
8611// Test that we can set a property on the global object even if there
8612// is a read-only property in the prototype chain.
8613TEST(ReadOnlyPropertyInGlobalProto) {
8614 v8::HandleScope scope;
8615 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8616 LocalContext context(0, templ);
8617 v8::Handle<v8::Object> global = context->Global();
8618 v8::Handle<v8::Object> global_proto =
8619 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
8620 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
8621 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
8622 // Check without 'eval' or 'with'.
8623 v8::Handle<v8::Value> res =
8624 CompileRun("function f() { x = 42; return x; }; f()");
8625 // Check with 'eval'.
8626 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
8627 CHECK_EQ(v8::Integer::New(42), res);
8628 // Check with 'with'.
8629 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
8630 CHECK_EQ(v8::Integer::New(42), res);
8631}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008632
8633static int force_set_set_count = 0;
8634static int force_set_get_count = 0;
8635bool pass_on_get = false;
8636
8637static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
8638 const v8::AccessorInfo& info) {
8639 force_set_get_count++;
8640 if (pass_on_get) {
8641 return v8::Handle<v8::Value>();
8642 } else {
8643 return v8::Int32::New(3);
8644 }
8645}
8646
8647static void ForceSetSetter(v8::Local<v8::String> name,
8648 v8::Local<v8::Value> value,
8649 const v8::AccessorInfo& info) {
8650 force_set_set_count++;
8651}
8652
8653static v8::Handle<v8::Value> ForceSetInterceptSetter(
8654 v8::Local<v8::String> name,
8655 v8::Local<v8::Value> value,
8656 const v8::AccessorInfo& info) {
8657 force_set_set_count++;
8658 return v8::Undefined();
8659}
8660
8661TEST(ForceSet) {
8662 force_set_get_count = 0;
8663 force_set_set_count = 0;
8664 pass_on_get = false;
8665
8666 v8::HandleScope scope;
8667 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8668 v8::Handle<v8::String> access_property = v8::String::New("a");
8669 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
8670 LocalContext context(NULL, templ);
8671 v8::Handle<v8::Object> global = context->Global();
8672
8673 // Ordinary properties
8674 v8::Handle<v8::String> simple_property = v8::String::New("p");
8675 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
8676 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8677 // This should fail because the property is read-only
8678 global->Set(simple_property, v8::Int32::New(5));
8679 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8680 // This should succeed even though the property is read-only
8681 global->ForceSet(simple_property, v8::Int32::New(6));
8682 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
8683
8684 // Accessors
8685 CHECK_EQ(0, force_set_set_count);
8686 CHECK_EQ(0, force_set_get_count);
8687 CHECK_EQ(3, global->Get(access_property)->Int32Value());
8688 // CHECK_EQ the property shouldn't override it, just call the setter
8689 // which in this case does nothing.
8690 global->Set(access_property, v8::Int32::New(7));
8691 CHECK_EQ(3, global->Get(access_property)->Int32Value());
8692 CHECK_EQ(1, force_set_set_count);
8693 CHECK_EQ(2, force_set_get_count);
8694 // Forcing the property to be set should override the accessor without
8695 // calling it
8696 global->ForceSet(access_property, v8::Int32::New(8));
8697 CHECK_EQ(8, global->Get(access_property)->Int32Value());
8698 CHECK_EQ(1, force_set_set_count);
8699 CHECK_EQ(2, force_set_get_count);
8700}
8701
8702TEST(ForceSetWithInterceptor) {
8703 force_set_get_count = 0;
8704 force_set_set_count = 0;
8705 pass_on_get = false;
8706
8707 v8::HandleScope scope;
8708 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8709 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
8710 LocalContext context(NULL, templ);
8711 v8::Handle<v8::Object> global = context->Global();
8712
8713 v8::Handle<v8::String> some_property = v8::String::New("a");
8714 CHECK_EQ(0, force_set_set_count);
8715 CHECK_EQ(0, force_set_get_count);
8716 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8717 // Setting the property shouldn't override it, just call the setter
8718 // which in this case does nothing.
8719 global->Set(some_property, v8::Int32::New(7));
8720 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8721 CHECK_EQ(1, force_set_set_count);
8722 CHECK_EQ(2, force_set_get_count);
8723 // Getting the property when the interceptor returns an empty handle
8724 // should yield undefined, since the property isn't present on the
8725 // object itself yet.
8726 pass_on_get = true;
8727 CHECK(global->Get(some_property)->IsUndefined());
8728 CHECK_EQ(1, force_set_set_count);
8729 CHECK_EQ(3, force_set_get_count);
8730 // Forcing the property to be set should cause the value to be
8731 // set locally without calling the interceptor.
8732 global->ForceSet(some_property, v8::Int32::New(8));
8733 CHECK_EQ(8, global->Get(some_property)->Int32Value());
8734 CHECK_EQ(1, force_set_set_count);
8735 CHECK_EQ(4, force_set_get_count);
8736 // Reenabling the interceptor should cause it to take precedence over
8737 // the property
8738 pass_on_get = false;
8739 CHECK_EQ(3, global->Get(some_property)->Int32Value());
8740 CHECK_EQ(1, force_set_set_count);
8741 CHECK_EQ(5, force_set_get_count);
8742 // The interceptor should also work for other properties
8743 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
8744 CHECK_EQ(1, force_set_set_count);
8745 CHECK_EQ(6, force_set_get_count);
8746}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00008747
8748
ager@chromium.orge2902be2009-06-08 12:21:35 +00008749THREADED_TEST(ForceDelete) {
8750 v8::HandleScope scope;
8751 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8752 LocalContext context(NULL, templ);
8753 v8::Handle<v8::Object> global = context->Global();
8754
8755 // Ordinary properties
8756 v8::Handle<v8::String> simple_property = v8::String::New("p");
8757 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
8758 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8759 // This should fail because the property is dont-delete.
8760 CHECK(!global->Delete(simple_property));
8761 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8762 // This should succeed even though the property is dont-delete.
8763 CHECK(global->ForceDelete(simple_property));
8764 CHECK(global->Get(simple_property)->IsUndefined());
8765}
8766
8767
8768static int force_delete_interceptor_count = 0;
8769static bool pass_on_delete = false;
8770
8771
8772static v8::Handle<v8::Boolean> ForceDeleteDeleter(
8773 v8::Local<v8::String> name,
8774 const v8::AccessorInfo& info) {
8775 force_delete_interceptor_count++;
8776 if (pass_on_delete) {
8777 return v8::Handle<v8::Boolean>();
8778 } else {
8779 return v8::True();
8780 }
8781}
8782
8783
8784THREADED_TEST(ForceDeleteWithInterceptor) {
8785 force_delete_interceptor_count = 0;
8786 pass_on_delete = false;
8787
8788 v8::HandleScope scope;
8789 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8790 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
8791 LocalContext context(NULL, templ);
8792 v8::Handle<v8::Object> global = context->Global();
8793
8794 v8::Handle<v8::String> some_property = v8::String::New("a");
8795 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
8796
8797 // Deleting a property should get intercepted and nothing should
8798 // happen.
8799 CHECK_EQ(0, force_delete_interceptor_count);
8800 CHECK(global->Delete(some_property));
8801 CHECK_EQ(1, force_delete_interceptor_count);
8802 CHECK_EQ(42, global->Get(some_property)->Int32Value());
8803 // Deleting the property when the interceptor returns an empty
8804 // handle should not delete the property since it is DontDelete.
8805 pass_on_delete = true;
8806 CHECK(!global->Delete(some_property));
8807 CHECK_EQ(2, force_delete_interceptor_count);
8808 CHECK_EQ(42, global->Get(some_property)->Int32Value());
8809 // Forcing the property to be deleted should delete the value
8810 // without calling the interceptor.
8811 CHECK(global->ForceDelete(some_property));
8812 CHECK(global->Get(some_property)->IsUndefined());
8813 CHECK_EQ(2, force_delete_interceptor_count);
8814}
8815
8816
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008817// Make sure that forcing a delete invalidates any IC stubs, so we
8818// don't read the hole value.
8819THREADED_TEST(ForceDeleteIC) {
8820 v8::HandleScope scope;
8821 LocalContext context;
8822 // Create a DontDelete variable on the global object.
8823 CompileRun("this.__proto__ = { foo: 'horse' };"
8824 "var foo = 'fish';"
8825 "function f() { return foo.length; }");
8826 // Initialize the IC for foo in f.
8827 CompileRun("for (var i = 0; i < 4; i++) f();");
8828 // Make sure the value of foo is correct before the deletion.
8829 CHECK_EQ(4, CompileRun("f()")->Int32Value());
8830 // Force the deletion of foo.
8831 CHECK(context->Global()->ForceDelete(v8_str("foo")));
8832 // Make sure the value for foo is read from the prototype, and that
8833 // we don't get in trouble with reading the deleted cell value
8834 // sentinel.
8835 CHECK_EQ(5, CompileRun("f()")->Int32Value());
8836}
8837
8838
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00008839v8::Persistent<Context> calling_context0;
8840v8::Persistent<Context> calling_context1;
8841v8::Persistent<Context> calling_context2;
8842
8843
8844// Check that the call to the callback is initiated in
8845// calling_context2, the directly calling context is calling_context1
8846// and the callback itself is in calling_context0.
8847static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
8848 ApiTestFuzzer::Fuzz();
8849 CHECK(Context::GetCurrent() == calling_context0);
8850 CHECK(Context::GetCalling() == calling_context1);
8851 CHECK(Context::GetEntered() == calling_context2);
8852 return v8::Integer::New(42);
8853}
8854
8855
8856THREADED_TEST(GetCallingContext) {
8857 v8::HandleScope scope;
8858
8859 calling_context0 = Context::New();
8860 calling_context1 = Context::New();
8861 calling_context2 = Context::New();
8862
8863 // Allow cross-domain access.
8864 Local<String> token = v8_str("<security token>");
8865 calling_context0->SetSecurityToken(token);
8866 calling_context1->SetSecurityToken(token);
8867 calling_context2->SetSecurityToken(token);
8868
8869 // Create an object with a C++ callback in context0.
8870 calling_context0->Enter();
8871 Local<v8::FunctionTemplate> callback_templ =
8872 v8::FunctionTemplate::New(GetCallingContextCallback);
8873 calling_context0->Global()->Set(v8_str("callback"),
8874 callback_templ->GetFunction());
8875 calling_context0->Exit();
8876
8877 // Expose context0 in context1 and setup a function that calls the
8878 // callback function.
8879 calling_context1->Enter();
8880 calling_context1->Global()->Set(v8_str("context0"),
8881 calling_context0->Global());
8882 CompileRun("function f() { context0.callback() }");
8883 calling_context1->Exit();
8884
8885 // Expose context1 in context2 and call the callback function in
8886 // context0 indirectly through f in context1.
8887 calling_context2->Enter();
8888 calling_context2->Global()->Set(v8_str("context1"),
8889 calling_context1->Global());
8890 CompileRun("context1.f()");
8891 calling_context2->Exit();
8892
8893 // Dispose the contexts to allow them to be garbage collected.
8894 calling_context0.Dispose();
8895 calling_context1.Dispose();
8896 calling_context2.Dispose();
8897 calling_context0.Clear();
8898 calling_context1.Clear();
8899 calling_context2.Clear();
8900}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008901
8902
8903// Check that a variable declaration with no explicit initialization
8904// value does not shadow an existing property in the prototype chain.
8905//
8906// This is consistent with Firefox and Safari.
8907//
8908// See http://crbug.com/12548.
8909THREADED_TEST(InitGlobalVarInProtoChain) {
8910 v8::HandleScope scope;
8911 LocalContext context;
8912 // Introduce a variable in the prototype chain.
8913 CompileRun("__proto__.x = 42");
8914 v8::Handle<v8::Value> result = CompileRun("var x; x");
8915 CHECK(!result->IsUndefined());
8916 CHECK_EQ(42, result->Int32Value());
8917}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008918
8919
8920// Regression test for issue 398.
8921// If a function is added to an object, creating a constant function
8922// field, and the result is cloned, replacing the constant function on the
8923// original should not affect the clone.
8924// See http://code.google.com/p/v8/issues/detail?id=398
8925THREADED_TEST(ReplaceConstantFunction) {
8926 v8::HandleScope scope;
8927 LocalContext context;
8928 v8::Handle<v8::Object> obj = v8::Object::New();
8929 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
8930 v8::Handle<v8::String> foo_string = v8::String::New("foo");
8931 obj->Set(foo_string, func_templ->GetFunction());
8932 v8::Handle<v8::Object> obj_clone = obj->Clone();
8933 obj_clone->Set(foo_string, v8::String::New("Hello"));
8934 CHECK(!obj->Get(foo_string)->IsUndefined());
8935}
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008936
8937
8938// Regression test for http://crbug.com/16276.
8939THREADED_TEST(Regress16276) {
8940 v8::HandleScope scope;
8941 LocalContext context;
8942 // Force the IC in f to be a dictionary load IC.
8943 CompileRun("function f(obj) { return obj.x; }\n"
8944 "var obj = { x: { foo: 42 }, y: 87 };\n"
8945 "var x = obj.x;\n"
8946 "delete obj.y;\n"
8947 "for (var i = 0; i < 5; i++) f(obj);");
8948 // Detach the global object to make 'this' refer directly to the
8949 // global object (not the proxy), and make sure that the dictionary
8950 // load IC doesn't mess up loading directly from the global object.
8951 context->DetachGlobal();
8952 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
8953}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008954
8955
8956THREADED_TEST(PixelArray) {
8957 v8::HandleScope scope;
8958 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008959 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008960 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
8961 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
8962 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008963 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008964 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008965 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008966 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008967 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008968 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008969 CHECK_EQ(i % 256, pixels->get(i));
8970 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008971 }
8972
8973 v8::Handle<v8::Object> obj = v8::Object::New();
8974 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
8975 // Set the elements to be the pixels.
8976 // jsobj->set_elements(*pixels);
8977 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
8978 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
8979 obj->Set(v8_str("field"), v8::Int32::New(1503));
8980 context->Global()->Set(v8_str("pixels"), obj);
8981 v8::Handle<v8::Value> result = CompileRun("pixels.field");
8982 CHECK_EQ(1503, result->Int32Value());
8983 result = CompileRun("pixels[1]");
8984 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +00008985
8986 result = CompileRun("var sum = 0;"
8987 "for (var i = 0; i < 8; i++) {"
8988 " sum += pixels[i] = pixels[i] = -i;"
8989 "}"
8990 "sum;");
8991 CHECK_EQ(-28, result->Int32Value());
8992
8993 result = CompileRun("var sum = 0;"
8994 "for (var i = 0; i < 8; i++) {"
8995 " sum += pixels[i] = pixels[i] = 0;"
8996 "}"
8997 "sum;");
8998 CHECK_EQ(0, result->Int32Value());
8999
9000 result = CompileRun("var sum = 0;"
9001 "for (var i = 0; i < 8; i++) {"
9002 " sum += pixels[i] = pixels[i] = 255;"
9003 "}"
9004 "sum;");
9005 CHECK_EQ(8 * 255, result->Int32Value());
9006
9007 result = CompileRun("var sum = 0;"
9008 "for (var i = 0; i < 8; i++) {"
9009 " sum += pixels[i] = pixels[i] = 256 + i;"
9010 "}"
9011 "sum;");
9012 CHECK_EQ(2076, result->Int32Value());
9013
9014 result = CompileRun("var sum = 0;"
9015 "for (var i = 0; i < 8; i++) {"
9016 " sum += pixels[i] = pixels[i] = i;"
9017 "}"
9018 "sum;");
9019 CHECK_EQ(28, result->Int32Value());
9020
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009021 result = CompileRun("var sum = 0;"
9022 "for (var i = 0; i < 8; i++) {"
9023 " sum += pixels[i];"
9024 "}"
9025 "sum;");
9026 CHECK_EQ(28, result->Int32Value());
9027
9028 i::Handle<i::Smi> value(i::Smi::FromInt(2));
9029 i::SetElement(jsobj, 1, value);
9030 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
9031 *value.location() = i::Smi::FromInt(256);
9032 i::SetElement(jsobj, 1, value);
9033 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
9034 *value.location() = i::Smi::FromInt(-1);
9035 i::SetElement(jsobj, 1, value);
9036 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9037
9038 result = CompileRun("for (var i = 0; i < 8; i++) {"
9039 " pixels[i] = (i * 65) - 109;"
9040 "}"
9041 "pixels[1] + pixels[6];");
9042 CHECK_EQ(255, result->Int32Value());
9043 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9044 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
9045 CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
9046 CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
9047 CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
9048 CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
9049 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
9050 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
9051 result = CompileRun("var sum = 0;"
9052 "for (var i = 0; i < 8; i++) {"
9053 " sum += pixels[i];"
9054 "}"
9055 "sum;");
9056 CHECK_EQ(984, result->Int32Value());
9057
9058 result = CompileRun("for (var i = 0; i < 8; i++) {"
9059 " pixels[i] = (i * 1.1);"
9060 "}"
9061 "pixels[1] + pixels[6];");
9062 CHECK_EQ(8, result->Int32Value());
9063 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
9064 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
9065 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
9066 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
9067 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
9068 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
9069 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
9070 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
9071
9072 result = CompileRun("for (var i = 0; i < 8; i++) {"
9073 " pixels[7] = undefined;"
9074 "}"
9075 "pixels[7];");
9076 CHECK_EQ(0, result->Int32Value());
9077 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
9078
9079 result = CompileRun("for (var i = 0; i < 8; i++) {"
9080 " pixels[6] = '2.3';"
9081 "}"
9082 "pixels[6];");
9083 CHECK_EQ(2, result->Int32Value());
9084 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
9085
9086 result = CompileRun("for (var i = 0; i < 8; i++) {"
9087 " pixels[5] = NaN;"
9088 "}"
9089 "pixels[5];");
9090 CHECK_EQ(0, result->Int32Value());
9091 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9092
9093 result = CompileRun("for (var i = 0; i < 8; i++) {"
9094 " pixels[8] = Infinity;"
9095 "}"
9096 "pixels[8];");
9097 CHECK_EQ(255, result->Int32Value());
9098 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
9099
9100 result = CompileRun("for (var i = 0; i < 8; i++) {"
9101 " pixels[9] = -Infinity;"
9102 "}"
9103 "pixels[9];");
9104 CHECK_EQ(0, result->Int32Value());
9105 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
9106
9107 result = CompileRun("pixels[3] = 33;"
9108 "delete pixels[3];"
9109 "pixels[3];");
9110 CHECK_EQ(33, result->Int32Value());
9111
9112 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
9113 "pixels[2] = 12; pixels[3] = 13;"
9114 "pixels.__defineGetter__('2',"
9115 "function() { return 120; });"
9116 "pixels[2];");
9117 CHECK_EQ(12, result->Int32Value());
9118
9119 result = CompileRun("var js_array = new Array(40);"
9120 "js_array[0] = 77;"
9121 "js_array;");
9122 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9123
9124 result = CompileRun("pixels[1] = 23;"
9125 "pixels.__proto__ = [];"
9126 "js_array.__proto__ = pixels;"
9127 "js_array.concat(pixels);");
9128 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9129 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9130
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +00009131 result = CompileRun("pixels[1] = 23;");
9132 CHECK_EQ(23, result->Int32Value());
9133
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009134 // Test for index greater than 255. Regression test for:
9135 // http://code.google.com/p/chromium/issues/detail?id=26337.
9136 result = CompileRun("pixels[256] = 255;");
9137 CHECK_EQ(255, result->Int32Value());
9138 result = CompileRun("var i = 0;"
9139 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
9140 "i");
9141 CHECK_EQ(255, result->Int32Value());
9142
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009143 free(pixel_data);
9144}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009145
ager@chromium.org96c75b52009-08-26 09:13:16 +00009146
ager@chromium.org3811b432009-10-28 14:53:37 +00009147template <class ExternalArrayClass, class ElementType>
9148static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
9149 int64_t low,
9150 int64_t high) {
9151 v8::HandleScope scope;
9152 LocalContext context;
9153 const int kElementCount = 40;
9154 int element_size = 0;
9155 switch (array_type) {
9156 case v8::kExternalByteArray:
9157 case v8::kExternalUnsignedByteArray:
9158 element_size = 1;
9159 break;
9160 case v8::kExternalShortArray:
9161 case v8::kExternalUnsignedShortArray:
9162 element_size = 2;
9163 break;
9164 case v8::kExternalIntArray:
9165 case v8::kExternalUnsignedIntArray:
9166 case v8::kExternalFloatArray:
9167 element_size = 4;
9168 break;
9169 default:
9170 UNREACHABLE();
9171 break;
9172 }
9173 ElementType* array_data =
9174 static_cast<ElementType*>(malloc(kElementCount * element_size));
9175 i::Handle<ExternalArrayClass> array =
9176 i::Handle<ExternalArrayClass>::cast(
9177 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
9178 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9179 for (int i = 0; i < kElementCount; i++) {
9180 array->set(i, static_cast<ElementType>(i));
9181 }
9182 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9183 for (int i = 0; i < kElementCount; i++) {
9184 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
9185 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
9186 }
9187
9188 v8::Handle<v8::Object> obj = v8::Object::New();
9189 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
9190 // Set the elements to be the external array.
9191 obj->SetIndexedPropertiesToExternalArrayData(array_data,
9192 array_type,
9193 kElementCount);
9194 CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
9195 obj->Set(v8_str("field"), v8::Int32::New(1503));
9196 context->Global()->Set(v8_str("ext_array"), obj);
9197 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
9198 CHECK_EQ(1503, result->Int32Value());
9199 result = CompileRun("ext_array[1]");
9200 CHECK_EQ(1, result->Int32Value());
9201
9202 // Check pass through of assigned smis
9203 result = CompileRun("var sum = 0;"
9204 "for (var i = 0; i < 8; i++) {"
9205 " sum += ext_array[i] = ext_array[i] = -i;"
9206 "}"
9207 "sum;");
9208 CHECK_EQ(-28, result->Int32Value());
9209
9210 // Check assigned smis
9211 result = CompileRun("for (var i = 0; i < 8; i++) {"
9212 " ext_array[i] = i;"
9213 "}"
9214 "var sum = 0;"
9215 "for (var i = 0; i < 8; i++) {"
9216 " sum += ext_array[i];"
9217 "}"
9218 "sum;");
9219 CHECK_EQ(28, result->Int32Value());
9220
9221 // Check assigned smis in reverse order
9222 result = CompileRun("for (var i = 8; --i >= 0; ) {"
9223 " ext_array[i] = i;"
9224 "}"
9225 "var sum = 0;"
9226 "for (var i = 0; i < 8; i++) {"
9227 " sum += ext_array[i];"
9228 "}"
9229 "sum;");
9230 CHECK_EQ(28, result->Int32Value());
9231
9232 // Check pass through of assigned HeapNumbers
9233 result = CompileRun("var sum = 0;"
9234 "for (var i = 0; i < 16; i+=2) {"
9235 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
9236 "}"
9237 "sum;");
9238 CHECK_EQ(-28, result->Int32Value());
9239
9240 // Check assigned HeapNumbers
9241 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
9242 " ext_array[i] = (i * 0.5);"
9243 "}"
9244 "var sum = 0;"
9245 "for (var i = 0; i < 16; i+=2) {"
9246 " sum += ext_array[i];"
9247 "}"
9248 "sum;");
9249 CHECK_EQ(28, result->Int32Value());
9250
9251 // Check assigned HeapNumbers in reverse order
9252 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9253 " ext_array[i] = (i * 0.5);"
9254 "}"
9255 "var sum = 0;"
9256 "for (var i = 0; i < 16; i+=2) {"
9257 " sum += ext_array[i];"
9258 "}"
9259 "sum;");
9260 CHECK_EQ(28, result->Int32Value());
9261
9262 i::ScopedVector<char> test_buf(1024);
9263
9264 // Check legal boundary conditions.
9265 // The repeated loads and stores ensure the ICs are exercised.
9266 const char* boundary_program =
9267 "var res = 0;"
9268 "for (var i = 0; i < 16; i++) {"
9269 " ext_array[i] = %lld;"
9270 " if (i > 8) {"
9271 " res = ext_array[i];"
9272 " }"
9273 "}"
9274 "res;";
9275 i::OS::SNPrintF(test_buf,
9276 boundary_program,
9277 low);
9278 result = CompileRun(test_buf.start());
9279 CHECK_EQ(low, result->IntegerValue());
9280
9281 i::OS::SNPrintF(test_buf,
9282 boundary_program,
9283 high);
9284 result = CompileRun(test_buf.start());
9285 CHECK_EQ(high, result->IntegerValue());
9286
9287 // Check misprediction of type in IC.
9288 result = CompileRun("var tmp_array = ext_array;"
9289 "var sum = 0;"
9290 "for (var i = 0; i < 8; i++) {"
9291 " tmp_array[i] = i;"
9292 " sum += tmp_array[i];"
9293 " if (i == 4) {"
9294 " tmp_array = {};"
9295 " }"
9296 "}"
9297 "sum;");
9298 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
9299 CHECK_EQ(28, result->Int32Value());
9300
9301 // Make sure out-of-range loads do not throw.
9302 i::OS::SNPrintF(test_buf,
9303 "var caught_exception = false;"
9304 "try {"
9305 " ext_array[%d];"
9306 "} catch (e) {"
9307 " caught_exception = true;"
9308 "}"
9309 "caught_exception;",
9310 kElementCount);
9311 result = CompileRun(test_buf.start());
9312 CHECK_EQ(false, result->BooleanValue());
9313
9314 // Make sure out-of-range stores do not throw.
9315 i::OS::SNPrintF(test_buf,
9316 "var caught_exception = false;"
9317 "try {"
9318 " ext_array[%d] = 1;"
9319 "} catch (e) {"
9320 " caught_exception = true;"
9321 "}"
9322 "caught_exception;",
9323 kElementCount);
9324 result = CompileRun(test_buf.start());
9325 CHECK_EQ(false, result->BooleanValue());
9326
9327 // Check other boundary conditions, values and operations.
9328 result = CompileRun("for (var i = 0; i < 8; i++) {"
9329 " ext_array[7] = undefined;"
9330 "}"
9331 "ext_array[7];");
9332 CHECK_EQ(0, result->Int32Value());
9333 CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9334
9335 result = CompileRun("for (var i = 0; i < 8; i++) {"
9336 " ext_array[6] = '2.3';"
9337 "}"
9338 "ext_array[6];");
9339 CHECK_EQ(2, result->Int32Value());
9340 CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9341
9342 if (array_type != v8::kExternalFloatArray) {
9343 // Though the specification doesn't state it, be explicit about
9344 // converting NaNs and +/-Infinity to zero.
9345 result = CompileRun("for (var i = 0; i < 8; i++) {"
9346 " ext_array[i] = 5;"
9347 "}"
9348 "for (var i = 0; i < 8; i++) {"
9349 " ext_array[i] = NaN;"
9350 "}"
9351 "ext_array[5];");
9352 CHECK_EQ(0, result->Int32Value());
9353 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9354
9355 result = CompileRun("for (var i = 0; i < 8; i++) {"
9356 " ext_array[i] = 5;"
9357 "}"
9358 "for (var i = 0; i < 8; i++) {"
9359 " ext_array[i] = Infinity;"
9360 "}"
9361 "ext_array[5];");
9362 CHECK_EQ(0, result->Int32Value());
9363 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9364
9365 result = CompileRun("for (var i = 0; i < 8; i++) {"
9366 " ext_array[i] = 5;"
9367 "}"
9368 "for (var i = 0; i < 8; i++) {"
9369 " ext_array[i] = -Infinity;"
9370 "}"
9371 "ext_array[5];");
9372 CHECK_EQ(0, result->Int32Value());
9373 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9374 }
9375
9376 result = CompileRun("ext_array[3] = 33;"
9377 "delete ext_array[3];"
9378 "ext_array[3];");
9379 CHECK_EQ(33, result->Int32Value());
9380
9381 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9382 "ext_array[2] = 12; ext_array[3] = 13;"
9383 "ext_array.__defineGetter__('2',"
9384 "function() { return 120; });"
9385 "ext_array[2];");
9386 CHECK_EQ(12, result->Int32Value());
9387
9388 result = CompileRun("var js_array = new Array(40);"
9389 "js_array[0] = 77;"
9390 "js_array;");
9391 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9392
9393 result = CompileRun("ext_array[1] = 23;"
9394 "ext_array.__proto__ = [];"
9395 "js_array.__proto__ = ext_array;"
9396 "js_array.concat(ext_array);");
9397 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9398 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9399
9400 result = CompileRun("ext_array[1] = 23;");
9401 CHECK_EQ(23, result->Int32Value());
9402
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009403 // Test more complex manipulations which cause eax to contain values
9404 // that won't be completely overwritten by loads from the arrays.
9405 // This catches bugs in the instructions used for the KeyedLoadIC
9406 // for byte and word types.
9407 {
9408 const int kXSize = 300;
9409 const int kYSize = 300;
9410 const int kLargeElementCount = kXSize * kYSize * 4;
9411 ElementType* large_array_data =
9412 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9413 i::Handle<ExternalArrayClass> large_array =
9414 i::Handle<ExternalArrayClass>::cast(
9415 i::Factory::NewExternalArray(kLargeElementCount,
9416 array_type,
9417 array_data));
9418 v8::Handle<v8::Object> large_obj = v8::Object::New();
9419 // Set the elements to be the external array.
9420 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9421 array_type,
9422 kLargeElementCount);
9423 context->Global()->Set(v8_str("large_array"), large_obj);
9424 // Initialize contents of a few rows.
9425 for (int x = 0; x < 300; x++) {
9426 int row = 0;
9427 int offset = row * 300 * 4;
9428 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9429 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9430 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9431 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9432 row = 150;
9433 offset = row * 300 * 4;
9434 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9435 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9436 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9437 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9438 row = 298;
9439 offset = row * 300 * 4;
9440 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9441 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9442 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9443 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9444 }
9445 // The goal of the code below is to make "offset" large enough
9446 // that the computation of the index (which goes into eax) has
9447 // high bits set which will not be overwritten by a byte or short
9448 // load.
9449 result = CompileRun("var failed = false;"
9450 "var offset = 0;"
9451 "for (var i = 0; i < 300; i++) {"
9452 " if (large_array[4 * i] != 127 ||"
9453 " large_array[4 * i + 1] != 0 ||"
9454 " large_array[4 * i + 2] != 0 ||"
9455 " large_array[4 * i + 3] != 127) {"
9456 " failed = true;"
9457 " }"
9458 "}"
9459 "offset = 150 * 300 * 4;"
9460 "for (var i = 0; i < 300; i++) {"
9461 " if (large_array[offset + 4 * i] != 127 ||"
9462 " large_array[offset + 4 * i + 1] != 0 ||"
9463 " large_array[offset + 4 * i + 2] != 0 ||"
9464 " large_array[offset + 4 * i + 3] != 127) {"
9465 " failed = true;"
9466 " }"
9467 "}"
9468 "offset = 298 * 300 * 4;"
9469 "for (var i = 0; i < 300; i++) {"
9470 " if (large_array[offset + 4 * i] != 127 ||"
9471 " large_array[offset + 4 * i + 1] != 0 ||"
9472 " large_array[offset + 4 * i + 2] != 0 ||"
9473 " large_array[offset + 4 * i + 3] != 127) {"
9474 " failed = true;"
9475 " }"
9476 "}"
9477 "!failed;");
9478 CHECK_EQ(true, result->BooleanValue());
9479 free(large_array_data);
9480 }
9481
ager@chromium.org3811b432009-10-28 14:53:37 +00009482 free(array_data);
9483}
9484
9485
9486THREADED_TEST(ExternalByteArray) {
9487 ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
9488 v8::kExternalByteArray,
9489 -128,
9490 127);
9491}
9492
9493
9494THREADED_TEST(ExternalUnsignedByteArray) {
9495 ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
9496 v8::kExternalUnsignedByteArray,
9497 0,
9498 255);
9499}
9500
9501
9502THREADED_TEST(ExternalShortArray) {
9503 ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
9504 v8::kExternalShortArray,
9505 -32768,
9506 32767);
9507}
9508
9509
9510THREADED_TEST(ExternalUnsignedShortArray) {
9511 ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
9512 v8::kExternalUnsignedShortArray,
9513 0,
9514 65535);
9515}
9516
9517
9518THREADED_TEST(ExternalIntArray) {
9519 ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
9520 v8::kExternalIntArray,
9521 INT_MIN, // -2147483648
9522 INT_MAX); // 2147483647
9523}
9524
9525
9526THREADED_TEST(ExternalUnsignedIntArray) {
9527 ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
9528 v8::kExternalUnsignedIntArray,
9529 0,
9530 UINT_MAX); // 4294967295
9531}
9532
9533
9534THREADED_TEST(ExternalFloatArray) {
9535 ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
9536 v8::kExternalFloatArray,
9537 -500,
9538 500);
9539}
9540
9541
9542THREADED_TEST(ExternalArrays) {
9543 TestExternalByteArray();
9544 TestExternalUnsignedByteArray();
9545 TestExternalShortArray();
9546 TestExternalUnsignedShortArray();
9547 TestExternalIntArray();
9548 TestExternalUnsignedIntArray();
9549 TestExternalFloatArray();
9550}
9551
9552
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009553THREADED_TEST(ScriptContextDependence) {
9554 v8::HandleScope scope;
9555 LocalContext c1;
9556 const char *source = "foo";
9557 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
9558 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
9559 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
9560 CHECK_EQ(dep->Run()->Int32Value(), 100);
9561 CHECK_EQ(indep->Run()->Int32Value(), 100);
9562 LocalContext c2;
9563 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
9564 CHECK_EQ(dep->Run()->Int32Value(), 100);
9565 CHECK_EQ(indep->Run()->Int32Value(), 101);
9566}
9567
ager@chromium.org96c75b52009-08-26 09:13:16 +00009568
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009569THREADED_TEST(StackTrace) {
9570 v8::HandleScope scope;
9571 LocalContext context;
9572 v8::TryCatch try_catch;
9573 const char *source = "function foo() { FAIL.FAIL; }; foo();";
9574 v8::Handle<v8::String> src = v8::String::New(source);
9575 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
9576 v8::Script::New(src, origin)->Run();
9577 CHECK(try_catch.HasCaught());
9578 v8::String::Utf8Value stack(try_catch.StackTrace());
9579 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
9580}
ager@chromium.org96c75b52009-08-26 09:13:16 +00009581
9582
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009583// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +00009584THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009585 bool rv = false;
9586 for (int i = 0; i < 100; i++) {
9587 rv = v8::V8::IdleNotification();
9588 if (rv)
9589 break;
9590 }
9591 CHECK(rv == true);
9592}
9593
9594
9595static uint32_t* stack_limit;
9596
9597static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
9598 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
9599 return v8::Undefined();
9600}
9601
9602
9603// Uses the address of a local variable to determine the stack top now.
9604// Given a size, returns an address that is that far from the current
9605// top of stack.
9606static uint32_t* ComputeStackLimit(uint32_t size) {
9607 uint32_t* answer = &size - (size / sizeof(size));
9608 // If the size is very large and the stack is very near the bottom of
9609 // memory then the calculation above may wrap around and give an address
9610 // that is above the (downwards-growing) stack. In that case we return
9611 // a very low address.
9612 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
9613 return answer;
9614}
9615
9616
9617TEST(SetResourceConstraints) {
9618 static const int K = 1024;
9619 uint32_t* set_limit = ComputeStackLimit(128 * K);
9620
9621 // Set stack limit.
9622 v8::ResourceConstraints constraints;
9623 constraints.set_stack_limit(set_limit);
9624 CHECK(v8::SetResourceConstraints(&constraints));
9625
9626 // Execute a script.
9627 v8::HandleScope scope;
9628 LocalContext env;
9629 Local<v8::FunctionTemplate> fun_templ =
9630 v8::FunctionTemplate::New(GetStackLimitCallback);
9631 Local<Function> fun = fun_templ->GetFunction();
9632 env->Global()->Set(v8_str("get_stack_limit"), fun);
9633 CompileRun("get_stack_limit();");
9634
9635 CHECK(stack_limit == set_limit);
9636}
9637
9638
9639TEST(SetResourceConstraintsInThread) {
9640 uint32_t* set_limit;
9641 {
9642 v8::Locker locker;
9643 static const int K = 1024;
9644 set_limit = ComputeStackLimit(128 * K);
9645
9646 // Set stack limit.
9647 v8::ResourceConstraints constraints;
9648 constraints.set_stack_limit(set_limit);
9649 CHECK(v8::SetResourceConstraints(&constraints));
9650
9651 // Execute a script.
9652 v8::HandleScope scope;
9653 LocalContext env;
9654 Local<v8::FunctionTemplate> fun_templ =
9655 v8::FunctionTemplate::New(GetStackLimitCallback);
9656 Local<Function> fun = fun_templ->GetFunction();
9657 env->Global()->Set(v8_str("get_stack_limit"), fun);
9658 CompileRun("get_stack_limit();");
9659
9660 CHECK(stack_limit == set_limit);
9661 }
9662 {
9663 v8::Locker locker;
9664 CHECK(stack_limit == set_limit);
9665 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00009666}
ager@chromium.org3811b432009-10-28 14:53:37 +00009667
9668
9669THREADED_TEST(GetHeapStatistics) {
9670 v8::HandleScope scope;
9671 LocalContext c1;
9672 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009673 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
9674 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +00009675 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009676 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
9677 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +00009678}
9679
9680
9681static double DoubleFromBits(uint64_t value) {
9682 double target;
9683#ifdef BIG_ENDIAN_FLOATING_POINT
9684 const int kIntSize = 4;
9685 // Somebody swapped the lower and higher half of doubles.
9686 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9687 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9688#else
9689 memcpy(&target, &value, sizeof(target));
9690#endif
9691 return target;
9692}
9693
9694
9695static uint64_t DoubleToBits(double value) {
9696 uint64_t target;
9697#ifdef BIG_ENDIAN_FLOATING_POINT
9698 const int kIntSize = 4;
9699 // Somebody swapped the lower and higher half of doubles.
9700 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9701 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9702#else
9703 memcpy(&target, &value, sizeof(target));
9704#endif
9705 return target;
9706}
9707
9708
9709static double DoubleToDateTime(double input) {
9710 double date_limit = 864e13;
9711 if (IsNaN(input) || input < -date_limit || input > date_limit) {
9712 return i::OS::nan_value();
9713 }
9714 return (input < 0) ? -(floor(-input)) : floor(input);
9715}
9716
9717// We don't have a consistent way to write 64-bit constants syntactically, so we
9718// split them into two 32-bit constants and combine them programmatically.
9719static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
9720 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
9721}
9722
9723
9724THREADED_TEST(QuietSignalingNaNs) {
9725 v8::HandleScope scope;
9726 LocalContext context;
9727 v8::TryCatch try_catch;
9728
9729 // Special double values.
9730 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
9731 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
9732 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
9733 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
9734 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
9735 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
9736 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
9737
9738 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
9739 // on either side of the epoch.
9740 double date_limit = 864e13;
9741
9742 double test_values[] = {
9743 snan,
9744 qnan,
9745 infinity,
9746 max_normal,
9747 date_limit + 1,
9748 date_limit,
9749 min_normal,
9750 max_denormal,
9751 min_denormal,
9752 0,
9753 -0,
9754 -min_denormal,
9755 -max_denormal,
9756 -min_normal,
9757 -date_limit,
9758 -date_limit - 1,
9759 -max_normal,
9760 -infinity,
9761 -qnan,
9762 -snan
9763 };
9764 int num_test_values = 20;
9765
9766 for (int i = 0; i < num_test_values; i++) {
9767 double test_value = test_values[i];
9768
9769 // Check that Number::New preserves non-NaNs and quiets SNaNs.
9770 v8::Handle<v8::Value> number = v8::Number::New(test_value);
9771 double stored_number = number->NumberValue();
9772 if (!IsNaN(test_value)) {
9773 CHECK_EQ(test_value, stored_number);
9774 } else {
9775 uint64_t stored_bits = DoubleToBits(stored_number);
9776 // Check if quiet nan (bits 51..62 all set).
9777 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9778 }
9779
9780 // Check that Date::New preserves non-NaNs in the date range and
9781 // quiets SNaNs.
9782 v8::Handle<v8::Value> date = v8::Date::New(test_value);
9783 double expected_stored_date = DoubleToDateTime(test_value);
9784 double stored_date = date->NumberValue();
9785 if (!IsNaN(expected_stored_date)) {
9786 CHECK_EQ(expected_stored_date, stored_date);
9787 } else {
9788 uint64_t stored_bits = DoubleToBits(stored_date);
9789 // Check if quiet nan (bits 51..62 all set).
9790 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9791 }
9792 }
9793}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +00009794
9795
9796static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
9797 v8::HandleScope scope;
9798 v8::TryCatch tc;
9799 v8::Handle<v8::String> str = args[0]->ToString();
9800 if (tc.HasCaught())
9801 return tc.ReThrow();
9802 return v8::Undefined();
9803}
9804
9805
9806// Test that an exception can be propagated down through a spaghetti
9807// stack using ReThrow.
9808THREADED_TEST(SpaghettiStackReThrow) {
9809 v8::HandleScope scope;
9810 LocalContext context;
9811 context->Global()->Set(
9812 v8::String::New("s"),
9813 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
9814 v8::TryCatch try_catch;
9815 CompileRun(
9816 "var i = 0;"
9817 "var o = {"
9818 " toString: function () {"
9819 " if (i == 10) {"
9820 " throw 'Hey!';"
9821 " } else {"
9822 " i++;"
9823 " return s(o);"
9824 " }"
9825 " }"
9826 "};"
9827 "s(o);");
9828 CHECK(try_catch.HasCaught());
9829 v8::String::Utf8Value value(try_catch.Exception());
9830 CHECK_EQ(0, strcmp(*value, "Hey!"));
9831}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009832
9833
sgjesse@chromium.org98180592009-12-02 08:17:28 +00009834TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009835 v8::V8::Initialize();
9836
9837 v8::HandleScope scope;
9838 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +00009839 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009840 int gc_count;
9841
ager@chromium.org60121232009-12-03 11:25:37 +00009842 // Create a context used to keep the code from aging in the compilation
9843 // cache.
9844 other_context = Context::New();
9845
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009846 // Context-dependent context data creates reference from the compilation
9847 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +00009848 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009849 context = Context::New();
9850 {
9851 v8::HandleScope scope;
9852
9853 context->Enter();
9854 Local<v8::String> obj = v8::String::New("");
9855 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +00009856 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009857 context->Exit();
9858 }
9859 context.Dispose();
9860 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +00009861 other_context->Enter();
9862 CompileRun(source_simple);
9863 other_context->Exit();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009864 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +00009865 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009866 }
ager@chromium.org60121232009-12-03 11:25:37 +00009867 CHECK_GE(2, gc_count);
9868 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009869
9870 // Eval in a function creates reference from the compilation cache to the
9871 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +00009872 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009873 context = Context::New();
9874 {
9875 v8::HandleScope scope;
9876
9877 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +00009878 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009879 context->Exit();
9880 }
9881 context.Dispose();
9882 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +00009883 other_context->Enter();
9884 CompileRun(source_eval);
9885 other_context->Exit();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009886 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +00009887 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009888 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009889 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +00009890 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009891
9892 // Looking up the line number for an exception creates reference from the
9893 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +00009894 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009895 context = Context::New();
9896 {
9897 v8::HandleScope scope;
9898
9899 context->Enter();
9900 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +00009901 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009902 CHECK(try_catch.HasCaught());
9903 v8::Handle<v8::Message> message = try_catch.Message();
9904 CHECK(!message.IsEmpty());
9905 CHECK_EQ(1, message->GetLineNumber());
9906 context->Exit();
9907 }
9908 context.Dispose();
9909 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +00009910 other_context->Enter();
9911 CompileRun(source_exception);
9912 other_context->Exit();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009913 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +00009914 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009915 }
ager@chromium.org60121232009-12-03 11:25:37 +00009916 CHECK_GE(2, gc_count);
9917 CHECK_EQ(1, GetGlobalObjectsCount());
9918
9919 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00009920}
ager@chromium.org5c838252010-02-19 08:53:10 +00009921
9922
9923THREADED_TEST(ScriptOrigin) {
9924 v8::HandleScope scope;
9925 LocalContext env;
9926 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
9927 v8::Handle<v8::String> script = v8::String::New(
9928 "function f() {}\n\nfunction g() {}");
9929 v8::Script::Compile(script, &origin)->Run();
9930 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
9931 env->Global()->Get(v8::String::New("f")));
9932 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
9933 env->Global()->Get(v8::String::New("g")));
9934
9935 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
9936 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
9937 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
9938
9939 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
9940 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
9941 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
9942}
9943
9944
9945THREADED_TEST(ScriptLineNumber) {
9946 v8::HandleScope scope;
9947 LocalContext env;
9948 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
9949 v8::Handle<v8::String> script = v8::String::New(
9950 "function f() {}\n\nfunction g() {}");
9951 v8::Script::Compile(script, &origin)->Run();
9952 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
9953 env->Global()->Get(v8::String::New("f")));
9954 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
9955 env->Global()->Get(v8::String::New("g")));
9956 CHECK_EQ(0, f->GetScriptLineNumber());
9957 CHECK_EQ(2, g->GetScriptLineNumber());
9958}
9959
9960
9961static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
9962 const AccessorInfo& info) {
9963 return v8_num(42);
9964}
9965
9966
9967static void SetterWhichSetsYOnThisTo23(Local<String> name,
9968 Local<Value> value,
9969 const AccessorInfo& info) {
9970 info.This()->Set(v8_str("y"), v8_num(23));
9971}
9972
9973
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009974TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +00009975 v8::HandleScope scope;
9976 Local<ObjectTemplate> templ = ObjectTemplate::New();
9977 templ->SetAccessor(v8_str("x"),
9978 GetterWhichReturns42,
9979 SetterWhichSetsYOnThisTo23);
9980 LocalContext context;
9981 context->Global()->Set(v8_str("P"), templ->NewInstance());
9982 CompileRun("function C1() {"
9983 " this.x = 23;"
9984 "};"
9985 "C1.prototype = P;"
9986 "function C2() {"
9987 " this.x = 23"
9988 "};"
9989 "C2.prototype = { };"
9990 "C2.prototype.__proto__ = P;");
9991
9992 v8::Local<v8::Script> script;
9993 script = v8::Script::Compile(v8_str("new C1();"));
9994 for (int i = 0; i < 10; i++) {
9995 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
9996 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
9997 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
9998 }
9999
10000 script = v8::Script::Compile(v8_str("new C2();"));
10001 for (int i = 0; i < 10; i++) {
10002 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10003 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
10004 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
10005 }
10006}
10007
10008
10009static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
10010 Local<String> name, const AccessorInfo& info) {
10011 return v8_num(42);
10012}
10013
10014
10015static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
10016 Local<String> name, Local<Value> value, const AccessorInfo& info) {
10017 if (name->Equals(v8_str("x"))) {
10018 info.This()->Set(v8_str("y"), v8_num(23));
10019 }
10020 return v8::Handle<Value>();
10021}
10022
10023
10024THREADED_TEST(InterceptorOnConstructorPrototype) {
10025 v8::HandleScope scope;
10026 Local<ObjectTemplate> templ = ObjectTemplate::New();
10027 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
10028 NamedPropertySetterWhichSetsYOnThisTo23);
10029 LocalContext context;
10030 context->Global()->Set(v8_str("P"), templ->NewInstance());
10031 CompileRun("function C1() {"
10032 " this.x = 23;"
10033 "};"
10034 "C1.prototype = P;"
10035 "function C2() {"
10036 " this.x = 23"
10037 "};"
10038 "C2.prototype = { };"
10039 "C2.prototype.__proto__ = P;");
10040
10041 v8::Local<v8::Script> script;
10042 script = v8::Script::Compile(v8_str("new C1();"));
10043 for (int i = 0; i < 10; i++) {
10044 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10045 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10046 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10047 }
10048
10049 script = v8::Script::Compile(v8_str("new C2();"));
10050 for (int i = 0; i < 10; i++) {
10051 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
10052 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
10053 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
10054 }
10055}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010056
10057
10058TEST(Bug618) {
10059 const char* source = "function C1() {"
10060 " this.x = 23;"
10061 "};"
10062 "C1.prototype = P;";
10063
10064 v8::HandleScope scope;
10065 LocalContext context;
10066 v8::Local<v8::Script> script;
10067
10068 // Use a simple object as prototype.
10069 v8::Local<v8::Object> prototype = v8::Object::New();
10070 prototype->Set(v8_str("y"), v8_num(42));
10071 context->Global()->Set(v8_str("P"), prototype);
10072
10073 // This compile will add the code to the compilation cache.
10074 CompileRun(source);
10075
10076 script = v8::Script::Compile(v8_str("new C1();"));
10077 for (int i = 0; i < 10; i++) {
10078 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10079 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
10080 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
10081 }
10082
10083 // Use an API object with accessors as prototype.
10084 Local<ObjectTemplate> templ = ObjectTemplate::New();
10085 templ->SetAccessor(v8_str("x"),
10086 GetterWhichReturns42,
10087 SetterWhichSetsYOnThisTo23);
10088 context->Global()->Set(v8_str("P"), templ->NewInstance());
10089
10090 // This compile will get the code from the compilation cache.
10091 CompileRun(source);
10092
10093 script = v8::Script::Compile(v8_str("new C1();"));
10094 for (int i = 0; i < 10; i++) {
10095 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
10096 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
10097 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
10098 }
10099}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010100
10101int prologue_call_count = 0;
10102int epilogue_call_count = 0;
10103int prologue_call_count_second = 0;
10104int epilogue_call_count_second = 0;
10105
10106void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
10107 ++prologue_call_count;
10108}
10109
10110void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
10111 ++epilogue_call_count;
10112}
10113
10114void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10115 ++prologue_call_count_second;
10116}
10117
10118void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
10119 ++epilogue_call_count_second;
10120}
10121
10122TEST(GCCallbacks) {
10123 LocalContext context;
10124
10125 v8::V8::AddGCPrologueCallback(PrologueCallback);
10126 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
10127 CHECK_EQ(0, prologue_call_count);
10128 CHECK_EQ(0, epilogue_call_count);
10129 i::Heap::CollectAllGarbage(false);
10130 CHECK_EQ(1, prologue_call_count);
10131 CHECK_EQ(1, epilogue_call_count);
10132 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
10133 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
10134 i::Heap::CollectAllGarbage(false);
10135 CHECK_EQ(2, prologue_call_count);
10136 CHECK_EQ(2, epilogue_call_count);
10137 CHECK_EQ(1, prologue_call_count_second);
10138 CHECK_EQ(1, epilogue_call_count_second);
10139 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
10140 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
10141 i::Heap::CollectAllGarbage(false);
10142 CHECK_EQ(2, prologue_call_count);
10143 CHECK_EQ(2, epilogue_call_count);
10144 CHECK_EQ(2, prologue_call_count_second);
10145 CHECK_EQ(2, epilogue_call_count_second);
10146 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
10147 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
10148 i::Heap::CollectAllGarbage(false);
10149 CHECK_EQ(2, prologue_call_count);
10150 CHECK_EQ(2, epilogue_call_count);
10151 CHECK_EQ(2, prologue_call_count_second);
10152 CHECK_EQ(2, epilogue_call_count_second);
10153}