blob: 9b9f469f60a7a4d434eed5ca7c5003487f0a4fad [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"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000040#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000041#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000043static const bool kLogThreading = true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
53using ::v8::ObjectTemplate;
54using ::v8::Value;
55using ::v8::Context;
56using ::v8::Local;
57using ::v8::String;
58using ::v8::Script;
59using ::v8::Function;
60using ::v8::AccessorInfo;
61using ::v8::Extension;
62
lrn@chromium.org32d961d2010-06-30 09:09:34 +000063namespace i = ::i;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000064
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000065
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000066static void ExpectString(const char* code, const char* expected) {
67 Local<Value> result = CompileRun(code);
68 CHECK(result->IsString());
69 String::AsciiValue ascii(result);
70 CHECK_EQ(expected, *ascii);
71}
72
73
74static void ExpectBoolean(const char* code, bool expected) {
75 Local<Value> result = CompileRun(code);
76 CHECK(result->IsBoolean());
77 CHECK_EQ(expected, result->BooleanValue());
78}
79
80
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000081static void ExpectTrue(const char* code) {
82 ExpectBoolean(code, true);
83}
84
85
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000086static void ExpectFalse(const char* code) {
87 ExpectBoolean(code, false);
88}
89
90
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000091static void ExpectObject(const char* code, Local<Value> expected) {
92 Local<Value> result = CompileRun(code);
93 CHECK(result->Equals(expected));
94}
95
96
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000097static void ExpectUndefined(const char* code) {
98 Local<Value> result = CompileRun(code);
99 CHECK(result->IsUndefined());
100}
101
102
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000103static int signature_callback_count;
104static v8::Handle<Value> IncrementingSignatureCallback(
105 const v8::Arguments& args) {
106 ApiTestFuzzer::Fuzz();
107 signature_callback_count++;
108 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
109 for (int i = 0; i < args.Length(); i++)
110 result->Set(v8::Integer::New(i), args[i]);
111 return result;
112}
113
114
115static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
116 ApiTestFuzzer::Fuzz();
117 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
118 for (int i = 0; i < args.Length(); i++) {
119 result->Set(v8::Integer::New(i), args[i]);
120 }
121 return result;
122}
123
124
125THREADED_TEST(Handles) {
126 v8::HandleScope scope;
127 Local<Context> local_env;
128 {
129 LocalContext env;
130 local_env = env.local();
131 }
132
133 // Local context should still be live.
134 CHECK(!local_env.IsEmpty());
135 local_env->Enter();
136
137 v8::Handle<v8::Primitive> undef = v8::Undefined();
138 CHECK(!undef.IsEmpty());
139 CHECK(undef->IsUndefined());
140
141 const char* c_source = "1 + 2 + 3";
142 Local<String> source = String::New(c_source);
143 Local<Script> script = Script::Compile(source);
144 CHECK_EQ(6, script->Run()->Int32Value());
145
146 local_env->Exit();
147}
148
149
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000150THREADED_TEST(ReceiverSignature) {
151 v8::HandleScope scope;
152 LocalContext env;
153 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
154 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
155 fun->PrototypeTemplate()->Set(
156 v8_str("m"),
157 v8::FunctionTemplate::New(IncrementingSignatureCallback,
158 v8::Handle<Value>(),
159 sig));
160 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
161 signature_callback_count = 0;
162 CompileRun(
163 "var o = new Fun();"
164 "o.m();");
165 CHECK_EQ(1, signature_callback_count);
166 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
167 sub_fun->Inherit(fun);
168 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
169 CompileRun(
170 "var o = new SubFun();"
171 "o.m();");
172 CHECK_EQ(2, signature_callback_count);
173
174 v8::TryCatch try_catch;
175 CompileRun(
176 "var o = { };"
177 "o.m = Fun.prototype.m;"
178 "o.m();");
179 CHECK_EQ(2, signature_callback_count);
180 CHECK(try_catch.HasCaught());
181 try_catch.Reset();
182 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
183 sub_fun->Inherit(fun);
184 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
185 CompileRun(
186 "var o = new UnrelFun();"
187 "o.m = Fun.prototype.m;"
188 "o.m();");
189 CHECK_EQ(2, signature_callback_count);
190 CHECK(try_catch.HasCaught());
191}
192
193
194
195
196THREADED_TEST(ArgumentSignature) {
197 v8::HandleScope scope;
198 LocalContext env;
199 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
200 cons->SetClassName(v8_str("Cons"));
201 v8::Handle<v8::Signature> sig =
202 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
203 v8::Handle<v8::FunctionTemplate> fun =
204 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
205 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
206 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
207
208 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000209 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000210
211 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000212 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000213
214 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000215 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000216
217 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
218 cons1->SetClassName(v8_str("Cons1"));
219 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
220 cons2->SetClassName(v8_str("Cons2"));
221 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
222 cons3->SetClassName(v8_str("Cons3"));
223
224 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
225 v8::Handle<v8::Signature> wsig =
226 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
227 v8::Handle<v8::FunctionTemplate> fun2 =
228 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
229
230 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
231 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
232 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
233 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
234 v8::Handle<Value> value4 = CompileRun(
235 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
236 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000237 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
239 v8::Handle<Value> value5 = CompileRun(
240 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000241 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000242
243 v8::Handle<Value> value6 = CompileRun(
244 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000245 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
247 v8::Handle<Value> value7 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
249 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000250 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000251
252 v8::Handle<Value> value8 = CompileRun(
253 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000254 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255}
256
257
258THREADED_TEST(HulIgennem) {
259 v8::HandleScope scope;
260 LocalContext env;
261 v8::Handle<v8::Primitive> undef = v8::Undefined();
262 Local<String> undef_str = undef->ToString();
263 char* value = i::NewArray<char>(undef_str->Length() + 1);
264 undef_str->WriteAscii(value);
265 CHECK_EQ(0, strcmp(value, "undefined"));
266 i::DeleteArray(value);
267}
268
269
270THREADED_TEST(Access) {
271 v8::HandleScope scope;
272 LocalContext env;
273 Local<v8::Object> obj = v8::Object::New();
274 Local<Value> foo_before = obj->Get(v8_str("foo"));
275 CHECK(foo_before->IsUndefined());
276 Local<String> bar_str = v8_str("bar");
277 obj->Set(v8_str("foo"), bar_str);
278 Local<Value> foo_after = obj->Get(v8_str("foo"));
279 CHECK(!foo_after->IsUndefined());
280 CHECK(foo_after->IsString());
281 CHECK_EQ(bar_str, foo_after);
282}
283
284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000285THREADED_TEST(AccessElement) {
286 v8::HandleScope scope;
287 LocalContext env;
288 Local<v8::Object> obj = v8::Object::New();
289 Local<Value> before = obj->Get(1);
290 CHECK(before->IsUndefined());
291 Local<String> bar_str = v8_str("bar");
292 obj->Set(1, bar_str);
293 Local<Value> after = obj->Get(1);
294 CHECK(!after->IsUndefined());
295 CHECK(after->IsString());
296 CHECK_EQ(bar_str, after);
297
298 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
299 CHECK_EQ(v8_str("a"), value->Get(0));
300 CHECK_EQ(v8_str("b"), value->Get(1));
301}
302
303
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000304THREADED_TEST(Script) {
305 v8::HandleScope scope;
306 LocalContext env;
307 const char* c_source = "1 + 2 + 3";
308 Local<String> source = String::New(c_source);
309 Local<Script> script = Script::Compile(source);
310 CHECK_EQ(6, script->Run()->Int32Value());
311}
312
313
314static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000315 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000317 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000318 return converted;
319}
320
321
322class TestResource: public String::ExternalStringResource {
323 public:
324 static int dispose_count;
325
326 explicit TestResource(uint16_t* data)
327 : data_(data), length_(0) {
328 while (data[length_]) ++length_;
329 }
330
331 ~TestResource() {
332 i::DeleteArray(data_);
333 ++dispose_count;
334 }
335
336 const uint16_t* data() const {
337 return data_;
338 }
339
340 size_t length() const {
341 return length_;
342 }
343 private:
344 uint16_t* data_;
345 size_t length_;
346};
347
348
349int TestResource::dispose_count = 0;
350
351
352class TestAsciiResource: public String::ExternalAsciiStringResource {
353 public:
354 static int dispose_count;
355
ager@chromium.org5ec48922009-05-05 07:25:34 +0000356 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000357 : data_(data),
358 length_(strlen(data)) { }
359
360 ~TestAsciiResource() {
361 i::DeleteArray(data_);
362 ++dispose_count;
363 }
364
365 const char* data() const {
366 return data_;
367 }
368
369 size_t length() const {
370 return length_;
371 }
372 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000373 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374 size_t length_;
375};
376
377
378int TestAsciiResource::dispose_count = 0;
379
380
381THREADED_TEST(ScriptUsingStringResource) {
382 TestResource::dispose_count = 0;
383 const char* c_source = "1 + 2 * 3";
384 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
385 {
386 v8::HandleScope scope;
387 LocalContext env;
388 TestResource* resource = new TestResource(two_byte_source);
389 Local<String> source = String::NewExternal(resource);
390 Local<Script> script = Script::Compile(source);
391 Local<Value> value = script->Run();
392 CHECK(value->IsNumber());
393 CHECK_EQ(7, value->Int32Value());
394 CHECK(source->IsExternal());
395 CHECK_EQ(resource,
396 static_cast<TestResource*>(source->GetExternalStringResource()));
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000397 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398 CHECK_EQ(0, TestResource::dispose_count);
399 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000400 i::CompilationCache::Clear();
401 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402 CHECK_EQ(1, TestResource::dispose_count);
403}
404
405
406THREADED_TEST(ScriptUsingAsciiStringResource) {
407 TestAsciiResource::dispose_count = 0;
408 const char* c_source = "1 + 2 * 3";
409 {
410 v8::HandleScope scope;
411 LocalContext env;
412 Local<String> source =
413 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
414 Local<Script> script = Script::Compile(source);
415 Local<Value> value = script->Run();
416 CHECK(value->IsNumber());
417 CHECK_EQ(7, value->Int32Value());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000418 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419 CHECK_EQ(0, TestAsciiResource::dispose_count);
420 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000421 i::CompilationCache::Clear();
422 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000423 CHECK_EQ(1, TestAsciiResource::dispose_count);
424}
425
426
ager@chromium.org6f10e412009-02-13 10:11:16 +0000427THREADED_TEST(ScriptMakingExternalString) {
428 TestResource::dispose_count = 0;
429 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
430 {
431 v8::HandleScope scope;
432 LocalContext env;
433 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000435 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
436 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000437 bool success = source->MakeExternal(new TestResource(two_byte_source));
438 CHECK(success);
439 Local<Script> script = Script::Compile(source);
440 Local<Value> value = script->Run();
441 CHECK(value->IsNumber());
442 CHECK_EQ(7, value->Int32Value());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000443 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000444 CHECK_EQ(0, TestResource::dispose_count);
445 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000446 i::CompilationCache::Clear();
447 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000448 CHECK_EQ(1, TestResource::dispose_count);
449}
450
451
452THREADED_TEST(ScriptMakingExternalAsciiString) {
453 TestAsciiResource::dispose_count = 0;
454 const char* c_source = "1 + 2 * 3";
455 {
456 v8::HandleScope scope;
457 LocalContext env;
458 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000460 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
461 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000462 bool success = source->MakeExternal(
463 new TestAsciiResource(i::StrDup(c_source)));
464 CHECK(success);
465 Local<Script> script = Script::Compile(source);
466 Local<Value> value = script->Run();
467 CHECK(value->IsNumber());
468 CHECK_EQ(7, value->Int32Value());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000469 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000470 CHECK_EQ(0, TestAsciiResource::dispose_count);
471 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000472 i::CompilationCache::Clear();
473 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000474 CHECK_EQ(1, TestAsciiResource::dispose_count);
475}
476
477
ager@chromium.org5c838252010-02-19 08:53:10 +0000478TEST(MakingExternalStringConditions) {
479 v8::HandleScope scope;
480 LocalContext env;
481
482 // Free some space in the new space so that we can check freshness.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000483 i::Heap::CollectGarbage(i::NEW_SPACE);
484 i::Heap::CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000485
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000486 uint16_t* two_byte_string = AsciiToTwoByteString("small");
487 Local<String> small_string = String::New(two_byte_string);
488 i::DeleteArray(two_byte_string);
489
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // We should refuse to externalize newly created small string.
491 CHECK(!small_string->CanMakeExternal());
492 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000493 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
494 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000495 // Old space strings should be accepted.
496 CHECK(small_string->CanMakeExternal());
497
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000498 two_byte_string = AsciiToTwoByteString("small 2");
499 small_string = String::New(two_byte_string);
500 i::DeleteArray(two_byte_string);
501
ager@chromium.org5c838252010-02-19 08:53:10 +0000502 // We should refuse externalizing newly created small string.
503 CHECK(!small_string->CanMakeExternal());
504 for (int i = 0; i < 100; i++) {
505 String::Value value(small_string);
506 }
507 // Frequently used strings should be accepted.
508 CHECK(small_string->CanMakeExternal());
509
510 const int buf_size = 10 * 1024;
511 char* buf = i::NewArray<char>(buf_size);
512 memset(buf, 'a', buf_size);
513 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000514
515 two_byte_string = AsciiToTwoByteString(buf);
516 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000517 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000518 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000519 // Large strings should be immediately accepted.
520 CHECK(large_string->CanMakeExternal());
521}
522
523
524TEST(MakingExternalAsciiStringConditions) {
525 v8::HandleScope scope;
526 LocalContext env;
527
528 // Free some space in the new space so that we can check freshness.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000529 i::Heap::CollectGarbage(i::NEW_SPACE);
530 i::Heap::CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000531
532 Local<String> small_string = String::New("small");
533 // We should refuse to externalize newly created small string.
534 CHECK(!small_string->CanMakeExternal());
535 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000536 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
537 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000538 // Old space strings should be accepted.
539 CHECK(small_string->CanMakeExternal());
540
541 small_string = String::New("small 2");
542 // We should refuse externalizing newly created small string.
543 CHECK(!small_string->CanMakeExternal());
544 for (int i = 0; i < 100; i++) {
545 String::Value value(small_string);
546 }
547 // Frequently used strings should be accepted.
548 CHECK(small_string->CanMakeExternal());
549
550 const int buf_size = 10 * 1024;
551 char* buf = i::NewArray<char>(buf_size);
552 memset(buf, 'a', buf_size);
553 buf[buf_size - 1] = '\0';
554 Local<String> large_string = String::New(buf);
555 i::DeleteArray(buf);
556 // Large strings should be immediately accepted.
557 CHECK(large_string->CanMakeExternal());
558}
559
560
ager@chromium.org6f10e412009-02-13 10:11:16 +0000561THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000562 {
563 v8::HandleScope scope;
564 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
565 Local<String> string =
566 String::NewExternal(new TestResource(two_byte_string));
567 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
568 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000569 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
570 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.orge2902be2009-06-08 12:21:35 +0000571 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
572 CHECK(isymbol->IsSymbol());
573 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000574 i::Heap::CollectAllGarbage(false);
575 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000576}
577
578
579THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000580 {
581 v8::HandleScope scope;
582 const char* one_byte_string = "test string";
583 Local<String> string = String::NewExternal(
584 new TestAsciiResource(i::StrDup(one_byte_string)));
585 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
586 // Trigger GCs so that the newly allocated string moves to old gen.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000587 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
588 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.orge2902be2009-06-08 12:21:35 +0000589 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
590 CHECK(isymbol->IsSymbol());
591 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000592 i::Heap::CollectAllGarbage(false);
593 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000594}
595
596
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000597THREADED_TEST(ScavengeExternalString) {
598 TestResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000599 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000600 {
601 v8::HandleScope scope;
602 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
603 Local<String> string =
604 String::NewExternal(new TestResource(two_byte_string));
605 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000606 i::Heap::CollectGarbage(i::NEW_SPACE);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000607 in_new_space = i::Heap::InNewSpace(*istring);
608 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 CHECK_EQ(0, TestResource::dispose_count);
610 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000611 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000612 CHECK_EQ(1, TestResource::dispose_count);
613}
614
615
616THREADED_TEST(ScavengeExternalAsciiString) {
617 TestAsciiResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000618 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 {
620 v8::HandleScope scope;
621 const char* one_byte_string = "test string";
622 Local<String> string = String::NewExternal(
623 new TestAsciiResource(i::StrDup(one_byte_string)));
624 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000625 i::Heap::CollectGarbage(i::NEW_SPACE);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000626 in_new_space = i::Heap::InNewSpace(*istring);
627 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628 CHECK_EQ(0, TestAsciiResource::dispose_count);
629 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000630 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 CHECK_EQ(1, TestAsciiResource::dispose_count);
632}
633
634
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000635class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
636 public:
637 static int dispose_calls;
638
639 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
640 : TestAsciiResource(data),
641 dispose_(dispose) { }
642
643 void Dispose() {
644 ++dispose_calls;
645 if (dispose_) delete this;
646 }
647 private:
648 bool dispose_;
649};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000650
651
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000652int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000653
654
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000655TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000656 const char* c_source = "1 + 2 * 3";
657
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000658 // Use a stack allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000659 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000660 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
661 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000662 {
663 v8::HandleScope scope;
664 LocalContext env;
665 Local<String> source = String::NewExternal(&res_stack);
666 Local<Script> script = Script::Compile(source);
667 Local<Value> value = script->Run();
668 CHECK(value->IsNumber());
669 CHECK_EQ(7, value->Int32Value());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000670 i::Heap::CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000671 CHECK_EQ(0, TestAsciiResource::dispose_count);
672 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000673 i::CompilationCache::Clear();
674 i::Heap::CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000675 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000676 CHECK_EQ(0, TestAsciiResource::dispose_count);
677
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000678 // Use a heap allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000679 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000680 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
681 TestAsciiResource* res_heap =
682 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000683 {
684 v8::HandleScope scope;
685 LocalContext env;
686 Local<String> source = String::NewExternal(res_heap);
687 Local<Script> script = Script::Compile(source);
688 Local<Value> value = script->Run();
689 CHECK(value->IsNumber());
690 CHECK_EQ(7, value->Int32Value());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000691 i::Heap::CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000692 CHECK_EQ(0, TestAsciiResource::dispose_count);
693 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000694 i::CompilationCache::Clear();
695 i::Heap::CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000696 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000697 CHECK_EQ(1, TestAsciiResource::dispose_count);
698}
699
700
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000701THREADED_TEST(StringConcat) {
702 {
703 v8::HandleScope scope;
704 LocalContext env;
705 const char* one_byte_string_1 = "function a_times_t";
706 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
707 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
708 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
709 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
710 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
711 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
712 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000713
714 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
715 Local<String> right = String::New(two_byte_source);
716 i::DeleteArray(two_byte_source);
717
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000718 Local<String> source = String::Concat(left, right);
719 right = String::NewExternal(
720 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
721 source = String::Concat(source, right);
722 right = String::NewExternal(
723 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
724 source = String::Concat(source, right);
725 right = v8_str(one_byte_string_2);
726 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000727
728 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
729 right = String::New(two_byte_source);
730 i::DeleteArray(two_byte_source);
731
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000732 source = String::Concat(source, right);
733 right = String::NewExternal(
734 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
735 source = String::Concat(source, right);
736 Local<Script> script = Script::Compile(source);
737 Local<Value> value = script->Run();
738 CHECK(value->IsNumber());
739 CHECK_EQ(68, value->Int32Value());
740 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000741 i::CompilationCache::Clear();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000742 i::Heap::CollectAllGarbage(false);
743 i::Heap::CollectAllGarbage(false);
744}
745
746
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747THREADED_TEST(GlobalProperties) {
748 v8::HandleScope scope;
749 LocalContext env;
750 v8::Handle<v8::Object> global = env->Global();
751 global->Set(v8_str("pi"), v8_num(3.1415926));
752 Local<Value> pi = global->Get(v8_str("pi"));
753 CHECK_EQ(3.1415926, pi->NumberValue());
754}
755
756
757static v8::Handle<Value> handle_call(const v8::Arguments& args) {
758 ApiTestFuzzer::Fuzz();
759 return v8_num(102);
760}
761
762
763static v8::Handle<Value> construct_call(const v8::Arguments& args) {
764 ApiTestFuzzer::Fuzz();
765 args.This()->Set(v8_str("x"), v8_num(1));
766 args.This()->Set(v8_str("y"), v8_num(2));
767 return args.This();
768}
769
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000770static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
771 ApiTestFuzzer::Fuzz();
772 return v8_num(239);
773}
774
775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776THREADED_TEST(FunctionTemplate) {
777 v8::HandleScope scope;
778 LocalContext env;
779 {
780 Local<v8::FunctionTemplate> fun_templ =
781 v8::FunctionTemplate::New(handle_call);
782 Local<Function> fun = fun_templ->GetFunction();
783 env->Global()->Set(v8_str("obj"), fun);
784 Local<Script> script = v8_compile("obj()");
785 CHECK_EQ(102, script->Run()->Int32Value());
786 }
787 // Use SetCallHandler to initialize a function template, should work like the
788 // previous one.
789 {
790 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
791 fun_templ->SetCallHandler(handle_call);
792 Local<Function> fun = fun_templ->GetFunction();
793 env->Global()->Set(v8_str("obj"), fun);
794 Local<Script> script = v8_compile("obj()");
795 CHECK_EQ(102, script->Run()->Int32Value());
796 }
797 // Test constructor calls.
798 {
799 Local<v8::FunctionTemplate> fun_templ =
800 v8::FunctionTemplate::New(construct_call);
801 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000802 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000803 Local<Function> fun = fun_templ->GetFunction();
804 env->Global()->Set(v8_str("obj"), fun);
805 Local<Script> script = v8_compile("var s = new obj(); s.x");
806 CHECK_EQ(1, script->Run()->Int32Value());
807
808 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
809 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000810
811 result = v8_compile("(new obj()).m")->Run();
812 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813 }
814}
815
816
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000817static void* expected_ptr;
818static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
819 void* ptr = v8::External::Unwrap(args.Data());
820 CHECK_EQ(expected_ptr, ptr);
821 return v8::Boolean::New(true);
822}
823
824
825static void TestExternalPointerWrapping() {
826 v8::HandleScope scope;
827 LocalContext env;
828
829 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
830
831 v8::Handle<v8::Object> obj = v8::Object::New();
832 obj->Set(v8_str("func"),
833 v8::FunctionTemplate::New(callback, data)->GetFunction());
834 env->Global()->Set(v8_str("obj"), obj);
835
836 CHECK(CompileRun(
837 "function foo() {\n"
838 " for (var i = 0; i < 13; i++) obj.func();\n"
839 "}\n"
840 "foo(), true")->BooleanValue());
841}
842
843
844THREADED_TEST(ExternalWrap) {
845 // Check heap allocated object.
846 int* ptr = new int;
847 expected_ptr = ptr;
848 TestExternalPointerWrapping();
849 delete ptr;
850
851 // Check stack allocated object.
852 int foo;
853 expected_ptr = &foo;
854 TestExternalPointerWrapping();
855
856 // Check not aligned addresses.
857 const int n = 100;
858 char* s = new char[n];
859 for (int i = 0; i < n; i++) {
860 expected_ptr = s + i;
861 TestExternalPointerWrapping();
862 }
863
864 delete[] s;
865
866 // Check several invalid addresses.
867 expected_ptr = reinterpret_cast<void*>(1);
868 TestExternalPointerWrapping();
869
870 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
871 TestExternalPointerWrapping();
872
873 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
874 TestExternalPointerWrapping();
875
876#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000877 // Check a value with a leading 1 bit in x64 Smi encoding.
878 expected_ptr = reinterpret_cast<void*>(0x400000000);
879 TestExternalPointerWrapping();
880
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000881 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
882 TestExternalPointerWrapping();
883
884 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
885 TestExternalPointerWrapping();
886#endif
887}
888
889
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000890THREADED_TEST(FindInstanceInPrototypeChain) {
891 v8::HandleScope scope;
892 LocalContext env;
893
894 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
895 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
896 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
897 derived->Inherit(base);
898
899 Local<v8::Function> base_function = base->GetFunction();
900 Local<v8::Function> derived_function = derived->GetFunction();
901 Local<v8::Function> other_function = other->GetFunction();
902
903 Local<v8::Object> base_instance = base_function->NewInstance();
904 Local<v8::Object> derived_instance = derived_function->NewInstance();
905 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
906 Local<v8::Object> other_instance = other_function->NewInstance();
907 derived_instance2->Set(v8_str("__proto__"), derived_instance);
908 other_instance->Set(v8_str("__proto__"), derived_instance2);
909
910 // base_instance is only an instance of base.
911 CHECK_EQ(base_instance,
912 base_instance->FindInstanceInPrototypeChain(base));
913 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
914 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
915
916 // derived_instance is an instance of base and derived.
917 CHECK_EQ(derived_instance,
918 derived_instance->FindInstanceInPrototypeChain(base));
919 CHECK_EQ(derived_instance,
920 derived_instance->FindInstanceInPrototypeChain(derived));
921 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
922
923 // other_instance is an instance of other and its immediate
924 // prototype derived_instance2 is an instance of base and derived.
925 // Note, derived_instance is an instance of base and derived too,
926 // but it comes after derived_instance2 in the prototype chain of
927 // other_instance.
928 CHECK_EQ(derived_instance2,
929 other_instance->FindInstanceInPrototypeChain(base));
930 CHECK_EQ(derived_instance2,
931 other_instance->FindInstanceInPrototypeChain(derived));
932 CHECK_EQ(other_instance,
933 other_instance->FindInstanceInPrototypeChain(other));
934}
935
936
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000937THREADED_TEST(TinyInteger) {
938 v8::HandleScope scope;
939 LocalContext env;
940 int32_t value = 239;
941 Local<v8::Integer> value_obj = v8::Integer::New(value);
942 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
943}
944
945
946THREADED_TEST(BigSmiInteger) {
947 v8::HandleScope scope;
948 LocalContext env;
949 int32_t value = i::Smi::kMaxValue;
950 // We cannot add one to a Smi::kMaxValue without wrapping.
951 if (i::kSmiValueSize < 32) {
952 CHECK(i::Smi::IsValid(value));
953 CHECK(!i::Smi::IsValid(value + 1));
954 Local<v8::Integer> value_obj = v8::Integer::New(value);
955 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
956 }
957}
958
959
960THREADED_TEST(BigInteger) {
961 v8::HandleScope scope;
962 LocalContext env;
963 // We cannot add one to a Smi::kMaxValue without wrapping.
964 if (i::kSmiValueSize < 32) {
965 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
966 // The code will not be run in that case, due to the "if" guard.
967 int32_t value =
968 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
969 CHECK(value > i::Smi::kMaxValue);
970 CHECK(!i::Smi::IsValid(value));
971 Local<v8::Integer> value_obj = v8::Integer::New(value);
972 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
973 }
974}
975
976
977THREADED_TEST(TinyUnsignedInteger) {
978 v8::HandleScope scope;
979 LocalContext env;
980 uint32_t value = 239;
981 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983}
984
985
986THREADED_TEST(BigUnsignedSmiInteger) {
987 v8::HandleScope scope;
988 LocalContext env;
989 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
990 CHECK(i::Smi::IsValid(value));
991 CHECK(!i::Smi::IsValid(value + 1));
992 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
993 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
994}
995
996
997THREADED_TEST(BigUnsignedInteger) {
998 v8::HandleScope scope;
999 LocalContext env;
1000 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1001 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1002 CHECK(!i::Smi::IsValid(value));
1003 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1004 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1005}
1006
1007
1008THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1009 v8::HandleScope scope;
1010 LocalContext env;
1011 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1012 uint32_t value = INT32_MAX_AS_UINT + 1;
1013 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1014 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1015 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1016}
1017
1018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001019THREADED_TEST(Number) {
1020 v8::HandleScope scope;
1021 LocalContext env;
1022 double PI = 3.1415926;
1023 Local<v8::Number> pi_obj = v8::Number::New(PI);
1024 CHECK_EQ(PI, pi_obj->NumberValue());
1025}
1026
1027
1028THREADED_TEST(ToNumber) {
1029 v8::HandleScope scope;
1030 LocalContext env;
1031 Local<String> str = v8_str("3.1415926");
1032 CHECK_EQ(3.1415926, str->NumberValue());
1033 v8::Handle<v8::Boolean> t = v8::True();
1034 CHECK_EQ(1.0, t->NumberValue());
1035 v8::Handle<v8::Boolean> f = v8::False();
1036 CHECK_EQ(0.0, f->NumberValue());
1037}
1038
1039
1040THREADED_TEST(Date) {
1041 v8::HandleScope scope;
1042 LocalContext env;
1043 double PI = 3.1415926;
1044 Local<Value> date_obj = v8::Date::New(PI);
1045 CHECK_EQ(3.0, date_obj->NumberValue());
1046}
1047
1048
1049THREADED_TEST(Boolean) {
1050 v8::HandleScope scope;
1051 LocalContext env;
1052 v8::Handle<v8::Boolean> t = v8::True();
1053 CHECK(t->Value());
1054 v8::Handle<v8::Boolean> f = v8::False();
1055 CHECK(!f->Value());
1056 v8::Handle<v8::Primitive> u = v8::Undefined();
1057 CHECK(!u->BooleanValue());
1058 v8::Handle<v8::Primitive> n = v8::Null();
1059 CHECK(!n->BooleanValue());
1060 v8::Handle<String> str1 = v8_str("");
1061 CHECK(!str1->BooleanValue());
1062 v8::Handle<String> str2 = v8_str("x");
1063 CHECK(str2->BooleanValue());
1064 CHECK(!v8::Number::New(0)->BooleanValue());
1065 CHECK(v8::Number::New(-1)->BooleanValue());
1066 CHECK(v8::Number::New(1)->BooleanValue());
1067 CHECK(v8::Number::New(42)->BooleanValue());
1068 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1069}
1070
1071
1072static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1073 ApiTestFuzzer::Fuzz();
1074 return v8_num(13.4);
1075}
1076
1077
1078static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1079 ApiTestFuzzer::Fuzz();
1080 return v8_num(876);
1081}
1082
1083
1084THREADED_TEST(GlobalPrototype) {
1085 v8::HandleScope scope;
1086 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1087 func_templ->PrototypeTemplate()->Set(
1088 "dummy",
1089 v8::FunctionTemplate::New(DummyCallHandler));
1090 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1091 templ->Set("x", v8_num(200));
1092 templ->SetAccessor(v8_str("m"), GetM);
1093 LocalContext env(0, templ);
1094 v8::Handle<v8::Object> obj = env->Global();
1095 v8::Handle<Script> script = v8_compile("dummy()");
1096 v8::Handle<Value> result = script->Run();
1097 CHECK_EQ(13.4, result->NumberValue());
1098 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1099 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1100}
1101
1102
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001103THREADED_TEST(ObjectTemplate) {
1104 v8::HandleScope scope;
1105 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1106 templ1->Set("x", v8_num(10));
1107 templ1->Set("y", v8_num(13));
1108 LocalContext env;
1109 Local<v8::Object> instance1 = templ1->NewInstance();
1110 env->Global()->Set(v8_str("p"), instance1);
1111 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1112 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1113 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1114 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1115 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1116 templ2->Set("a", v8_num(12));
1117 templ2->Set("b", templ1);
1118 Local<v8::Object> instance2 = templ2->NewInstance();
1119 env->Global()->Set(v8_str("q"), instance2);
1120 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1121 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1122 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1123 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1124}
1125
1126
1127static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1128 ApiTestFuzzer::Fuzz();
1129 return v8_num(17.2);
1130}
1131
1132
1133static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1134 ApiTestFuzzer::Fuzz();
1135 return v8_num(15.2);
1136}
1137
1138
1139THREADED_TEST(DescriptorInheritance) {
1140 v8::HandleScope scope;
1141 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1142 super->PrototypeTemplate()->Set("flabby",
1143 v8::FunctionTemplate::New(GetFlabby));
1144 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1145
1146 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1147
1148 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1149 base1->Inherit(super);
1150 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1151
1152 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1153 base2->Inherit(super);
1154 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1155
1156 LocalContext env;
1157
1158 env->Global()->Set(v8_str("s"), super->GetFunction());
1159 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1160 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1161
1162 // Checks right __proto__ chain.
1163 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1164 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1165
1166 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1167
1168 // Instance accessor should not be visible on function object or its prototype
1169 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1170 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1171 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1172
1173 env->Global()->Set(v8_str("obj"),
1174 base1->GetFunction()->NewInstance());
1175 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1176 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1177 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1178 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1179 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1180
1181 env->Global()->Set(v8_str("obj2"),
1182 base2->GetFunction()->NewInstance());
1183 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1184 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1185 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1186 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1187 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1188
1189 // base1 and base2 cannot cross reference to each's prototype
1190 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1191 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1192}
1193
1194
1195int echo_named_call_count;
1196
1197
1198static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1199 const AccessorInfo& info) {
1200 ApiTestFuzzer::Fuzz();
1201 CHECK_EQ(v8_str("data"), info.Data());
1202 echo_named_call_count++;
1203 return name;
1204}
1205
1206
1207THREADED_TEST(NamedPropertyHandlerGetter) {
1208 echo_named_call_count = 0;
1209 v8::HandleScope scope;
1210 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1211 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1212 0, 0, 0, 0,
1213 v8_str("data"));
1214 LocalContext env;
1215 env->Global()->Set(v8_str("obj"),
1216 templ->GetFunction()->NewInstance());
1217 CHECK_EQ(echo_named_call_count, 0);
1218 v8_compile("obj.x")->Run();
1219 CHECK_EQ(echo_named_call_count, 1);
1220 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1221 v8::Handle<Value> str = CompileRun(code);
1222 String::AsciiValue value(str);
1223 CHECK_EQ(*value, "oddlepoddle");
1224 // Check default behavior
1225 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1226 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1227 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1228}
1229
1230
1231int echo_indexed_call_count = 0;
1232
1233
1234static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1235 const AccessorInfo& info) {
1236 ApiTestFuzzer::Fuzz();
1237 CHECK_EQ(v8_num(637), info.Data());
1238 echo_indexed_call_count++;
1239 return v8_num(index);
1240}
1241
1242
1243THREADED_TEST(IndexedPropertyHandlerGetter) {
1244 v8::HandleScope scope;
1245 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1246 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1247 0, 0, 0, 0,
1248 v8_num(637));
1249 LocalContext env;
1250 env->Global()->Set(v8_str("obj"),
1251 templ->GetFunction()->NewInstance());
1252 Local<Script> script = v8_compile("obj[900]");
1253 CHECK_EQ(script->Run()->Int32Value(), 900);
1254}
1255
1256
1257v8::Handle<v8::Object> bottom;
1258
1259static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1260 uint32_t index,
1261 const AccessorInfo& info) {
1262 ApiTestFuzzer::Fuzz();
1263 CHECK(info.This()->Equals(bottom));
1264 return v8::Handle<Value>();
1265}
1266
1267static v8::Handle<Value> CheckThisNamedPropertyHandler(
1268 Local<String> name,
1269 const AccessorInfo& info) {
1270 ApiTestFuzzer::Fuzz();
1271 CHECK(info.This()->Equals(bottom));
1272 return v8::Handle<Value>();
1273}
1274
1275
1276v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1277 Local<Value> value,
1278 const AccessorInfo& info) {
1279 ApiTestFuzzer::Fuzz();
1280 CHECK(info.This()->Equals(bottom));
1281 return v8::Handle<Value>();
1282}
1283
1284
1285v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1286 Local<Value> value,
1287 const AccessorInfo& info) {
1288 ApiTestFuzzer::Fuzz();
1289 CHECK(info.This()->Equals(bottom));
1290 return v8::Handle<Value>();
1291}
1292
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001293v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001294 uint32_t index,
1295 const AccessorInfo& info) {
1296 ApiTestFuzzer::Fuzz();
1297 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001298 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001299}
1300
1301
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001302v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001303 const AccessorInfo& info) {
1304 ApiTestFuzzer::Fuzz();
1305 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001306 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001307}
1308
1309
1310v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1311 uint32_t index,
1312 const AccessorInfo& info) {
1313 ApiTestFuzzer::Fuzz();
1314 CHECK(info.This()->Equals(bottom));
1315 return v8::Handle<v8::Boolean>();
1316}
1317
1318
1319v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1320 Local<String> property,
1321 const AccessorInfo& info) {
1322 ApiTestFuzzer::Fuzz();
1323 CHECK(info.This()->Equals(bottom));
1324 return v8::Handle<v8::Boolean>();
1325}
1326
1327
1328v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1329 const AccessorInfo& info) {
1330 ApiTestFuzzer::Fuzz();
1331 CHECK(info.This()->Equals(bottom));
1332 return v8::Handle<v8::Array>();
1333}
1334
1335
1336v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1337 const AccessorInfo& info) {
1338 ApiTestFuzzer::Fuzz();
1339 CHECK(info.This()->Equals(bottom));
1340 return v8::Handle<v8::Array>();
1341}
1342
1343
1344THREADED_TEST(PropertyHandlerInPrototype) {
1345 v8::HandleScope scope;
1346 LocalContext env;
1347
1348 // Set up a prototype chain with three interceptors.
1349 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1350 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1351 CheckThisIndexedPropertyHandler,
1352 CheckThisIndexedPropertySetter,
1353 CheckThisIndexedPropertyQuery,
1354 CheckThisIndexedPropertyDeleter,
1355 CheckThisIndexedPropertyEnumerator);
1356
1357 templ->InstanceTemplate()->SetNamedPropertyHandler(
1358 CheckThisNamedPropertyHandler,
1359 CheckThisNamedPropertySetter,
1360 CheckThisNamedPropertyQuery,
1361 CheckThisNamedPropertyDeleter,
1362 CheckThisNamedPropertyEnumerator);
1363
1364 bottom = templ->GetFunction()->NewInstance();
1365 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1366 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1367
1368 bottom->Set(v8_str("__proto__"), middle);
1369 middle->Set(v8_str("__proto__"), top);
1370 env->Global()->Set(v8_str("obj"), bottom);
1371
1372 // Indexed and named get.
1373 Script::Compile(v8_str("obj[0]"))->Run();
1374 Script::Compile(v8_str("obj.x"))->Run();
1375
1376 // Indexed and named set.
1377 Script::Compile(v8_str("obj[1] = 42"))->Run();
1378 Script::Compile(v8_str("obj.y = 42"))->Run();
1379
1380 // Indexed and named query.
1381 Script::Compile(v8_str("0 in obj"))->Run();
1382 Script::Compile(v8_str("'x' in obj"))->Run();
1383
1384 // Indexed and named deleter.
1385 Script::Compile(v8_str("delete obj[0]"))->Run();
1386 Script::Compile(v8_str("delete obj.x"))->Run();
1387
1388 // Enumerators.
1389 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1390}
1391
1392
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001393static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1394 const AccessorInfo& info) {
1395 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001396 if (v8_str("pre")->Equals(key)) {
1397 return v8_str("PrePropertyHandler: pre");
1398 }
1399 return v8::Handle<String>();
1400}
1401
1402
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001403static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1404 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001405 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001406 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001407 }
1408
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001409 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001410}
1411
1412
1413THREADED_TEST(PrePropertyHandler) {
1414 v8::HandleScope scope;
1415 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1416 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1417 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001418 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001419 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001420 Script::Compile(v8_str(
1421 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1422 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1423 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1424 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1425 CHECK_EQ(v8_str("Object: on"), result_on);
1426 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1427 CHECK(result_post.IsEmpty());
1428}
1429
1430
ager@chromium.org870a0b62008-11-04 11:43:05 +00001431THREADED_TEST(UndefinedIsNotEnumerable) {
1432 v8::HandleScope scope;
1433 LocalContext env;
1434 v8::Handle<Value> result = Script::Compile(v8_str(
1435 "this.propertyIsEnumerable(undefined)"))->Run();
1436 CHECK(result->IsFalse());
1437}
1438
1439
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001440v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001441static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001442
1443
1444static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1445 ApiTestFuzzer::Fuzz();
1446 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1447 if (depth == kTargetRecursionDepth) return v8::Undefined();
1448 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1449 return call_recursively_script->Run();
1450}
1451
1452
1453static v8::Handle<Value> CallFunctionRecursivelyCall(
1454 const v8::Arguments& args) {
1455 ApiTestFuzzer::Fuzz();
1456 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1457 if (depth == kTargetRecursionDepth) {
1458 printf("[depth = %d]\n", depth);
1459 return v8::Undefined();
1460 }
1461 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1462 v8::Handle<Value> function =
1463 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001464 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001465}
1466
1467
1468THREADED_TEST(DeepCrossLanguageRecursion) {
1469 v8::HandleScope scope;
1470 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1471 global->Set(v8_str("callScriptRecursively"),
1472 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1473 global->Set(v8_str("callFunctionRecursively"),
1474 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1475 LocalContext env(NULL, global);
1476
1477 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1478 call_recursively_script = v8_compile("callScriptRecursively()");
1479 v8::Handle<Value> result = call_recursively_script->Run();
1480 call_recursively_script = v8::Handle<Script>();
1481
1482 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1483 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1484}
1485
1486
1487static v8::Handle<Value>
1488 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1489 ApiTestFuzzer::Fuzz();
1490 return v8::ThrowException(key);
1491}
1492
1493
1494static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1495 Local<Value>,
1496 const AccessorInfo&) {
1497 v8::ThrowException(key);
1498 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1499}
1500
1501
1502THREADED_TEST(CallbackExceptionRegression) {
1503 v8::HandleScope scope;
1504 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1505 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1506 ThrowingPropertyHandlerSet);
1507 LocalContext env;
1508 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1509 v8::Handle<Value> otto = Script::Compile(v8_str(
1510 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1511 CHECK_EQ(v8_str("otto"), otto);
1512 v8::Handle<Value> netto = Script::Compile(v8_str(
1513 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1514 CHECK_EQ(v8_str("netto"), netto);
1515}
1516
1517
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001518THREADED_TEST(FunctionPrototype) {
1519 v8::HandleScope scope;
1520 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1521 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1522 LocalContext env;
1523 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1524 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1525 CHECK_EQ(script->Run()->Int32Value(), 321);
1526}
1527
1528
1529THREADED_TEST(InternalFields) {
1530 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001531 LocalContext env;
1532
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001533 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1534 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1535 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001536 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1537 CHECK_EQ(1, obj->InternalFieldCount());
1538 CHECK(obj->GetInternalField(0)->IsUndefined());
1539 obj->SetInternalField(0, v8_num(17));
1540 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1541}
1542
1543
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001544THREADED_TEST(GlobalObjectInternalFields) {
1545 v8::HandleScope scope;
1546 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1547 global_template->SetInternalFieldCount(1);
1548 LocalContext env(NULL, global_template);
1549 v8::Handle<v8::Object> global_proxy = env->Global();
1550 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1551 CHECK_EQ(1, global->InternalFieldCount());
1552 CHECK(global->GetInternalField(0)->IsUndefined());
1553 global->SetInternalField(0, v8_num(17));
1554 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1555}
1556
1557
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001558THREADED_TEST(InternalFieldsNativePointers) {
1559 v8::HandleScope scope;
1560 LocalContext env;
1561
1562 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1563 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1564 instance_templ->SetInternalFieldCount(1);
1565 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1566 CHECK_EQ(1, obj->InternalFieldCount());
1567 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1568
1569 char* data = new char[100];
1570
1571 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001572 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001573 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001574 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001575
1576 // Check reading and writing aligned pointers.
1577 obj->SetPointerInInternalField(0, aligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001578 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001579 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1580
1581 // Check reading and writing unaligned pointers.
1582 obj->SetPointerInInternalField(0, unaligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001583 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001584 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1585
1586 delete[] data;
1587}
1588
1589
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001590THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1591 v8::HandleScope scope;
1592 LocalContext env;
1593
1594 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1595 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1596 instance_templ->SetInternalFieldCount(1);
1597 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1598 CHECK_EQ(1, obj->InternalFieldCount());
1599 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1600
1601 char* data = new char[100];
1602
1603 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001604 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001605 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001606 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001607
1608 obj->SetPointerInInternalField(0, aligned);
1609 i::Heap::CollectAllGarbage(false);
1610 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1611
1612 obj->SetPointerInInternalField(0, unaligned);
1613 i::Heap::CollectAllGarbage(false);
1614 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1615
1616 obj->SetInternalField(0, v8::External::Wrap(aligned));
1617 i::Heap::CollectAllGarbage(false);
1618 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1619
1620 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1621 i::Heap::CollectAllGarbage(false);
1622 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1623
1624 delete[] data;
1625}
1626
1627
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001628THREADED_TEST(IdentityHash) {
1629 v8::HandleScope scope;
1630 LocalContext env;
1631
1632 // Ensure that the test starts with an fresh heap to test whether the hash
1633 // code is based on the address.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001634 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001635 Local<v8::Object> obj = v8::Object::New();
1636 int hash = obj->GetIdentityHash();
1637 int hash1 = obj->GetIdentityHash();
1638 CHECK_EQ(hash, hash1);
1639 int hash2 = v8::Object::New()->GetIdentityHash();
1640 // Since the identity hash is essentially a random number two consecutive
1641 // objects should not be assigned the same hash code. If the test below fails
1642 // the random number generator should be evaluated.
1643 CHECK_NE(hash, hash2);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001644 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001645 int hash3 = v8::Object::New()->GetIdentityHash();
1646 // Make sure that the identity hash is not based on the initial address of
1647 // the object alone. If the test below fails the random number generator
1648 // should be evaluated.
1649 CHECK_NE(hash, hash3);
1650 int hash4 = obj->GetIdentityHash();
1651 CHECK_EQ(hash, hash4);
1652}
1653
1654
1655THREADED_TEST(HiddenProperties) {
1656 v8::HandleScope scope;
1657 LocalContext env;
1658
1659 v8::Local<v8::Object> obj = v8::Object::New();
1660 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1661 v8::Local<v8::String> empty = v8_str("");
1662 v8::Local<v8::String> prop_name = v8_str("prop_name");
1663
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001664 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001665
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001666 // Make sure delete of a non-existent hidden value works
1667 CHECK(obj->DeleteHiddenValue(key));
1668
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001669 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1670 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1671 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1672 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1673
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001674 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001675
1676 // Make sure we do not find the hidden property.
1677 CHECK(!obj->Has(empty));
1678 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1679 CHECK(obj->Get(empty)->IsUndefined());
1680 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1681 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1682 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1683 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1684
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001685 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001686
1687 // Add another property and delete it afterwards to force the object in
1688 // slow case.
1689 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1690 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1691 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1692 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1693 CHECK(obj->Delete(prop_name));
1694 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1695
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001696 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001697
1698 CHECK(obj->DeleteHiddenValue(key));
1699 CHECK(obj->GetHiddenValue(key).IsEmpty());
1700}
1701
1702
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001703static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001704static v8::Handle<Value> InterceptorForHiddenProperties(
1705 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001706 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001707 return v8::Handle<Value>();
1708}
1709
1710
1711THREADED_TEST(HiddenPropertiesWithInterceptors) {
1712 v8::HandleScope scope;
1713 LocalContext context;
1714
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001715 interceptor_for_hidden_properties_called = false;
1716
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001717 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1718
1719 // Associate an interceptor with an object and start setting hidden values.
1720 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1721 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1722 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1723 Local<v8::Function> function = fun_templ->GetFunction();
1724 Local<v8::Object> obj = function->NewInstance();
1725 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1726 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001727 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001728}
1729
1730
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001731THREADED_TEST(External) {
1732 v8::HandleScope scope;
1733 int x = 3;
1734 Local<v8::External> ext = v8::External::New(&x);
1735 LocalContext env;
1736 env->Global()->Set(v8_str("ext"), ext);
1737 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001738 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001739 int* ptr = static_cast<int*>(reext->Value());
1740 CHECK_EQ(x, 3);
1741 *ptr = 10;
1742 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001743
1744 // Make sure unaligned pointers are wrapped properly.
1745 char* data = i::StrDup("0123456789");
1746 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1747 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1748 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1749 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1750
1751 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1752 CHECK_EQ('0', *char_ptr);
1753 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1754 CHECK_EQ('1', *char_ptr);
1755 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1756 CHECK_EQ('2', *char_ptr);
1757 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1758 CHECK_EQ('3', *char_ptr);
1759 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760}
1761
1762
1763THREADED_TEST(GlobalHandle) {
1764 v8::Persistent<String> global;
1765 {
1766 v8::HandleScope scope;
1767 Local<String> str = v8_str("str");
1768 global = v8::Persistent<String>::New(str);
1769 }
1770 CHECK_EQ(global->Length(), 3);
1771 global.Dispose();
1772}
1773
1774
1775THREADED_TEST(ScriptException) {
1776 v8::HandleScope scope;
1777 LocalContext env;
1778 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1779 v8::TryCatch try_catch;
1780 Local<Value> result = script->Run();
1781 CHECK(result.IsEmpty());
1782 CHECK(try_catch.HasCaught());
1783 String::AsciiValue exception_value(try_catch.Exception());
1784 CHECK_EQ(*exception_value, "panama!");
1785}
1786
1787
1788bool message_received;
1789
1790
1791static void check_message(v8::Handle<v8::Message> message,
1792 v8::Handle<Value> data) {
1793 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001794 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001795 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001796 message_received = true;
1797}
1798
1799
1800THREADED_TEST(MessageHandlerData) {
1801 message_received = false;
1802 v8::HandleScope scope;
1803 CHECK(!message_received);
1804 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1805 LocalContext context;
1806 v8::ScriptOrigin origin =
1807 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001808 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1809 &origin);
1810 script->SetData(v8_str("7.56"));
1811 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001812 CHECK(message_received);
1813 // clear out the message listener
1814 v8::V8::RemoveMessageListeners(check_message);
1815}
1816
1817
1818THREADED_TEST(GetSetProperty) {
1819 v8::HandleScope scope;
1820 LocalContext context;
1821 context->Global()->Set(v8_str("foo"), v8_num(14));
1822 context->Global()->Set(v8_str("12"), v8_num(92));
1823 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1824 context->Global()->Set(v8_num(13), v8_num(56));
1825 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1826 CHECK_EQ(14, foo->Int32Value());
1827 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1828 CHECK_EQ(92, twelve->Int32Value());
1829 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1830 CHECK_EQ(32, sixteen->Int32Value());
1831 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1832 CHECK_EQ(56, thirteen->Int32Value());
1833 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1834 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1835 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1836 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1837 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1838 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1839 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1840 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1841 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1842}
1843
1844
1845THREADED_TEST(PropertyAttributes) {
1846 v8::HandleScope scope;
1847 LocalContext context;
1848 // read-only
1849 Local<String> prop = v8_str("read_only");
1850 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1851 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1852 Script::Compile(v8_str("read_only = 9"))->Run();
1853 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1854 context->Global()->Set(prop, v8_num(10));
1855 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1856 // dont-delete
1857 prop = v8_str("dont_delete");
1858 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1859 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1860 Script::Compile(v8_str("delete dont_delete"))->Run();
1861 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1862}
1863
1864
1865THREADED_TEST(Array) {
1866 v8::HandleScope scope;
1867 LocalContext context;
1868 Local<v8::Array> array = v8::Array::New();
1869 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001870 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001871 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001872 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001873 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001874 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001875 CHECK_EQ(3, array->Length());
1876 CHECK(!array->Has(0));
1877 CHECK(!array->Has(1));
1878 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001879 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001881 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001882 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001883 CHECK_EQ(1, arr->Get(0)->Int32Value());
1884 CHECK_EQ(2, arr->Get(1)->Int32Value());
1885 CHECK_EQ(3, arr->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001886}
1887
1888
1889v8::Handle<Value> HandleF(const v8::Arguments& args) {
1890 v8::HandleScope scope;
1891 ApiTestFuzzer::Fuzz();
1892 Local<v8::Array> result = v8::Array::New(args.Length());
1893 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001894 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001895 return scope.Close(result);
1896}
1897
1898
1899THREADED_TEST(Vector) {
1900 v8::HandleScope scope;
1901 Local<ObjectTemplate> global = ObjectTemplate::New();
1902 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1903 LocalContext context(0, global);
1904
1905 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001906 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 CHECK_EQ(0, a0->Length());
1908
1909 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001910 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001911 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001912 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001913
1914 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001915 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001916 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001917 CHECK_EQ(12, a2->Get(0)->Int32Value());
1918 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001919
1920 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001921 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001922 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001923 CHECK_EQ(14, a3->Get(0)->Int32Value());
1924 CHECK_EQ(15, a3->Get(1)->Int32Value());
1925 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926
1927 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001928 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001929 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001930 CHECK_EQ(17, a4->Get(0)->Int32Value());
1931 CHECK_EQ(18, a4->Get(1)->Int32Value());
1932 CHECK_EQ(19, a4->Get(2)->Int32Value());
1933 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001934}
1935
1936
1937THREADED_TEST(FunctionCall) {
1938 v8::HandleScope scope;
1939 LocalContext context;
1940 CompileRun(
1941 "function Foo() {"
1942 " var result = [];"
1943 " for (var i = 0; i < arguments.length; i++) {"
1944 " result.push(arguments[i]);"
1945 " }"
1946 " return result;"
1947 "}");
1948 Local<Function> Foo =
1949 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1950
1951 v8::Handle<Value>* args0 = NULL;
1952 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1953 CHECK_EQ(0, a0->Length());
1954
1955 v8::Handle<Value> args1[] = { v8_num(1.1) };
1956 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1957 CHECK_EQ(1, a1->Length());
1958 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1959
1960 v8::Handle<Value> args2[] = { v8_num(2.2),
1961 v8_num(3.3) };
1962 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1963 CHECK_EQ(2, a2->Length());
1964 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1965 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1966
1967 v8::Handle<Value> args3[] = { v8_num(4.4),
1968 v8_num(5.5),
1969 v8_num(6.6) };
1970 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1971 CHECK_EQ(3, a3->Length());
1972 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1973 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1974 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1975
1976 v8::Handle<Value> args4[] = { v8_num(7.7),
1977 v8_num(8.8),
1978 v8_num(9.9),
1979 v8_num(10.11) };
1980 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1981 CHECK_EQ(4, a4->Length());
1982 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1983 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1984 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1985 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1986}
1987
1988
1989static const char* js_code_causing_out_of_memory =
1990 "var a = new Array(); while(true) a.push(a);";
1991
1992
1993// These tests run for a long time and prevent us from running tests
1994// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001995TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001996 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001997 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001998 // Set heap limits.
1999 static const int K = 1024;
2000 v8::ResourceConstraints constraints;
2001 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002002 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 v8::SetResourceConstraints(&constraints);
2004
2005 // Execute a script that causes out of memory.
2006 v8::HandleScope scope;
2007 LocalContext context;
2008 v8::V8::IgnoreOutOfMemoryException();
2009 Local<Script> script =
2010 Script::Compile(String::New(js_code_causing_out_of_memory));
2011 Local<Value> result = script->Run();
2012
2013 // Check for out of memory state.
2014 CHECK(result.IsEmpty());
2015 CHECK(context->HasOutOfMemoryException());
2016}
2017
2018
2019v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2020 ApiTestFuzzer::Fuzz();
2021
2022 v8::HandleScope scope;
2023 LocalContext context;
2024 Local<Script> script =
2025 Script::Compile(String::New(js_code_causing_out_of_memory));
2026 Local<Value> result = script->Run();
2027
2028 // Check for out of memory state.
2029 CHECK(result.IsEmpty());
2030 CHECK(context->HasOutOfMemoryException());
2031
2032 return result;
2033}
2034
2035
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002036TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002037 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002038 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039 // Set heap limits.
2040 static const int K = 1024;
2041 v8::ResourceConstraints constraints;
2042 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002043 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002044 v8::SetResourceConstraints(&constraints);
2045
2046 v8::HandleScope scope;
2047 Local<ObjectTemplate> templ = ObjectTemplate::New();
2048 templ->Set(v8_str("ProvokeOutOfMemory"),
2049 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2050 LocalContext context(0, templ);
2051 v8::V8::IgnoreOutOfMemoryException();
2052 Local<Value> result = CompileRun(
2053 "var thrown = false;"
2054 "try {"
2055 " ProvokeOutOfMemory();"
2056 "} catch (e) {"
2057 " thrown = true;"
2058 "}");
2059 // Check for out of memory state.
2060 CHECK(result.IsEmpty());
2061 CHECK(context->HasOutOfMemoryException());
2062}
2063
2064
2065TEST(HugeConsStringOutOfMemory) {
2066 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002067 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002068 v8::HandleScope scope;
2069 LocalContext context;
2070 // Set heap limits.
2071 static const int K = 1024;
2072 v8::ResourceConstraints constraints;
2073 constraints.set_max_young_space_size(256 * K);
2074 constraints.set_max_old_space_size(2 * K * K);
2075 v8::SetResourceConstraints(&constraints);
2076
2077 // Execute a script that causes out of memory.
2078 v8::V8::IgnoreOutOfMemoryException();
2079
2080 // Build huge string. This should fail with out of memory exception.
2081 Local<Value> result = CompileRun(
2082 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002083 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002084
2085 // Check for out of memory state.
2086 CHECK(result.IsEmpty());
2087 CHECK(context->HasOutOfMemoryException());
2088}
2089
2090
2091THREADED_TEST(ConstructCall) {
2092 v8::HandleScope scope;
2093 LocalContext context;
2094 CompileRun(
2095 "function Foo() {"
2096 " var result = [];"
2097 " for (var i = 0; i < arguments.length; i++) {"
2098 " result.push(arguments[i]);"
2099 " }"
2100 " return result;"
2101 "}");
2102 Local<Function> Foo =
2103 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2104
2105 v8::Handle<Value>* args0 = NULL;
2106 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2107 CHECK_EQ(0, a0->Length());
2108
2109 v8::Handle<Value> args1[] = { v8_num(1.1) };
2110 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2111 CHECK_EQ(1, a1->Length());
2112 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2113
2114 v8::Handle<Value> args2[] = { v8_num(2.2),
2115 v8_num(3.3) };
2116 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2117 CHECK_EQ(2, a2->Length());
2118 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2119 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2120
2121 v8::Handle<Value> args3[] = { v8_num(4.4),
2122 v8_num(5.5),
2123 v8_num(6.6) };
2124 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2125 CHECK_EQ(3, a3->Length());
2126 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2127 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2128 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2129
2130 v8::Handle<Value> args4[] = { v8_num(7.7),
2131 v8_num(8.8),
2132 v8_num(9.9),
2133 v8_num(10.11) };
2134 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2135 CHECK_EQ(4, a4->Length());
2136 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2137 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2138 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2139 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2140}
2141
2142
2143static void CheckUncle(v8::TryCatch* try_catch) {
2144 CHECK(try_catch->HasCaught());
2145 String::AsciiValue str_value(try_catch->Exception());
2146 CHECK_EQ(*str_value, "uncle?");
2147 try_catch->Reset();
2148}
2149
2150
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002151THREADED_TEST(ConversionNumber) {
2152 v8::HandleScope scope;
2153 LocalContext env;
2154 // Very large number.
2155 CompileRun("var obj = Math.pow(2,32) * 1237;");
2156 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2157 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2158 CHECK_EQ(0, obj->ToInt32()->Value());
2159 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2160 // Large number.
2161 CompileRun("var obj = -1234567890123;");
2162 obj = env->Global()->Get(v8_str("obj"));
2163 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2164 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2165 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2166 // Small positive integer.
2167 CompileRun("var obj = 42;");
2168 obj = env->Global()->Get(v8_str("obj"));
2169 CHECK_EQ(42.0, obj->ToNumber()->Value());
2170 CHECK_EQ(42, obj->ToInt32()->Value());
2171 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2172 // Negative integer.
2173 CompileRun("var obj = -37;");
2174 obj = env->Global()->Get(v8_str("obj"));
2175 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2176 CHECK_EQ(-37, obj->ToInt32()->Value());
2177 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2178 // Positive non-int32 integer.
2179 CompileRun("var obj = 0x81234567;");
2180 obj = env->Global()->Get(v8_str("obj"));
2181 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2182 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2183 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2184 // Fraction.
2185 CompileRun("var obj = 42.3;");
2186 obj = env->Global()->Get(v8_str("obj"));
2187 CHECK_EQ(42.3, obj->ToNumber()->Value());
2188 CHECK_EQ(42, obj->ToInt32()->Value());
2189 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2190 // Large negative fraction.
2191 CompileRun("var obj = -5726623061.75;");
2192 obj = env->Global()->Get(v8_str("obj"));
2193 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2194 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2195 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2196}
2197
2198
2199THREADED_TEST(isNumberType) {
2200 v8::HandleScope scope;
2201 LocalContext env;
2202 // Very large number.
2203 CompileRun("var obj = Math.pow(2,32) * 1237;");
2204 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2205 CHECK(!obj->IsInt32());
2206 CHECK(!obj->IsUint32());
2207 // Large negative number.
2208 CompileRun("var obj = -1234567890123;");
2209 obj = env->Global()->Get(v8_str("obj"));
2210 CHECK(!obj->IsInt32());
2211 CHECK(!obj->IsUint32());
2212 // Small positive integer.
2213 CompileRun("var obj = 42;");
2214 obj = env->Global()->Get(v8_str("obj"));
2215 CHECK(obj->IsInt32());
2216 CHECK(obj->IsUint32());
2217 // Negative integer.
2218 CompileRun("var obj = -37;");
2219 obj = env->Global()->Get(v8_str("obj"));
2220 CHECK(obj->IsInt32());
2221 CHECK(!obj->IsUint32());
2222 // Positive non-int32 integer.
2223 CompileRun("var obj = 0x81234567;");
2224 obj = env->Global()->Get(v8_str("obj"));
2225 CHECK(!obj->IsInt32());
2226 CHECK(obj->IsUint32());
2227 // Fraction.
2228 CompileRun("var obj = 42.3;");
2229 obj = env->Global()->Get(v8_str("obj"));
2230 CHECK(!obj->IsInt32());
2231 CHECK(!obj->IsUint32());
2232 // Large negative fraction.
2233 CompileRun("var obj = -5726623061.75;");
2234 obj = env->Global()->Get(v8_str("obj"));
2235 CHECK(!obj->IsInt32());
2236 CHECK(!obj->IsUint32());
2237}
2238
2239
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002240THREADED_TEST(ConversionException) {
2241 v8::HandleScope scope;
2242 LocalContext env;
2243 CompileRun(
2244 "function TestClass() { };"
2245 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2246 "var obj = new TestClass();");
2247 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2248
2249 v8::TryCatch try_catch;
2250
2251 Local<Value> to_string_result = obj->ToString();
2252 CHECK(to_string_result.IsEmpty());
2253 CheckUncle(&try_catch);
2254
2255 Local<Value> to_number_result = obj->ToNumber();
2256 CHECK(to_number_result.IsEmpty());
2257 CheckUncle(&try_catch);
2258
2259 Local<Value> to_integer_result = obj->ToInteger();
2260 CHECK(to_integer_result.IsEmpty());
2261 CheckUncle(&try_catch);
2262
2263 Local<Value> to_uint32_result = obj->ToUint32();
2264 CHECK(to_uint32_result.IsEmpty());
2265 CheckUncle(&try_catch);
2266
2267 Local<Value> to_int32_result = obj->ToInt32();
2268 CHECK(to_int32_result.IsEmpty());
2269 CheckUncle(&try_catch);
2270
2271 Local<Value> to_object_result = v8::Undefined()->ToObject();
2272 CHECK(to_object_result.IsEmpty());
2273 CHECK(try_catch.HasCaught());
2274 try_catch.Reset();
2275
2276 int32_t int32_value = obj->Int32Value();
2277 CHECK_EQ(0, int32_value);
2278 CheckUncle(&try_catch);
2279
2280 uint32_t uint32_value = obj->Uint32Value();
2281 CHECK_EQ(0, uint32_value);
2282 CheckUncle(&try_catch);
2283
2284 double number_value = obj->NumberValue();
2285 CHECK_NE(0, IsNaN(number_value));
2286 CheckUncle(&try_catch);
2287
2288 int64_t integer_value = obj->IntegerValue();
2289 CHECK_EQ(0.0, static_cast<double>(integer_value));
2290 CheckUncle(&try_catch);
2291}
2292
2293
2294v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2295 ApiTestFuzzer::Fuzz();
2296 return v8::ThrowException(v8_str("konto"));
2297}
2298
2299
ager@chromium.org8bb60582008-12-11 12:02:20 +00002300v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2301 if (args.Length() < 1) return v8::Boolean::New(false);
2302 v8::HandleScope scope;
2303 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002304 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2305 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002306 return v8::Boolean::New(try_catch.HasCaught());
2307}
2308
2309
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002310THREADED_TEST(APICatch) {
2311 v8::HandleScope scope;
2312 Local<ObjectTemplate> templ = ObjectTemplate::New();
2313 templ->Set(v8_str("ThrowFromC"),
2314 v8::FunctionTemplate::New(ThrowFromC));
2315 LocalContext context(0, templ);
2316 CompileRun(
2317 "var thrown = false;"
2318 "try {"
2319 " ThrowFromC();"
2320 "} catch (e) {"
2321 " thrown = true;"
2322 "}");
2323 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2324 CHECK(thrown->BooleanValue());
2325}
2326
2327
ager@chromium.org8bb60582008-12-11 12:02:20 +00002328THREADED_TEST(APIThrowTryCatch) {
2329 v8::HandleScope scope;
2330 Local<ObjectTemplate> templ = ObjectTemplate::New();
2331 templ->Set(v8_str("ThrowFromC"),
2332 v8::FunctionTemplate::New(ThrowFromC));
2333 LocalContext context(0, templ);
2334 v8::TryCatch try_catch;
2335 CompileRun("ThrowFromC();");
2336 CHECK(try_catch.HasCaught());
2337}
2338
2339
2340// Test that a try-finally block doesn't shadow a try-catch block
2341// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002342//
2343// BUG(271): Some of the exception propagation does not work on the
2344// ARM simulator because the simulator separates the C++ stack and the
2345// JS stack. This test therefore fails on the simulator. The test is
2346// not threaded to allow the threading tests to run on the simulator.
2347TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002348 v8::HandleScope scope;
2349 Local<ObjectTemplate> templ = ObjectTemplate::New();
2350 templ->Set(v8_str("CCatcher"),
2351 v8::FunctionTemplate::New(CCatcher));
2352 LocalContext context(0, templ);
2353 Local<Value> result = CompileRun("try {"
2354 " try {"
2355 " CCatcher('throw 7;');"
2356 " } finally {"
2357 " }"
2358 "} catch (e) {"
2359 "}");
2360 CHECK(result->IsTrue());
2361}
2362
2363
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002364static void check_reference_error_message(
2365 v8::Handle<v8::Message> message,
2366 v8::Handle<v8::Value> data) {
2367 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2368 CHECK(message->Get()->Equals(v8_str(reference_error)));
2369}
2370
2371
2372// Test that overwritten toString methods are not invoked on uncaught
2373// exception formatting. However, they are invoked when performing
2374// normal error string conversions.
2375TEST(APIThrowMessageOverwrittenToString) {
2376 v8::HandleScope scope;
2377 v8::V8::AddMessageListener(check_reference_error_message);
2378 LocalContext context;
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002379 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2380 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002381 CompileRun("ReferenceError.prototype.toString ="
2382 " function() { return 'Whoops' }");
2383 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002384 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2385 CompileRun("asdf;");
2386 CompileRun("ReferenceError.prototype.constructor = void 0;");
2387 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002388 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2389 CompileRun("asdf;");
2390 CompileRun("ReferenceError.prototype = new Object();");
2391 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002392 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2393 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002394 CompileRun("ReferenceError.prototype.constructor = new Object();"
2395 "ReferenceError.prototype.constructor.name = 1;"
2396 "Number.prototype.toString = function() { return 'Whoops'; };"
2397 "ReferenceError.prototype.toString = Object.prototype.toString;");
2398 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002399 v8::V8::RemoveMessageListeners(check_message);
2400}
2401
2402
ager@chromium.org8bb60582008-12-11 12:02:20 +00002403static void receive_message(v8::Handle<v8::Message> message,
2404 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002405 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002406 message_received = true;
2407}
2408
2409
2410TEST(APIThrowMessage) {
2411 message_received = false;
2412 v8::HandleScope scope;
2413 v8::V8::AddMessageListener(receive_message);
2414 Local<ObjectTemplate> templ = ObjectTemplate::New();
2415 templ->Set(v8_str("ThrowFromC"),
2416 v8::FunctionTemplate::New(ThrowFromC));
2417 LocalContext context(0, templ);
2418 CompileRun("ThrowFromC();");
2419 CHECK(message_received);
2420 v8::V8::RemoveMessageListeners(check_message);
2421}
2422
2423
2424TEST(APIThrowMessageAndVerboseTryCatch) {
2425 message_received = false;
2426 v8::HandleScope scope;
2427 v8::V8::AddMessageListener(receive_message);
2428 Local<ObjectTemplate> templ = ObjectTemplate::New();
2429 templ->Set(v8_str("ThrowFromC"),
2430 v8::FunctionTemplate::New(ThrowFromC));
2431 LocalContext context(0, templ);
2432 v8::TryCatch try_catch;
2433 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002434 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002435 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002436 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002437 CHECK(message_received);
2438 v8::V8::RemoveMessageListeners(check_message);
2439}
2440
2441
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002442THREADED_TEST(ExternalScriptException) {
2443 v8::HandleScope scope;
2444 Local<ObjectTemplate> templ = ObjectTemplate::New();
2445 templ->Set(v8_str("ThrowFromC"),
2446 v8::FunctionTemplate::New(ThrowFromC));
2447 LocalContext context(0, templ);
2448
2449 v8::TryCatch try_catch;
2450 Local<Script> script
2451 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2452 Local<Value> result = script->Run();
2453 CHECK(result.IsEmpty());
2454 CHECK(try_catch.HasCaught());
2455 String::AsciiValue exception_value(try_catch.Exception());
2456 CHECK_EQ("konto", *exception_value);
2457}
2458
2459
2460
2461v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2462 ApiTestFuzzer::Fuzz();
2463 CHECK_EQ(4, args.Length());
2464 int count = args[0]->Int32Value();
2465 int cInterval = args[2]->Int32Value();
2466 if (count == 0) {
2467 return v8::ThrowException(v8_str("FromC"));
2468 } else {
2469 Local<v8::Object> global = Context::GetCurrent()->Global();
2470 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2471 v8::Handle<Value> argv[] = { v8_num(count - 1),
2472 args[1],
2473 args[2],
2474 args[3] };
2475 if (count % cInterval == 0) {
2476 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002477 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002478 int expected = args[3]->Int32Value();
2479 if (try_catch.HasCaught()) {
2480 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002481 CHECK(result.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002482 CHECK(!i::Top::has_scheduled_exception());
2483 } else {
2484 CHECK_NE(expected, count);
2485 }
2486 return result;
2487 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002488 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002489 }
2490 }
2491}
2492
2493
2494v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2495 ApiTestFuzzer::Fuzz();
2496 CHECK_EQ(3, args.Length());
2497 bool equality = args[0]->BooleanValue();
2498 int count = args[1]->Int32Value();
2499 int expected = args[2]->Int32Value();
2500 if (equality) {
2501 CHECK_EQ(count, expected);
2502 } else {
2503 CHECK_NE(count, expected);
2504 }
2505 return v8::Undefined();
2506}
2507
2508
ager@chromium.org8bb60582008-12-11 12:02:20 +00002509THREADED_TEST(EvalInTryFinally) {
2510 v8::HandleScope scope;
2511 LocalContext context;
2512 v8::TryCatch try_catch;
2513 CompileRun("(function() {"
2514 " try {"
2515 " eval('asldkf (*&^&*^');"
2516 " } finally {"
2517 " return;"
2518 " }"
2519 "})()");
2520 CHECK(!try_catch.HasCaught());
2521}
2522
2523
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002524// This test works by making a stack of alternating JavaScript and C
2525// activations. These activations set up exception handlers with regular
2526// intervals, one interval for C activations and another for JavaScript
2527// activations. When enough activations have been created an exception is
2528// thrown and we check that the right activation catches the exception and that
2529// no other activations do. The right activation is always the topmost one with
2530// a handler, regardless of whether it is in JavaScript or C.
2531//
2532// The notation used to describe a test case looks like this:
2533//
2534// *JS[4] *C[3] @JS[2] C[1] JS[0]
2535//
2536// Each entry is an activation, either JS or C. The index is the count at that
2537// level. Stars identify activations with exception handlers, the @ identifies
2538// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002539//
2540// BUG(271): Some of the exception propagation does not work on the
2541// ARM simulator because the simulator separates the C++ stack and the
2542// JS stack. This test therefore fails on the simulator. The test is
2543// not threaded to allow the threading tests to run on the simulator.
2544TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002545 v8::HandleScope scope;
2546 Local<ObjectTemplate> templ = ObjectTemplate::New();
2547 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2548 templ->Set(v8_str("CThrowCountDown"),
2549 v8::FunctionTemplate::New(CThrowCountDown));
2550 LocalContext context(0, templ);
2551 CompileRun(
2552 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2553 " if (count == 0) throw 'FromJS';"
2554 " if (count % jsInterval == 0) {"
2555 " try {"
2556 " var value = CThrowCountDown(count - 1,"
2557 " jsInterval,"
2558 " cInterval,"
2559 " expected);"
2560 " check(false, count, expected);"
2561 " return value;"
2562 " } catch (e) {"
2563 " check(true, count, expected);"
2564 " }"
2565 " } else {"
2566 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2567 " }"
2568 "}");
2569 Local<Function> fun =
2570 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2571
2572 const int argc = 4;
2573 // count jsInterval cInterval expected
2574
2575 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2576 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2577 fun->Call(fun, argc, a0);
2578
2579 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2580 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2581 fun->Call(fun, argc, a1);
2582
2583 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2584 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2585 fun->Call(fun, argc, a2);
2586
2587 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2588 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2589 fun->Call(fun, argc, a3);
2590
2591 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2592 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2593 fun->Call(fun, argc, a4);
2594
2595 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2596 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2597 fun->Call(fun, argc, a5);
2598}
2599
2600
2601v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2602 ApiTestFuzzer::Fuzz();
2603 CHECK_EQ(1, args.Length());
2604 return v8::ThrowException(args[0]);
2605}
2606
2607
2608THREADED_TEST(ThrowValues) {
2609 v8::HandleScope scope;
2610 Local<ObjectTemplate> templ = ObjectTemplate::New();
2611 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2612 LocalContext context(0, templ);
2613 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2614 "function Run(obj) {"
2615 " try {"
2616 " Throw(obj);"
2617 " } catch (e) {"
2618 " return e;"
2619 " }"
2620 " return 'no exception';"
2621 "}"
2622 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2623 CHECK_EQ(5, result->Length());
2624 CHECK(result->Get(v8::Integer::New(0))->IsString());
2625 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2626 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2627 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2628 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2629 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2630 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2631}
2632
2633
2634THREADED_TEST(CatchZero) {
2635 v8::HandleScope scope;
2636 LocalContext context;
2637 v8::TryCatch try_catch;
2638 CHECK(!try_catch.HasCaught());
2639 Script::Compile(v8_str("throw 10"))->Run();
2640 CHECK(try_catch.HasCaught());
2641 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2642 try_catch.Reset();
2643 CHECK(!try_catch.HasCaught());
2644 Script::Compile(v8_str("throw 0"))->Run();
2645 CHECK(try_catch.HasCaught());
2646 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2647}
2648
2649
2650THREADED_TEST(CatchExceptionFromWith) {
2651 v8::HandleScope scope;
2652 LocalContext context;
2653 v8::TryCatch try_catch;
2654 CHECK(!try_catch.HasCaught());
2655 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2656 CHECK(try_catch.HasCaught());
2657}
2658
2659
2660THREADED_TEST(Equality) {
2661 v8::HandleScope scope;
2662 LocalContext context;
2663 // Check that equality works at all before relying on CHECK_EQ
2664 CHECK(v8_str("a")->Equals(v8_str("a")));
2665 CHECK(!v8_str("a")->Equals(v8_str("b")));
2666
2667 CHECK_EQ(v8_str("a"), v8_str("a"));
2668 CHECK_NE(v8_str("a"), v8_str("b"));
2669 CHECK_EQ(v8_num(1), v8_num(1));
2670 CHECK_EQ(v8_num(1.00), v8_num(1));
2671 CHECK_NE(v8_num(1), v8_num(2));
2672
2673 // Assume String is not symbol.
2674 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2675 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2676 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2677 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2678 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2679 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2680 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2681 CHECK(!not_a_number->StrictEquals(not_a_number));
2682 CHECK(v8::False()->StrictEquals(v8::False()));
2683 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2684
2685 v8::Handle<v8::Object> obj = v8::Object::New();
2686 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2687 CHECK(alias->StrictEquals(obj));
2688 alias.Dispose();
2689}
2690
2691
2692THREADED_TEST(MultiRun) {
2693 v8::HandleScope scope;
2694 LocalContext context;
2695 Local<Script> script = Script::Compile(v8_str("x"));
2696 for (int i = 0; i < 10; i++)
2697 script->Run();
2698}
2699
2700
2701static v8::Handle<Value> GetXValue(Local<String> name,
2702 const AccessorInfo& info) {
2703 ApiTestFuzzer::Fuzz();
2704 CHECK_EQ(info.Data(), v8_str("donut"));
2705 CHECK_EQ(name, v8_str("x"));
2706 return name;
2707}
2708
2709
2710THREADED_TEST(SimplePropertyRead) {
2711 v8::HandleScope scope;
2712 Local<ObjectTemplate> templ = ObjectTemplate::New();
2713 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2714 LocalContext context;
2715 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2716 Local<Script> script = Script::Compile(v8_str("obj.x"));
2717 for (int i = 0; i < 10; i++) {
2718 Local<Value> result = script->Run();
2719 CHECK_EQ(result, v8_str("x"));
2720 }
2721}
2722
ager@chromium.org5c838252010-02-19 08:53:10 +00002723THREADED_TEST(DefinePropertyOnAPIAccessor) {
2724 v8::HandleScope scope;
2725 Local<ObjectTemplate> templ = ObjectTemplate::New();
2726 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2727 LocalContext context;
2728 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2729
2730 // Uses getOwnPropertyDescriptor to check the configurable status
2731 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002732 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00002733 "obj, 'x');"
2734 "prop.configurable;"));
2735 Local<Value> result = script_desc->Run();
2736 CHECK_EQ(result->BooleanValue(), true);
2737
2738 // Redefine get - but still configurable
2739 Local<Script> script_define
2740 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2741 " configurable: true };"
2742 "Object.defineProperty(obj, 'x', desc);"
2743 "obj.x"));
2744 result = script_define->Run();
2745 CHECK_EQ(result, v8_num(42));
2746
2747 // Check that the accessor is still configurable
2748 result = script_desc->Run();
2749 CHECK_EQ(result->BooleanValue(), true);
2750
2751 // Redefine to a non-configurable
2752 script_define
2753 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2754 " configurable: false };"
2755 "Object.defineProperty(obj, 'x', desc);"
2756 "obj.x"));
2757 result = script_define->Run();
2758 CHECK_EQ(result, v8_num(43));
2759 result = script_desc->Run();
2760 CHECK_EQ(result->BooleanValue(), false);
2761
2762 // Make sure that it is not possible to redefine again
2763 v8::TryCatch try_catch;
2764 result = script_define->Run();
2765 CHECK(try_catch.HasCaught());
2766 String::AsciiValue exception_value(try_catch.Exception());
2767 CHECK_EQ(*exception_value,
2768 "TypeError: Cannot redefine property: defineProperty");
2769}
2770
2771THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2772 v8::HandleScope scope;
2773 Local<ObjectTemplate> templ = ObjectTemplate::New();
2774 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2775 LocalContext context;
2776 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2777
2778 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2779 "Object.getOwnPropertyDescriptor( "
2780 "obj, 'x');"
2781 "prop.configurable;"));
2782 Local<Value> result = script_desc->Run();
2783 CHECK_EQ(result->BooleanValue(), true);
2784
2785 Local<Script> script_define =
2786 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2787 " configurable: true };"
2788 "Object.defineProperty(obj, 'x', desc);"
2789 "obj.x"));
2790 result = script_define->Run();
2791 CHECK_EQ(result, v8_num(42));
2792
2793
2794 result = script_desc->Run();
2795 CHECK_EQ(result->BooleanValue(), true);
2796
2797
2798 script_define =
2799 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2800 " configurable: false };"
2801 "Object.defineProperty(obj, 'x', desc);"
2802 "obj.x"));
2803 result = script_define->Run();
2804 CHECK_EQ(result, v8_num(43));
2805 result = script_desc->Run();
2806
2807 CHECK_EQ(result->BooleanValue(), false);
2808
2809 v8::TryCatch try_catch;
2810 result = script_define->Run();
2811 CHECK(try_catch.HasCaught());
2812 String::AsciiValue exception_value(try_catch.Exception());
2813 CHECK_EQ(*exception_value,
2814 "TypeError: Cannot redefine property: defineProperty");
2815}
2816
2817
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002818static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2819 char const* name) {
2820 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2821}
ager@chromium.org5c838252010-02-19 08:53:10 +00002822
2823
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002824THREADED_TEST(DefineAPIAccessorOnObject) {
2825 v8::HandleScope scope;
2826 Local<ObjectTemplate> templ = ObjectTemplate::New();
2827 LocalContext context;
2828
2829 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2830 CompileRun("var obj2 = {};");
2831
2832 CHECK(CompileRun("obj1.x")->IsUndefined());
2833 CHECK(CompileRun("obj2.x")->IsUndefined());
2834
2835 CHECK(GetGlobalProperty(&context, "obj1")->
2836 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2837
2838 ExpectString("obj1.x", "x");
2839 CHECK(CompileRun("obj2.x")->IsUndefined());
2840
2841 CHECK(GetGlobalProperty(&context, "obj2")->
2842 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2843
2844 ExpectString("obj1.x", "x");
2845 ExpectString("obj2.x", "x");
2846
2847 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2848 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2849
2850 CompileRun("Object.defineProperty(obj1, 'x',"
2851 "{ get: function() { return 'y'; }, configurable: true })");
2852
2853 ExpectString("obj1.x", "y");
2854 ExpectString("obj2.x", "x");
2855
2856 CompileRun("Object.defineProperty(obj2, 'x',"
2857 "{ get: function() { return 'y'; }, configurable: true })");
2858
2859 ExpectString("obj1.x", "y");
2860 ExpectString("obj2.x", "y");
2861
2862 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2863 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2864
2865 CHECK(GetGlobalProperty(&context, "obj1")->
2866 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2867 CHECK(GetGlobalProperty(&context, "obj2")->
2868 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2869
2870 ExpectString("obj1.x", "x");
2871 ExpectString("obj2.x", "x");
2872
2873 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2874 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2875
2876 // Define getters/setters, but now make them not configurable.
2877 CompileRun("Object.defineProperty(obj1, 'x',"
2878 "{ get: function() { return 'z'; }, configurable: false })");
2879 CompileRun("Object.defineProperty(obj2, 'x',"
2880 "{ get: function() { return 'z'; }, configurable: false })");
2881
2882 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2883 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2884
2885 ExpectString("obj1.x", "z");
2886 ExpectString("obj2.x", "z");
2887
2888 CHECK(!GetGlobalProperty(&context, "obj1")->
2889 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2890 CHECK(!GetGlobalProperty(&context, "obj2")->
2891 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2892
2893 ExpectString("obj1.x", "z");
2894 ExpectString("obj2.x", "z");
2895}
2896
2897
2898THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2899 v8::HandleScope scope;
2900 Local<ObjectTemplate> templ = ObjectTemplate::New();
2901 LocalContext context;
2902
2903 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2904 CompileRun("var obj2 = {};");
2905
2906 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2907 v8_str("x"),
2908 GetXValue, NULL,
2909 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2910 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2911 v8_str("x"),
2912 GetXValue, NULL,
2913 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2914
2915 ExpectString("obj1.x", "x");
2916 ExpectString("obj2.x", "x");
2917
2918 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2919 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2920
2921 CHECK(!GetGlobalProperty(&context, "obj1")->
2922 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2923 CHECK(!GetGlobalProperty(&context, "obj2")->
2924 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2925
2926 {
2927 v8::TryCatch try_catch;
2928 CompileRun("Object.defineProperty(obj1, 'x',"
2929 "{get: function() { return 'func'; }})");
2930 CHECK(try_catch.HasCaught());
2931 String::AsciiValue exception_value(try_catch.Exception());
2932 CHECK_EQ(*exception_value,
2933 "TypeError: Cannot redefine property: defineProperty");
2934 }
2935 {
2936 v8::TryCatch try_catch;
2937 CompileRun("Object.defineProperty(obj2, 'x',"
2938 "{get: function() { return 'func'; }})");
2939 CHECK(try_catch.HasCaught());
2940 String::AsciiValue exception_value(try_catch.Exception());
2941 CHECK_EQ(*exception_value,
2942 "TypeError: Cannot redefine property: defineProperty");
2943 }
2944}
2945
2946
2947static v8::Handle<Value> Get239Value(Local<String> name,
2948 const AccessorInfo& info) {
2949 ApiTestFuzzer::Fuzz();
2950 CHECK_EQ(info.Data(), v8_str("donut"));
2951 CHECK_EQ(name, v8_str("239"));
2952 return name;
2953}
2954
2955
2956THREADED_TEST(ElementAPIAccessor) {
2957 v8::HandleScope scope;
2958 Local<ObjectTemplate> templ = ObjectTemplate::New();
2959 LocalContext context;
2960
2961 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2962 CompileRun("var obj2 = {};");
2963
2964 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2965 v8_str("239"),
2966 Get239Value, NULL,
2967 v8_str("donut")));
2968 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2969 v8_str("239"),
2970 Get239Value, NULL,
2971 v8_str("donut")));
2972
2973 ExpectString("obj1[239]", "239");
2974 ExpectString("obj2[239]", "239");
2975 ExpectString("obj1['239']", "239");
2976 ExpectString("obj2['239']", "239");
2977}
2978
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002979
2980v8::Persistent<Value> xValue;
2981
2982
2983static void SetXValue(Local<String> name,
2984 Local<Value> value,
2985 const AccessorInfo& info) {
2986 CHECK_EQ(value, v8_num(4));
2987 CHECK_EQ(info.Data(), v8_str("donut"));
2988 CHECK_EQ(name, v8_str("x"));
2989 CHECK(xValue.IsEmpty());
2990 xValue = v8::Persistent<Value>::New(value);
2991}
2992
2993
2994THREADED_TEST(SimplePropertyWrite) {
2995 v8::HandleScope scope;
2996 Local<ObjectTemplate> templ = ObjectTemplate::New();
2997 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2998 LocalContext context;
2999 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3000 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3001 for (int i = 0; i < 10; i++) {
3002 CHECK(xValue.IsEmpty());
3003 script->Run();
3004 CHECK_EQ(v8_num(4), xValue);
3005 xValue.Dispose();
3006 xValue = v8::Persistent<Value>();
3007 }
3008}
3009
3010
3011static v8::Handle<Value> XPropertyGetter(Local<String> property,
3012 const AccessorInfo& info) {
3013 ApiTestFuzzer::Fuzz();
3014 CHECK(info.Data()->IsUndefined());
3015 return property;
3016}
3017
3018
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003019THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003020 v8::HandleScope scope;
3021 Local<ObjectTemplate> templ = ObjectTemplate::New();
3022 templ->SetNamedPropertyHandler(XPropertyGetter);
3023 LocalContext context;
3024 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3025 Local<Script> script = Script::Compile(v8_str("obj.x"));
3026 for (int i = 0; i < 10; i++) {
3027 Local<Value> result = script->Run();
3028 CHECK_EQ(result, v8_str("x"));
3029 }
3030}
3031
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003032
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003033THREADED_TEST(NamedInterceptorDictionaryIC) {
3034 v8::HandleScope scope;
3035 Local<ObjectTemplate> templ = ObjectTemplate::New();
3036 templ->SetNamedPropertyHandler(XPropertyGetter);
3037 LocalContext context;
3038 // Create an object with a named interceptor.
3039 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3040 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3041 for (int i = 0; i < 10; i++) {
3042 Local<Value> result = script->Run();
3043 CHECK_EQ(result, v8_str("x"));
3044 }
3045 // Create a slow case object and a function accessing a property in
3046 // that slow case object (with dictionary probing in generated
3047 // code). Then force object with a named interceptor into slow-case,
3048 // pass it to the function, and check that the interceptor is called
3049 // instead of accessing the local property.
3050 Local<Value> result =
3051 CompileRun("function get_x(o) { return o.x; };"
3052 "var obj = { x : 42, y : 0 };"
3053 "delete obj.y;"
3054 "for (var i = 0; i < 10; i++) get_x(obj);"
3055 "interceptor_obj.x = 42;"
3056 "interceptor_obj.y = 10;"
3057 "delete interceptor_obj.y;"
3058 "get_x(interceptor_obj)");
3059 CHECK_EQ(result, v8_str("x"));
3060}
3061
3062
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003063THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3064 v8::HandleScope scope;
3065
3066 v8::Persistent<Context> context1 = Context::New();
3067
3068 context1->Enter();
3069 Local<ObjectTemplate> templ = ObjectTemplate::New();
3070 templ->SetNamedPropertyHandler(XPropertyGetter);
3071 // Create an object with a named interceptor.
3072 v8::Local<v8::Object> object = templ->NewInstance();
3073 context1->Global()->Set(v8_str("interceptor_obj"), object);
3074
3075 // Force the object into the slow case.
3076 CompileRun("interceptor_obj.y = 0;"
3077 "delete interceptor_obj.y;");
3078 context1->Exit();
3079
3080 {
3081 // Introduce the object into a different context.
3082 // Repeat named loads to exercise ICs.
3083 LocalContext context2;
3084 context2->Global()->Set(v8_str("interceptor_obj"), object);
3085 Local<Value> result =
3086 CompileRun("function get_x(o) { return o.x; }"
3087 "interceptor_obj.x = 42;"
3088 "for (var i=0; i != 10; i++) {"
3089 " get_x(interceptor_obj);"
3090 "}"
3091 "get_x(interceptor_obj)");
3092 // Check that the interceptor was actually invoked.
3093 CHECK_EQ(result, v8_str("x"));
3094 }
3095
3096 // Return to the original context and force some object to the slow case
3097 // to cause the NormalizedMapCache to verify.
3098 context1->Enter();
3099 CompileRun("var obj = { x : 0 }; delete obj.x;");
3100 context1->Exit();
3101
3102 context1.Dispose();
3103}
3104
3105
ager@chromium.org5c838252010-02-19 08:53:10 +00003106static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3107 const AccessorInfo& info) {
3108 // Set x on the prototype object and do not handle the get request.
3109 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003110 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003111 return v8::Handle<Value>();
3112}
3113
3114
3115// This is a regression test for http://crbug.com/20104. Map
3116// transitions should not interfere with post interceptor lookup.
3117THREADED_TEST(NamedInterceptorMapTransitionRead) {
3118 v8::HandleScope scope;
3119 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3120 Local<v8::ObjectTemplate> instance_template
3121 = function_template->InstanceTemplate();
3122 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3123 LocalContext context;
3124 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3125 // Create an instance of F and introduce a map transition for x.
3126 CompileRun("var o = new F(); o.x = 23;");
3127 // Create an instance of F and invoke the getter. The result should be 23.
3128 Local<Value> result = CompileRun("o = new F(); o.x");
3129 CHECK_EQ(result->Int32Value(), 23);
3130}
3131
3132
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003133static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3134 const AccessorInfo& info) {
3135 ApiTestFuzzer::Fuzz();
3136 if (index == 37) {
3137 return v8::Handle<Value>(v8_num(625));
3138 }
3139 return v8::Handle<Value>();
3140}
3141
3142
3143static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3144 Local<Value> value,
3145 const AccessorInfo& info) {
3146 ApiTestFuzzer::Fuzz();
3147 if (index == 39) {
3148 return value;
3149 }
3150 return v8::Handle<Value>();
3151}
3152
3153
3154THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3155 v8::HandleScope scope;
3156 Local<ObjectTemplate> templ = ObjectTemplate::New();
3157 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3158 IndexedPropertySetter);
3159 LocalContext context;
3160 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3161 Local<Script> getter_script = Script::Compile(v8_str(
3162 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3163 Local<Script> setter_script = Script::Compile(v8_str(
3164 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3165 "obj[17] = 23;"
3166 "obj.foo;"));
3167 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3168 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3169 "obj[39] = 47;"
3170 "obj.foo;")); // This setter should not run, due to the interceptor.
3171 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3172 "obj[37];"));
3173 Local<Value> result = getter_script->Run();
3174 CHECK_EQ(v8_num(5), result);
3175 result = setter_script->Run();
3176 CHECK_EQ(v8_num(23), result);
3177 result = interceptor_setter_script->Run();
3178 CHECK_EQ(v8_num(23), result);
3179 result = interceptor_getter_script->Run();
3180 CHECK_EQ(v8_num(625), result);
3181}
3182
3183
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003184static v8::Handle<Value> IdentityIndexedPropertyGetter(
3185 uint32_t index,
3186 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003187 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003188}
3189
3190
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003191THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3192 v8::HandleScope scope;
3193 Local<ObjectTemplate> templ = ObjectTemplate::New();
3194 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3195
3196 LocalContext context;
3197 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3198
3199 // Check fast object case.
3200 const char* fast_case_code =
3201 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3202 ExpectString(fast_case_code, "0");
3203
3204 // Check slow case.
3205 const char* slow_case_code =
3206 "obj.x = 1; delete obj.x;"
3207 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3208 ExpectString(slow_case_code, "1");
3209}
3210
3211
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003212THREADED_TEST(IndexedInterceptorWithNoSetter) {
3213 v8::HandleScope scope;
3214 Local<ObjectTemplate> templ = ObjectTemplate::New();
3215 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3216
3217 LocalContext context;
3218 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3219
3220 const char* code =
3221 "try {"
3222 " obj[0] = 239;"
3223 " for (var i = 0; i < 100; i++) {"
3224 " var v = obj[0];"
3225 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3226 " }"
3227 " 'PASSED'"
3228 "} catch(e) {"
3229 " e"
3230 "}";
3231 ExpectString(code, "PASSED");
3232}
3233
3234
ager@chromium.org5c838252010-02-19 08:53:10 +00003235THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3236 v8::HandleScope scope;
3237 Local<ObjectTemplate> templ = ObjectTemplate::New();
3238 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3239
3240 LocalContext context;
3241 Local<v8::Object> obj = templ->NewInstance();
3242 obj->TurnOnAccessCheck();
3243 context->Global()->Set(v8_str("obj"), obj);
3244
3245 const char* code =
3246 "try {"
3247 " for (var i = 0; i < 100; i++) {"
3248 " var v = obj[0];"
3249 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3250 " }"
3251 " 'PASSED'"
3252 "} catch(e) {"
3253 " e"
3254 "}";
3255 ExpectString(code, "PASSED");
3256}
3257
3258
3259THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3260 i::FLAG_allow_natives_syntax = true;
3261 v8::HandleScope scope;
3262 Local<ObjectTemplate> templ = ObjectTemplate::New();
3263 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3264
3265 LocalContext context;
3266 Local<v8::Object> obj = templ->NewInstance();
3267 context->Global()->Set(v8_str("obj"), obj);
3268
3269 const char* code =
3270 "try {"
3271 " for (var i = 0; i < 100; i++) {"
3272 " var expected = i;"
3273 " if (i == 5) {"
3274 " %EnableAccessChecks(obj);"
3275 " expected = undefined;"
3276 " }"
3277 " var v = obj[i];"
3278 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3279 " if (i == 5) %DisableAccessChecks(obj);"
3280 " }"
3281 " 'PASSED'"
3282 "} catch(e) {"
3283 " e"
3284 "}";
3285 ExpectString(code, "PASSED");
3286}
3287
3288
3289THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3290 v8::HandleScope scope;
3291 Local<ObjectTemplate> templ = ObjectTemplate::New();
3292 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3293
3294 LocalContext context;
3295 Local<v8::Object> obj = templ->NewInstance();
3296 context->Global()->Set(v8_str("obj"), obj);
3297
3298 const char* code =
3299 "try {"
3300 " for (var i = 0; i < 100; i++) {"
3301 " var v = obj[i];"
3302 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3303 " }"
3304 " 'PASSED'"
3305 "} catch(e) {"
3306 " e"
3307 "}";
3308 ExpectString(code, "PASSED");
3309}
3310
3311
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003312THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3313 v8::HandleScope scope;
3314 Local<ObjectTemplate> templ = ObjectTemplate::New();
3315 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3316
3317 LocalContext context;
3318 Local<v8::Object> obj = templ->NewInstance();
3319 context->Global()->Set(v8_str("obj"), obj);
3320
3321 const char* code =
3322 "try {"
3323 " for (var i = 0; i < 100; i++) {"
3324 " var expected = i;"
3325 " var key = i;"
3326 " if (i == 25) {"
3327 " key = -1;"
3328 " expected = undefined;"
3329 " }"
3330 " if (i == 50) {"
3331 " /* probe minimal Smi number on 32-bit platforms */"
3332 " key = -(1 << 30);"
3333 " expected = undefined;"
3334 " }"
3335 " if (i == 75) {"
3336 " /* probe minimal Smi number on 64-bit platforms */"
3337 " key = 1 << 31;"
3338 " expected = undefined;"
3339 " }"
3340 " var v = obj[key];"
3341 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3342 " }"
3343 " 'PASSED'"
3344 "} catch(e) {"
3345 " e"
3346 "}";
3347 ExpectString(code, "PASSED");
3348}
3349
3350
ager@chromium.org5c838252010-02-19 08:53:10 +00003351THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3352 v8::HandleScope scope;
3353 Local<ObjectTemplate> templ = ObjectTemplate::New();
3354 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3355
3356 LocalContext context;
3357 Local<v8::Object> obj = templ->NewInstance();
3358 context->Global()->Set(v8_str("obj"), obj);
3359
3360 const char* code =
3361 "try {"
3362 " for (var i = 0; i < 100; i++) {"
3363 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003364 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003365 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003366 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003367 " expected = undefined;"
3368 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003369 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003370 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3371 " }"
3372 " 'PASSED'"
3373 "} catch(e) {"
3374 " e"
3375 "}";
3376 ExpectString(code, "PASSED");
3377}
3378
3379
3380THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3381 v8::HandleScope scope;
3382 Local<ObjectTemplate> templ = ObjectTemplate::New();
3383 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3384
3385 LocalContext context;
3386 Local<v8::Object> obj = templ->NewInstance();
3387 context->Global()->Set(v8_str("obj"), obj);
3388
3389 const char* code =
3390 "var original = obj;"
3391 "try {"
3392 " for (var i = 0; i < 100; i++) {"
3393 " var expected = i;"
3394 " if (i == 50) {"
3395 " obj = {50: 'foobar'};"
3396 " expected = 'foobar';"
3397 " }"
3398 " var v = obj[i];"
3399 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3400 " if (i == 50) obj = original;"
3401 " }"
3402 " 'PASSED'"
3403 "} catch(e) {"
3404 " e"
3405 "}";
3406 ExpectString(code, "PASSED");
3407}
3408
3409
3410THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3411 v8::HandleScope scope;
3412 Local<ObjectTemplate> templ = ObjectTemplate::New();
3413 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3414
3415 LocalContext context;
3416 Local<v8::Object> obj = templ->NewInstance();
3417 context->Global()->Set(v8_str("obj"), obj);
3418
3419 const char* code =
3420 "var original = obj;"
3421 "try {"
3422 " for (var i = 0; i < 100; i++) {"
3423 " var expected = i;"
3424 " if (i == 5) {"
3425 " obj = 239;"
3426 " expected = undefined;"
3427 " }"
3428 " var v = obj[i];"
3429 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3430 " if (i == 5) obj = original;"
3431 " }"
3432 " 'PASSED'"
3433 "} catch(e) {"
3434 " e"
3435 "}";
3436 ExpectString(code, "PASSED");
3437}
3438
3439
3440THREADED_TEST(IndexedInterceptorOnProto) {
3441 v8::HandleScope scope;
3442 Local<ObjectTemplate> templ = ObjectTemplate::New();
3443 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3444
3445 LocalContext context;
3446 Local<v8::Object> obj = templ->NewInstance();
3447 context->Global()->Set(v8_str("obj"), obj);
3448
3449 const char* code =
3450 "var o = {__proto__: obj};"
3451 "try {"
3452 " for (var i = 0; i < 100; i++) {"
3453 " var v = o[i];"
3454 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3455 " }"
3456 " 'PASSED'"
3457 "} catch(e) {"
3458 " e"
3459 "}";
3460 ExpectString(code, "PASSED");
3461}
3462
3463
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003464THREADED_TEST(MultiContexts) {
3465 v8::HandleScope scope;
3466 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3467 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3468
3469 Local<String> password = v8_str("Password");
3470
3471 // Create an environment
3472 LocalContext context0(0, templ);
3473 context0->SetSecurityToken(password);
3474 v8::Handle<v8::Object> global0 = context0->Global();
3475 global0->Set(v8_str("custom"), v8_num(1234));
3476 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3477
3478 // Create an independent environment
3479 LocalContext context1(0, templ);
3480 context1->SetSecurityToken(password);
3481 v8::Handle<v8::Object> global1 = context1->Global();
3482 global1->Set(v8_str("custom"), v8_num(1234));
3483 CHECK_NE(global0, global1);
3484 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3485 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3486
3487 // Now create a new context with the old global
3488 LocalContext context2(0, templ, global1);
3489 context2->SetSecurityToken(password);
3490 v8::Handle<v8::Object> global2 = context2->Global();
3491 CHECK_EQ(global1, global2);
3492 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3493 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3494}
3495
3496
3497THREADED_TEST(FunctionPrototypeAcrossContexts) {
3498 // Make sure that functions created by cloning boilerplates cannot
3499 // communicate through their __proto__ field.
3500
3501 v8::HandleScope scope;
3502
3503 LocalContext env0;
3504 v8::Handle<v8::Object> global0 =
3505 env0->Global();
3506 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003507 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003508 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003509 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003510 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003511 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003512 proto0->Set(v8_str("custom"), v8_num(1234));
3513
3514 LocalContext env1;
3515 v8::Handle<v8::Object> global1 =
3516 env1->Global();
3517 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003518 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003519 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003520 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003521 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003522 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003523 CHECK(!proto1->Has(v8_str("custom")));
3524}
3525
3526
3527THREADED_TEST(Regress892105) {
3528 // Make sure that object and array literals created by cloning
3529 // boilerplates cannot communicate through their __proto__
3530 // field. This is rather difficult to check, but we try to add stuff
3531 // to Object.prototype and Array.prototype and create a new
3532 // environment. This should succeed.
3533
3534 v8::HandleScope scope;
3535
3536 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3537 "Array.prototype.arr = 4567;"
3538 "8901");
3539
3540 LocalContext env0;
3541 Local<Script> script0 = Script::Compile(source);
3542 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3543
3544 LocalContext env1;
3545 Local<Script> script1 = Script::Compile(source);
3546 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3547}
3548
3549
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003550THREADED_TEST(UndetectableObject) {
3551 v8::HandleScope scope;
3552 LocalContext env;
3553
3554 Local<v8::FunctionTemplate> desc =
3555 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3556 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3557
3558 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3559 env->Global()->Set(v8_str("undetectable"), obj);
3560
3561 ExpectString("undetectable.toString()", "[object Object]");
3562 ExpectString("typeof undetectable", "undefined");
3563 ExpectString("typeof(undetectable)", "undefined");
3564 ExpectBoolean("typeof undetectable == 'undefined'", true);
3565 ExpectBoolean("typeof undetectable == 'object'", false);
3566 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3567 ExpectBoolean("!undetectable", true);
3568
3569 ExpectObject("true&&undetectable", obj);
3570 ExpectBoolean("false&&undetectable", false);
3571 ExpectBoolean("true||undetectable", true);
3572 ExpectObject("false||undetectable", obj);
3573
3574 ExpectObject("undetectable&&true", obj);
3575 ExpectObject("undetectable&&false", obj);
3576 ExpectBoolean("undetectable||true", true);
3577 ExpectBoolean("undetectable||false", false);
3578
3579 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003580 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003581 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003582 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003583 ExpectBoolean("undetectable==undetectable", true);
3584
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003585
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003586 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003587 ExpectBoolean("null===undetectable", false);
3588 ExpectBoolean("undetectable===undefined", false);
3589 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003590 ExpectBoolean("undetectable===undetectable", true);
3591}
3592
3593
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003594
3595THREADED_TEST(ExtensibleOnUndetectable) {
3596 v8::HandleScope scope;
3597 LocalContext env;
3598
3599 Local<v8::FunctionTemplate> desc =
3600 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3601 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3602
3603 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3604 env->Global()->Set(v8_str("undetectable"), obj);
3605
3606 Local<String> source = v8_str("undetectable.x = 42;"
3607 "undetectable.x");
3608
3609 Local<Script> script = Script::Compile(source);
3610
3611 CHECK_EQ(v8::Integer::New(42), script->Run());
3612
3613 ExpectBoolean("Object.isExtensible(undetectable)", true);
3614
3615 source = v8_str("Object.preventExtensions(undetectable);");
3616 script = Script::Compile(source);
3617 script->Run();
3618 ExpectBoolean("Object.isExtensible(undetectable)", false);
3619
3620 source = v8_str("undetectable.y = 2000;");
3621 script = Script::Compile(source);
3622 v8::TryCatch try_catch;
3623 Local<Value> result = script->Run();
3624 CHECK(result.IsEmpty());
3625 CHECK(try_catch.HasCaught());
3626}
3627
3628
3629
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003630THREADED_TEST(UndetectableString) {
3631 v8::HandleScope scope;
3632 LocalContext env;
3633
3634 Local<String> obj = String::NewUndetectable("foo");
3635 env->Global()->Set(v8_str("undetectable"), obj);
3636
3637 ExpectString("undetectable", "foo");
3638 ExpectString("typeof undetectable", "undefined");
3639 ExpectString("typeof(undetectable)", "undefined");
3640 ExpectBoolean("typeof undetectable == 'undefined'", true);
3641 ExpectBoolean("typeof undetectable == 'string'", false);
3642 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3643 ExpectBoolean("!undetectable", true);
3644
3645 ExpectObject("true&&undetectable", obj);
3646 ExpectBoolean("false&&undetectable", false);
3647 ExpectBoolean("true||undetectable", true);
3648 ExpectObject("false||undetectable", obj);
3649
3650 ExpectObject("undetectable&&true", obj);
3651 ExpectObject("undetectable&&false", obj);
3652 ExpectBoolean("undetectable||true", true);
3653 ExpectBoolean("undetectable||false", false);
3654
3655 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003656 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003658 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003659 ExpectBoolean("undetectable==undetectable", true);
3660
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003661
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003662 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003663 ExpectBoolean("null===undetectable", false);
3664 ExpectBoolean("undetectable===undefined", false);
3665 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003666 ExpectBoolean("undetectable===undetectable", true);
3667}
3668
3669
3670template <typename T> static void USE(T) { }
3671
3672
3673// This test is not intended to be run, just type checked.
3674static void PersistentHandles() {
3675 USE(PersistentHandles);
3676 Local<String> str = v8_str("foo");
3677 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3678 USE(p_str);
3679 Local<Script> scr = Script::Compile(v8_str(""));
3680 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3681 USE(p_scr);
3682 Local<ObjectTemplate> templ = ObjectTemplate::New();
3683 v8::Persistent<ObjectTemplate> p_templ =
3684 v8::Persistent<ObjectTemplate>::New(templ);
3685 USE(p_templ);
3686}
3687
3688
3689static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3690 ApiTestFuzzer::Fuzz();
3691 return v8::Undefined();
3692}
3693
3694
3695THREADED_TEST(GlobalObjectTemplate) {
3696 v8::HandleScope handle_scope;
3697 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3698 global_template->Set(v8_str("JSNI_Log"),
3699 v8::FunctionTemplate::New(HandleLogDelegator));
3700 v8::Persistent<Context> context = Context::New(0, global_template);
3701 Context::Scope context_scope(context);
3702 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3703 context.Dispose();
3704}
3705
3706
3707static const char* kSimpleExtensionSource =
3708 "function Foo() {"
3709 " return 4;"
3710 "}";
3711
3712
3713THREADED_TEST(SimpleExtensions) {
3714 v8::HandleScope handle_scope;
3715 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3716 const char* extension_names[] = { "simpletest" };
3717 v8::ExtensionConfiguration extensions(1, extension_names);
3718 v8::Handle<Context> context = Context::New(&extensions);
3719 Context::Scope lock(context);
3720 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3721 CHECK_EQ(result, v8::Integer::New(4));
3722}
3723
3724
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003725static const char* kEvalExtensionSource1 =
3726 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003727 " var x = 42;"
3728 " return eval('x');"
3729 "}";
3730
3731
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003732static const char* kEvalExtensionSource2 =
3733 "(function() {"
3734 " var x = 42;"
3735 " function e() {"
3736 " return eval('x');"
3737 " }"
3738 " this.UseEval2 = e;"
3739 "})()";
3740
3741
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003742THREADED_TEST(UseEvalFromExtension) {
3743 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003744 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3745 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3746 const char* extension_names[] = { "evaltest1", "evaltest2" };
3747 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003748 v8::Handle<Context> context = Context::New(&extensions);
3749 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003750 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3751 CHECK_EQ(result, v8::Integer::New(42));
3752 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003753 CHECK_EQ(result, v8::Integer::New(42));
3754}
3755
3756
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003757static const char* kWithExtensionSource1 =
3758 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003759 " var x = 42;"
3760 " with({x:87}) { return x; }"
3761 "}";
3762
3763
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003764
3765static const char* kWithExtensionSource2 =
3766 "(function() {"
3767 " var x = 42;"
3768 " function e() {"
3769 " with ({x:87}) { return x; }"
3770 " }"
3771 " this.UseWith2 = e;"
3772 "})()";
3773
3774
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003775THREADED_TEST(UseWithFromExtension) {
3776 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003777 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3778 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3779 const char* extension_names[] = { "withtest1", "withtest2" };
3780 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003781 v8::Handle<Context> context = Context::New(&extensions);
3782 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003783 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3784 CHECK_EQ(result, v8::Integer::New(87));
3785 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003786 CHECK_EQ(result, v8::Integer::New(87));
3787}
3788
3789
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003790THREADED_TEST(AutoExtensions) {
3791 v8::HandleScope handle_scope;
3792 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3793 extension->set_auto_enable(true);
3794 v8::RegisterExtension(extension);
3795 v8::Handle<Context> context = Context::New();
3796 Context::Scope lock(context);
3797 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3798 CHECK_EQ(result, v8::Integer::New(4));
3799}
3800
3801
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003802static const char* kSyntaxErrorInExtensionSource =
3803 "[";
3804
3805
3806// Test that a syntax error in an extension does not cause a fatal
3807// error but results in an empty context.
3808THREADED_TEST(SyntaxErrorExtensions) {
3809 v8::HandleScope handle_scope;
3810 v8::RegisterExtension(new Extension("syntaxerror",
3811 kSyntaxErrorInExtensionSource));
3812 const char* extension_names[] = { "syntaxerror" };
3813 v8::ExtensionConfiguration extensions(1, extension_names);
3814 v8::Handle<Context> context = Context::New(&extensions);
3815 CHECK(context.IsEmpty());
3816}
3817
3818
3819static const char* kExceptionInExtensionSource =
3820 "throw 42";
3821
3822
3823// Test that an exception when installing an extension does not cause
3824// a fatal error but results in an empty context.
3825THREADED_TEST(ExceptionExtensions) {
3826 v8::HandleScope handle_scope;
3827 v8::RegisterExtension(new Extension("exception",
3828 kExceptionInExtensionSource));
3829 const char* extension_names[] = { "exception" };
3830 v8::ExtensionConfiguration extensions(1, extension_names);
3831 v8::Handle<Context> context = Context::New(&extensions);
3832 CHECK(context.IsEmpty());
3833}
3834
3835
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003836static const char* kNativeCallInExtensionSource =
3837 "function call_runtime_last_index_of(x) {"
3838 " return %StringLastIndexOf(x, 'bob', 10);"
3839 "}";
3840
3841
3842static const char* kNativeCallTest =
3843 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3844
3845// Test that a native runtime calls are supported in extensions.
3846THREADED_TEST(NativeCallInExtensions) {
3847 v8::HandleScope handle_scope;
3848 v8::RegisterExtension(new Extension("nativecall",
3849 kNativeCallInExtensionSource));
3850 const char* extension_names[] = { "nativecall" };
3851 v8::ExtensionConfiguration extensions(1, extension_names);
3852 v8::Handle<Context> context = Context::New(&extensions);
3853 Context::Scope lock(context);
3854 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3855 CHECK_EQ(result, v8::Integer::New(3));
3856}
3857
3858
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003859static void CheckDependencies(const char* name, const char* expected) {
3860 v8::HandleScope handle_scope;
3861 v8::ExtensionConfiguration config(1, &name);
3862 LocalContext context(&config);
3863 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3864}
3865
3866
3867/*
3868 * Configuration:
3869 *
3870 * /-- B <--\
3871 * A <- -- D <-- E
3872 * \-- C <--/
3873 */
3874THREADED_TEST(ExtensionDependency) {
3875 static const char* kEDeps[] = { "D" };
3876 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3877 static const char* kDDeps[] = { "B", "C" };
3878 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3879 static const char* kBCDeps[] = { "A" };
3880 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3881 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3882 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3883 CheckDependencies("A", "undefinedA");
3884 CheckDependencies("B", "undefinedAB");
3885 CheckDependencies("C", "undefinedAC");
3886 CheckDependencies("D", "undefinedABCD");
3887 CheckDependencies("E", "undefinedABCDE");
3888 v8::HandleScope handle_scope;
3889 static const char* exts[2] = { "C", "E" };
3890 v8::ExtensionConfiguration config(2, exts);
3891 LocalContext context(&config);
3892 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3893}
3894
3895
3896static const char* kExtensionTestScript =
3897 "native function A();"
3898 "native function B();"
3899 "native function C();"
3900 "function Foo(i) {"
3901 " if (i == 0) return A();"
3902 " if (i == 1) return B();"
3903 " if (i == 2) return C();"
3904 "}";
3905
3906
3907static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3908 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003909 if (args.IsConstructCall()) {
3910 args.This()->Set(v8_str("data"), args.Data());
3911 return v8::Null();
3912 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003913 return args.Data();
3914}
3915
3916
3917class FunctionExtension : public Extension {
3918 public:
3919 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3920 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3921 v8::Handle<String> name);
3922};
3923
3924
3925static int lookup_count = 0;
3926v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3927 v8::Handle<String> name) {
3928 lookup_count++;
3929 if (name->Equals(v8_str("A"))) {
3930 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3931 } else if (name->Equals(v8_str("B"))) {
3932 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3933 } else if (name->Equals(v8_str("C"))) {
3934 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3935 } else {
3936 return v8::Handle<v8::FunctionTemplate>();
3937 }
3938}
3939
3940
3941THREADED_TEST(FunctionLookup) {
3942 v8::RegisterExtension(new FunctionExtension());
3943 v8::HandleScope handle_scope;
3944 static const char* exts[1] = { "functiontest" };
3945 v8::ExtensionConfiguration config(1, exts);
3946 LocalContext context(&config);
3947 CHECK_EQ(3, lookup_count);
3948 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3949 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3950 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3951}
3952
3953
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003954THREADED_TEST(NativeFunctionConstructCall) {
3955 v8::RegisterExtension(new FunctionExtension());
3956 v8::HandleScope handle_scope;
3957 static const char* exts[1] = { "functiontest" };
3958 v8::ExtensionConfiguration config(1, exts);
3959 LocalContext context(&config);
3960 for (int i = 0; i < 10; i++) {
3961 // Run a few times to ensure that allocation of objects doesn't
3962 // change behavior of a constructor function.
3963 CHECK_EQ(v8::Integer::New(8),
3964 Script::Compile(v8_str("(new A()).data"))->Run());
3965 CHECK_EQ(v8::Integer::New(7),
3966 Script::Compile(v8_str("(new B()).data"))->Run());
3967 CHECK_EQ(v8::Integer::New(6),
3968 Script::Compile(v8_str("(new C()).data"))->Run());
3969 }
3970}
3971
3972
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973static const char* last_location;
3974static const char* last_message;
3975void StoringErrorCallback(const char* location, const char* message) {
3976 if (last_location == NULL) {
3977 last_location = location;
3978 last_message = message;
3979 }
3980}
3981
3982
3983// ErrorReporting creates a circular extensions configuration and
3984// tests that the fatal error handler gets called. This renders V8
3985// unusable and therefore this test cannot be run in parallel.
3986TEST(ErrorReporting) {
3987 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3988 static const char* aDeps[] = { "B" };
3989 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3990 static const char* bDeps[] = { "A" };
3991 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3992 last_location = NULL;
3993 v8::ExtensionConfiguration config(1, bDeps);
3994 v8::Handle<Context> context = Context::New(&config);
3995 CHECK(context.IsEmpty());
3996 CHECK_NE(last_location, NULL);
3997}
3998
3999
ager@chromium.org7c537e22008-10-16 08:43:32 +00004000static const char* js_code_causing_huge_string_flattening =
4001 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004002 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004003 " str = str + str;"
4004 "}"
4005 "str.match(/X/);";
4006
4007
4008void OOMCallback(const char* location, const char* message) {
4009 exit(0);
4010}
4011
4012
4013TEST(RegexpOutOfMemory) {
4014 // Execute a script that causes out of memory when flattening a string.
4015 v8::HandleScope scope;
4016 v8::V8::SetFatalErrorHandler(OOMCallback);
4017 LocalContext context;
4018 Local<Script> script =
4019 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4020 last_location = NULL;
4021 Local<Value> result = script->Run();
4022
4023 CHECK(false); // Should not return.
4024}
4025
4026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004027static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4028 v8::Handle<Value> data) {
4029 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004030 CHECK(message->GetScriptResourceName()->IsUndefined());
4031 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004032 message->GetLineNumber();
4033 message->GetSourceLine();
4034}
4035
4036
4037THREADED_TEST(ErrorWithMissingScriptInfo) {
4038 v8::HandleScope scope;
4039 LocalContext context;
4040 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4041 Script::Compile(v8_str("throw Error()"))->Run();
4042 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4043}
4044
4045
4046int global_index = 0;
4047
4048class Snorkel {
4049 public:
4050 Snorkel() { index_ = global_index++; }
4051 int index_;
4052};
4053
4054class Whammy {
4055 public:
4056 Whammy() {
4057 cursor_ = 0;
4058 }
4059 ~Whammy() {
4060 script_.Dispose();
4061 }
4062 v8::Handle<Script> getScript() {
4063 if (script_.IsEmpty())
4064 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4065 return Local<Script>(*script_);
4066 }
4067
4068 public:
4069 static const int kObjectCount = 256;
4070 int cursor_;
4071 v8::Persistent<v8::Object> objects_[kObjectCount];
4072 v8::Persistent<Script> script_;
4073};
4074
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004075static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004076 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4077 delete snorkel;
4078 obj.ClearWeak();
4079}
4080
4081v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4082 const AccessorInfo& info) {
4083 Whammy* whammy =
4084 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4085
4086 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4087
4088 v8::Handle<v8::Object> obj = v8::Object::New();
4089 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4090 if (!prev.IsEmpty()) {
4091 prev->Set(v8_str("next"), obj);
4092 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4093 whammy->objects_[whammy->cursor_].Clear();
4094 }
4095 whammy->objects_[whammy->cursor_] = global;
4096 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4097 return whammy->getScript()->Run();
4098}
4099
4100THREADED_TEST(WeakReference) {
4101 v8::HandleScope handle_scope;
4102 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004103 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004104 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4105 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004106 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004107 const char* extension_list[] = { "v8/gc" };
4108 v8::ExtensionConfiguration extensions(1, extension_list);
4109 v8::Persistent<Context> context = Context::New(&extensions);
4110 Context::Scope context_scope(context);
4111
4112 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4113 context->Global()->Set(v8_str("whammy"), interceptor);
4114 const char* code =
4115 "var last;"
4116 "for (var i = 0; i < 10000; i++) {"
4117 " var obj = whammy.length;"
4118 " if (last) last.next = obj;"
4119 " last = obj;"
4120 "}"
4121 "gc();"
4122 "4";
4123 v8::Handle<Value> result = CompileRun(code);
4124 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004125 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004126 context.Dispose();
4127}
4128
4129
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004130static bool in_scavenge = false;
4131static int last = -1;
4132
4133static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4134 CHECK_EQ(-1, last);
4135 last = 0;
4136 obj.Dispose();
4137 obj.Clear();
4138 in_scavenge = true;
4139 i::Heap::PerformScavenge();
4140 in_scavenge = false;
4141 *(reinterpret_cast<bool*>(data)) = true;
4142}
4143
4144static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4145 void* data) {
4146 CHECK_EQ(0, last);
4147 last = 1;
4148 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4149 obj.Dispose();
4150 obj.Clear();
4151}
4152
4153THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4154 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4155 // Calling callbacks from scavenges is unsafe as objects held by those
4156 // handlers might have become strongly reachable, but scavenge doesn't
4157 // check that.
4158 v8::Persistent<Context> context = Context::New();
4159 Context::Scope context_scope(context);
4160
4161 v8::Persistent<v8::Object> object_a;
4162 v8::Persistent<v8::Object> object_b;
4163
4164 {
4165 v8::HandleScope handle_scope;
4166 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4167 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4168 }
4169
4170 bool object_a_disposed = false;
4171 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4172 bool released_in_scavenge = false;
4173 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4174
4175 while (!object_a_disposed) {
4176 i::Heap::CollectAllGarbage(false);
4177 }
4178 CHECK(!released_in_scavenge);
4179}
4180
4181
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004182v8::Handle<Function> args_fun;
4183
4184
4185static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4186 ApiTestFuzzer::Fuzz();
4187 CHECK_EQ(args_fun, args.Callee());
4188 CHECK_EQ(3, args.Length());
4189 CHECK_EQ(v8::Integer::New(1), args[0]);
4190 CHECK_EQ(v8::Integer::New(2), args[1]);
4191 CHECK_EQ(v8::Integer::New(3), args[2]);
4192 CHECK_EQ(v8::Undefined(), args[3]);
4193 v8::HandleScope scope;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00004194 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004195 return v8::Undefined();
4196}
4197
4198
4199THREADED_TEST(Arguments) {
4200 v8::HandleScope scope;
4201 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4202 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4203 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004204 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 v8_compile("f(1, 2, 3)")->Run();
4206}
4207
4208
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4210 const AccessorInfo&) {
4211 return v8::Handle<Value>();
4212}
4213
4214
4215static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4216 const AccessorInfo&) {
4217 return v8::Handle<Value>();
4218}
4219
4220
4221static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4222 const AccessorInfo&) {
4223 if (!name->Equals(v8_str("foo"))) {
4224 return v8::Handle<v8::Boolean>(); // not intercepted
4225 }
4226
4227 return v8::False(); // intercepted, and don't delete the property
4228}
4229
4230
4231static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4232 if (index != 2) {
4233 return v8::Handle<v8::Boolean>(); // not intercepted
4234 }
4235
4236 return v8::False(); // intercepted, and don't delete the property
4237}
4238
4239
4240THREADED_TEST(Deleter) {
4241 v8::HandleScope scope;
4242 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4243 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4244 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4245 LocalContext context;
4246 context->Global()->Set(v8_str("k"), obj->NewInstance());
4247 CompileRun(
4248 "k.foo = 'foo';"
4249 "k.bar = 'bar';"
4250 "k[2] = 2;"
4251 "k[4] = 4;");
4252 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4253 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4254
4255 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4256 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4257
4258 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4259 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4260
4261 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4262 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4263}
4264
4265
4266static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4267 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004268 if (name->Equals(v8_str("foo")) ||
4269 name->Equals(v8_str("bar")) ||
4270 name->Equals(v8_str("baz"))) {
4271 return v8::Undefined();
4272 }
4273 return v8::Handle<Value>();
4274}
4275
4276
4277static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4278 ApiTestFuzzer::Fuzz();
4279 if (index == 0 || index == 1) return v8::Undefined();
4280 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004281}
4282
4283
4284static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4285 ApiTestFuzzer::Fuzz();
4286 v8::Handle<v8::Array> result = v8::Array::New(3);
4287 result->Set(v8::Integer::New(0), v8_str("foo"));
4288 result->Set(v8::Integer::New(1), v8_str("bar"));
4289 result->Set(v8::Integer::New(2), v8_str("baz"));
4290 return result;
4291}
4292
4293
4294static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4295 ApiTestFuzzer::Fuzz();
4296 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004297 result->Set(v8::Integer::New(0), v8_str("0"));
4298 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004299 return result;
4300}
4301
4302
4303THREADED_TEST(Enumerators) {
4304 v8::HandleScope scope;
4305 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4306 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004307 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004308 LocalContext context;
4309 context->Global()->Set(v8_str("k"), obj->NewInstance());
4310 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004311 "k[10] = 0;"
4312 "k.a = 0;"
4313 "k[5] = 0;"
4314 "k.b = 0;"
4315 "k[4294967295] = 0;"
4316 "k.c = 0;"
4317 "k[4294967296] = 0;"
4318 "k.d = 0;"
4319 "k[140000] = 0;"
4320 "k.e = 0;"
4321 "k[30000000000] = 0;"
4322 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004323 "var result = [];"
4324 "for (var prop in k) {"
4325 " result.push(prop);"
4326 "}"
4327 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004328 // Check that we get all the property names returned including the
4329 // ones from the enumerators in the right order: indexed properties
4330 // in numerical order, indexed interceptor properties, named
4331 // properties in insertion order, named interceptor properties.
4332 // This order is not mandated by the spec, so this test is just
4333 // documenting our behavior.
4334 CHECK_EQ(17, result->Length());
4335 // Indexed properties in numerical order.
4336 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4337 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4338 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4339 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4340 // Indexed interceptor properties in the order they are returned
4341 // from the enumerator interceptor.
4342 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4343 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4344 // Named properties in insertion order.
4345 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4346 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4347 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4348 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4349 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4350 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4351 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4352 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4353 // Named interceptor properties.
4354 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4355 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4356 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004357}
4358
4359
4360int p_getter_count;
4361int p_getter_count2;
4362
4363
4364static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4365 ApiTestFuzzer::Fuzz();
4366 p_getter_count++;
4367 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4368 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4369 if (name->Equals(v8_str("p1"))) {
4370 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4371 } else if (name->Equals(v8_str("p2"))) {
4372 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4373 } else if (name->Equals(v8_str("p3"))) {
4374 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4375 } else if (name->Equals(v8_str("p4"))) {
4376 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4377 }
4378 return v8::Undefined();
4379}
4380
4381
4382static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4383 ApiTestFuzzer::Fuzz();
4384 LocalContext context;
4385 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4386 CompileRun(
4387 "o1.__proto__ = { };"
4388 "var o2 = { __proto__: o1 };"
4389 "var o3 = { __proto__: o2 };"
4390 "var o4 = { __proto__: o3 };"
4391 "for (var i = 0; i < 10; i++) o4.p4;"
4392 "for (var i = 0; i < 10; i++) o3.p3;"
4393 "for (var i = 0; i < 10; i++) o2.p2;"
4394 "for (var i = 0; i < 10; i++) o1.p1;");
4395}
4396
4397
4398static v8::Handle<Value> PGetter2(Local<String> name,
4399 const AccessorInfo& info) {
4400 ApiTestFuzzer::Fuzz();
4401 p_getter_count2++;
4402 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4403 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4404 if (name->Equals(v8_str("p1"))) {
4405 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4406 } else if (name->Equals(v8_str("p2"))) {
4407 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4408 } else if (name->Equals(v8_str("p3"))) {
4409 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4410 } else if (name->Equals(v8_str("p4"))) {
4411 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4412 }
4413 return v8::Undefined();
4414}
4415
4416
4417THREADED_TEST(GetterHolders) {
4418 v8::HandleScope scope;
4419 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4420 obj->SetAccessor(v8_str("p1"), PGetter);
4421 obj->SetAccessor(v8_str("p2"), PGetter);
4422 obj->SetAccessor(v8_str("p3"), PGetter);
4423 obj->SetAccessor(v8_str("p4"), PGetter);
4424 p_getter_count = 0;
4425 RunHolderTest(obj);
4426 CHECK_EQ(40, p_getter_count);
4427}
4428
4429
4430THREADED_TEST(PreInterceptorHolders) {
4431 v8::HandleScope scope;
4432 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4433 obj->SetNamedPropertyHandler(PGetter2);
4434 p_getter_count2 = 0;
4435 RunHolderTest(obj);
4436 CHECK_EQ(40, p_getter_count2);
4437}
4438
4439
4440THREADED_TEST(ObjectInstantiation) {
4441 v8::HandleScope scope;
4442 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4443 templ->SetAccessor(v8_str("t"), PGetter2);
4444 LocalContext context;
4445 context->Global()->Set(v8_str("o"), templ->NewInstance());
4446 for (int i = 0; i < 100; i++) {
4447 v8::HandleScope inner_scope;
4448 v8::Handle<v8::Object> obj = templ->NewInstance();
4449 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4450 context->Global()->Set(v8_str("o2"), obj);
4451 v8::Handle<Value> value =
4452 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4453 CHECK_EQ(v8::True(), value);
4454 context->Global()->Set(v8_str("o"), obj);
4455 }
4456}
4457
4458
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004459static int StrCmp16(uint16_t* a, uint16_t* b) {
4460 while (true) {
4461 if (*a == 0 && *b == 0) return 0;
4462 if (*a != *b) return 0 + *a - *b;
4463 a++;
4464 b++;
4465 }
4466}
4467
4468
4469static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4470 while (true) {
4471 if (n-- == 0) return 0;
4472 if (*a == 0 && *b == 0) return 0;
4473 if (*a != *b) return 0 + *a - *b;
4474 a++;
4475 b++;
4476 }
4477}
4478
4479
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480THREADED_TEST(StringWrite) {
4481 v8::HandleScope scope;
4482 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004483 // abc<Icelandic eth><Unicode snowman>.
4484 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4485
4486 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004487
4488 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004489 char utf8buf[100];
4490 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004491 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004492 int charlen;
4493
4494 memset(utf8buf, 0x1, sizeof(utf8buf));
4495 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4496 CHECK_EQ(len, 9);
4497 CHECK_EQ(charlen, 5);
4498 CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4499
4500 memset(utf8buf, 0x1, sizeof(utf8buf));
4501 len = str2->WriteUtf8(utf8buf, 8, &charlen);
4502 CHECK_EQ(len, 8);
4503 CHECK_EQ(charlen, 5);
4504 CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4505
4506 memset(utf8buf, 0x1, sizeof(utf8buf));
4507 len = str2->WriteUtf8(utf8buf, 7, &charlen);
4508 CHECK_EQ(len, 5);
4509 CHECK_EQ(charlen, 4);
4510 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4511
4512 memset(utf8buf, 0x1, sizeof(utf8buf));
4513 len = str2->WriteUtf8(utf8buf, 6, &charlen);
4514 CHECK_EQ(len, 5);
4515 CHECK_EQ(charlen, 4);
4516 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4517
4518 memset(utf8buf, 0x1, sizeof(utf8buf));
4519 len = str2->WriteUtf8(utf8buf, 5, &charlen);
4520 CHECK_EQ(len, 5);
4521 CHECK_EQ(charlen, 4);
4522 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4523
4524 memset(utf8buf, 0x1, sizeof(utf8buf));
4525 len = str2->WriteUtf8(utf8buf, 4, &charlen);
4526 CHECK_EQ(len, 3);
4527 CHECK_EQ(charlen, 3);
4528 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4529
4530 memset(utf8buf, 0x1, sizeof(utf8buf));
4531 len = str2->WriteUtf8(utf8buf, 3, &charlen);
4532 CHECK_EQ(len, 3);
4533 CHECK_EQ(charlen, 3);
4534 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4535
4536 memset(utf8buf, 0x1, sizeof(utf8buf));
4537 len = str2->WriteUtf8(utf8buf, 2, &charlen);
4538 CHECK_EQ(len, 2);
4539 CHECK_EQ(charlen, 2);
4540 CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004541
4542 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004543 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004544 len = str->WriteAscii(buf);
4545 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004546 len = str->Write(wbuf);
4547 CHECK_EQ(len, 5);
4548 CHECK_EQ(strcmp("abcde", buf), 0);
4549 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4550 CHECK_EQ(StrCmp16(answer1, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004551
4552 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004553 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004554 len = str->WriteAscii(buf, 0, 4);
4555 CHECK_EQ(len, 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004556 len = str->Write(wbuf, 0, 4);
4557 CHECK_EQ(len, 4);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004558 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004559 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4560 CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004561
4562 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004563 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004564 len = str->WriteAscii(buf, 0, 5);
4565 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004566 len = str->Write(wbuf, 0, 5);
4567 CHECK_EQ(len, 5);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004568 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004569 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4570 CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004571
4572 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004573 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004574 len = str->WriteAscii(buf, 0, 6);
4575 CHECK_EQ(len, 5);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004576 len = str->Write(wbuf, 0, 6);
4577 CHECK_EQ(len, 5);
4578 CHECK_EQ(strcmp("abcde", buf), 0);
4579 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4580 CHECK_EQ(StrCmp16(answer4, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004581
4582 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004583 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004584 len = str->WriteAscii(buf, 4, -1);
4585 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004586 len = str->Write(wbuf, 4, -1);
4587 CHECK_EQ(len, 1);
4588 CHECK_EQ(strcmp("e", buf), 0);
4589 uint16_t answer5[] = {'e', '\0'};
4590 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004591
4592 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004593 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004594 len = str->WriteAscii(buf, 4, 6);
4595 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004596 len = str->Write(wbuf, 4, 6);
4597 CHECK_EQ(len, 1);
4598 CHECK_EQ(strcmp("e", buf), 0);
4599 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004600
4601 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004602 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004603 len = str->WriteAscii(buf, 4, 1);
4604 CHECK_EQ(len, 1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004605 len = str->Write(wbuf, 4, 1);
4606 CHECK_EQ(len, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004607 CHECK_EQ(strncmp("e\1", buf, 2), 0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004608 uint16_t answer6[] = {'e', 0x101};
4609 CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4610
4611 memset(buf, 0x1, sizeof(buf));
4612 memset(wbuf, 0x1, sizeof(wbuf));
4613 len = str->WriteAscii(buf, 3, 1);
4614 CHECK_EQ(len, 1);
4615 len = str->Write(wbuf, 3, 1);
4616 CHECK_EQ(len, 1);
4617 CHECK_EQ(strncmp("d\1", buf, 2), 0);
4618 uint16_t answer7[] = {'d', 0x101};
4619 CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004620}
4621
4622
4623THREADED_TEST(ToArrayIndex) {
4624 v8::HandleScope scope;
4625 LocalContext context;
4626
4627 v8::Handle<String> str = v8_str("42");
4628 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4629 CHECK(!index.IsEmpty());
4630 CHECK_EQ(42.0, index->Uint32Value());
4631 str = v8_str("42asdf");
4632 index = str->ToArrayIndex();
4633 CHECK(index.IsEmpty());
4634 str = v8_str("-42");
4635 index = str->ToArrayIndex();
4636 CHECK(index.IsEmpty());
4637 str = v8_str("4294967295");
4638 index = str->ToArrayIndex();
4639 CHECK(!index.IsEmpty());
4640 CHECK_EQ(4294967295.0, index->Uint32Value());
4641 v8::Handle<v8::Number> num = v8::Number::New(1);
4642 index = num->ToArrayIndex();
4643 CHECK(!index.IsEmpty());
4644 CHECK_EQ(1.0, index->Uint32Value());
4645 num = v8::Number::New(-1);
4646 index = num->ToArrayIndex();
4647 CHECK(index.IsEmpty());
4648 v8::Handle<v8::Object> obj = v8::Object::New();
4649 index = obj->ToArrayIndex();
4650 CHECK(index.IsEmpty());
4651}
4652
4653
4654THREADED_TEST(ErrorConstruction) {
4655 v8::HandleScope scope;
4656 LocalContext context;
4657
4658 v8::Handle<String> foo = v8_str("foo");
4659 v8::Handle<String> message = v8_str("message");
4660 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4661 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004662 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4663 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004664 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4665 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004666 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004667 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4668 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004669 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004670 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4671 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004672 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004673 v8::Handle<Value> error = v8::Exception::Error(foo);
4674 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004675 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004676}
4677
4678
4679static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4680 ApiTestFuzzer::Fuzz();
4681 return v8_num(10);
4682}
4683
4684
4685static void YSetter(Local<String> name,
4686 Local<Value> value,
4687 const AccessorInfo& info) {
4688 if (info.This()->Has(name)) {
4689 info.This()->Delete(name);
4690 }
4691 info.This()->Set(name, value);
4692}
4693
4694
4695THREADED_TEST(DeleteAccessor) {
4696 v8::HandleScope scope;
4697 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4698 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4699 LocalContext context;
4700 v8::Handle<v8::Object> holder = obj->NewInstance();
4701 context->Global()->Set(v8_str("holder"), holder);
4702 v8::Handle<Value> result = CompileRun(
4703 "holder.y = 11; holder.y = 12; holder.y");
4704 CHECK_EQ(12, result->Uint32Value());
4705}
4706
4707
4708THREADED_TEST(TypeSwitch) {
4709 v8::HandleScope scope;
4710 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4711 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4712 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4713 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4714 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4715 LocalContext context;
4716 v8::Handle<v8::Object> obj0 = v8::Object::New();
4717 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4718 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4719 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4720 for (int i = 0; i < 10; i++) {
4721 CHECK_EQ(0, type_switch->match(obj0));
4722 CHECK_EQ(1, type_switch->match(obj1));
4723 CHECK_EQ(2, type_switch->match(obj2));
4724 CHECK_EQ(3, type_switch->match(obj3));
4725 CHECK_EQ(3, type_switch->match(obj3));
4726 CHECK_EQ(2, type_switch->match(obj2));
4727 CHECK_EQ(1, type_switch->match(obj1));
4728 CHECK_EQ(0, type_switch->match(obj0));
4729 }
4730}
4731
4732
4733// For use within the TestSecurityHandler() test.
4734static bool g_security_callback_result = false;
4735static bool NamedSecurityTestCallback(Local<v8::Object> global,
4736 Local<Value> name,
4737 v8::AccessType type,
4738 Local<Value> data) {
4739 // Always allow read access.
4740 if (type == v8::ACCESS_GET)
4741 return true;
4742
4743 // Sometimes allow other access.
4744 return g_security_callback_result;
4745}
4746
4747
4748static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4749 uint32_t key,
4750 v8::AccessType type,
4751 Local<Value> data) {
4752 // Always allow read access.
4753 if (type == v8::ACCESS_GET)
4754 return true;
4755
4756 // Sometimes allow other access.
4757 return g_security_callback_result;
4758}
4759
4760
4761static int trouble_nesting = 0;
4762static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4763 ApiTestFuzzer::Fuzz();
4764 trouble_nesting++;
4765
4766 // Call a JS function that throws an uncaught exception.
4767 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4768 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4769 arg_this->Get(v8_str("trouble_callee")) :
4770 arg_this->Get(v8_str("trouble_caller"));
4771 CHECK(trouble_callee->IsFunction());
4772 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4773}
4774
4775
4776static int report_count = 0;
4777static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4778 v8::Handle<Value>) {
4779 report_count++;
4780}
4781
4782
4783// Counts uncaught exceptions, but other tests running in parallel
4784// also have uncaught exceptions.
4785TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00004786 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004787 v8::HandleScope scope;
4788 LocalContext env;
4789 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4790
4791 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4792 v8::Local<v8::Object> global = env->Global();
4793 global->Set(v8_str("trouble"), fun->GetFunction());
4794
4795 Script::Compile(v8_str("function trouble_callee() {"
4796 " var x = null;"
4797 " return x.foo;"
4798 "};"
4799 "function trouble_caller() {"
4800 " trouble();"
4801 "};"))->Run();
4802 Local<Value> trouble = global->Get(v8_str("trouble"));
4803 CHECK(trouble->IsFunction());
4804 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4805 CHECK(trouble_callee->IsFunction());
4806 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4807 CHECK(trouble_caller->IsFunction());
4808 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4809 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004810 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4811}
4812
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004813static const char* script_resource_name = "ExceptionInNativeScript.js";
4814static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4815 v8::Handle<Value>) {
4816 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4817 CHECK(!name_val.IsEmpty() && name_val->IsString());
4818 v8::String::AsciiValue name(message->GetScriptResourceName());
4819 CHECK_EQ(script_resource_name, *name);
4820 CHECK_EQ(3, message->GetLineNumber());
4821 v8::String::AsciiValue source_line(message->GetSourceLine());
4822 CHECK_EQ(" new o.foo();", *source_line);
4823}
4824
4825TEST(ExceptionInNativeScript) {
4826 v8::HandleScope scope;
4827 LocalContext env;
4828 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4829
4830 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4831 v8::Local<v8::Object> global = env->Global();
4832 global->Set(v8_str("trouble"), fun->GetFunction());
4833
4834 Script::Compile(v8_str("function trouble() {\n"
4835 " var o = {};\n"
4836 " new o.foo();\n"
4837 "};"), v8::String::New(script_resource_name))->Run();
4838 Local<Value> trouble = global->Get(v8_str("trouble"));
4839 CHECK(trouble->IsFunction());
4840 Function::Cast(*trouble)->Call(global, 0, NULL);
4841 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4842}
4843
ager@chromium.org8bb60582008-12-11 12:02:20 +00004844
4845TEST(CompilationErrorUsingTryCatchHandler) {
4846 v8::HandleScope scope;
4847 LocalContext env;
4848 v8::TryCatch try_catch;
4849 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4850 CHECK_NE(NULL, *try_catch.Exception());
4851 CHECK(try_catch.HasCaught());
4852}
4853
4854
4855TEST(TryCatchFinallyUsingTryCatchHandler) {
4856 v8::HandleScope scope;
4857 LocalContext env;
4858 v8::TryCatch try_catch;
4859 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4860 CHECK(!try_catch.HasCaught());
4861 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4862 CHECK(try_catch.HasCaught());
4863 try_catch.Reset();
4864 Script::Compile(v8_str("(function() {"
4865 "try { throw ''; } finally { return; }"
4866 "})()"))->Run();
4867 CHECK(!try_catch.HasCaught());
4868 Script::Compile(v8_str("(function()"
4869 " { try { throw ''; } finally { throw 0; }"
4870 "})()"))->Run();
4871 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004872}
4873
4874
4875// SecurityHandler can't be run twice
4876TEST(SecurityHandler) {
4877 v8::HandleScope scope0;
4878 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4879 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4880 IndexedSecurityTestCallback);
4881 // Create an environment
4882 v8::Persistent<Context> context0 =
4883 Context::New(NULL, global_template);
4884 context0->Enter();
4885
4886 v8::Handle<v8::Object> global0 = context0->Global();
4887 v8::Handle<Script> script0 = v8_compile("foo = 111");
4888 script0->Run();
4889 global0->Set(v8_str("0"), v8_num(999));
4890 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4891 CHECK_EQ(111, foo0->Int32Value());
4892 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4893 CHECK_EQ(999, z0->Int32Value());
4894
4895 // Create another environment, should fail security checks.
4896 v8::HandleScope scope1;
4897
4898 v8::Persistent<Context> context1 =
4899 Context::New(NULL, global_template);
4900 context1->Enter();
4901
4902 v8::Handle<v8::Object> global1 = context1->Global();
4903 global1->Set(v8_str("othercontext"), global0);
4904 // This set will fail the security check.
4905 v8::Handle<Script> script1 =
4906 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4907 script1->Run();
4908 // This read will pass the security check.
4909 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4910 CHECK_EQ(111, foo1->Int32Value());
4911 // This read will pass the security check.
4912 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4913 CHECK_EQ(999, z1->Int32Value());
4914
4915 // Create another environment, should pass security checks.
4916 { g_security_callback_result = true; // allow security handler to pass.
4917 v8::HandleScope scope2;
4918 LocalContext context2;
4919 v8::Handle<v8::Object> global2 = context2->Global();
4920 global2->Set(v8_str("othercontext"), global0);
4921 v8::Handle<Script> script2 =
4922 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4923 script2->Run();
4924 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4925 CHECK_EQ(333, foo2->Int32Value());
4926 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4927 CHECK_EQ(888, z2->Int32Value());
4928 }
4929
4930 context1->Exit();
4931 context1.Dispose();
4932
4933 context0->Exit();
4934 context0.Dispose();
4935}
4936
4937
4938THREADED_TEST(SecurityChecks) {
4939 v8::HandleScope handle_scope;
4940 LocalContext env1;
4941 v8::Persistent<Context> env2 = Context::New();
4942
4943 Local<Value> foo = v8_str("foo");
4944 Local<Value> bar = v8_str("bar");
4945
4946 // Set to the same domain.
4947 env1->SetSecurityToken(foo);
4948
4949 // Create a function in env1.
4950 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4951 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4952 CHECK(spy->IsFunction());
4953
4954 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004955 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004956 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4957 CHECK(spy2->IsFunction());
4958
4959 // Switch to env2 in the same domain and invoke spy on env2.
4960 {
4961 env2->SetSecurityToken(foo);
4962 // Enter env2
4963 Context::Scope scope_env2(env2);
4964 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4965 CHECK(result->IsFunction());
4966 }
4967
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004968 {
4969 env2->SetSecurityToken(bar);
4970 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004971
4972 // Call cross_domain_call, it should throw an exception
4973 v8::TryCatch try_catch;
4974 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4975 CHECK(try_catch.HasCaught());
4976 }
4977
4978 env2.Dispose();
4979}
4980
4981
4982// Regression test case for issue 1183439.
4983THREADED_TEST(SecurityChecksForPrototypeChain) {
4984 v8::HandleScope scope;
4985 LocalContext current;
4986 v8::Persistent<Context> other = Context::New();
4987
4988 // Change context to be able to get to the Object function in the
4989 // other context without hitting the security checks.
4990 v8::Local<Value> other_object;
4991 { Context::Scope scope(other);
4992 other_object = other->Global()->Get(v8_str("Object"));
4993 other->Global()->Set(v8_num(42), v8_num(87));
4994 }
4995
4996 current->Global()->Set(v8_str("other"), other->Global());
4997 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4998
4999 // Make sure the security check fails here and we get an undefined
5000 // result instead of getting the Object function. Repeat in a loop
5001 // to make sure to exercise the IC code.
5002 v8::Local<Script> access_other0 = v8_compile("other.Object");
5003 v8::Local<Script> access_other1 = v8_compile("other[42]");
5004 for (int i = 0; i < 5; i++) {
5005 CHECK(!access_other0->Run()->Equals(other_object));
5006 CHECK(access_other0->Run()->IsUndefined());
5007 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5008 CHECK(access_other1->Run()->IsUndefined());
5009 }
5010
5011 // Create an object that has 'other' in its prototype chain and make
5012 // sure we cannot access the Object function indirectly through
5013 // that. Repeat in a loop to make sure to exercise the IC code.
5014 v8_compile("function F() { };"
5015 "F.prototype = other;"
5016 "var f = new F();")->Run();
5017 v8::Local<Script> access_f0 = v8_compile("f.Object");
5018 v8::Local<Script> access_f1 = v8_compile("f[42]");
5019 for (int j = 0; j < 5; j++) {
5020 CHECK(!access_f0->Run()->Equals(other_object));
5021 CHECK(access_f0->Run()->IsUndefined());
5022 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5023 CHECK(access_f1->Run()->IsUndefined());
5024 }
5025
5026 // Now it gets hairy: Set the prototype for the other global object
5027 // to be the current global object. The prototype chain for 'f' now
5028 // goes through 'other' but ends up in the current global object.
5029 { Context::Scope scope(other);
5030 other->Global()->Set(v8_str("__proto__"), current->Global());
5031 }
5032 // Set a named and an index property on the current global
5033 // object. To force the lookup to go through the other global object,
5034 // the properties must not exist in the other global object.
5035 current->Global()->Set(v8_str("foo"), v8_num(100));
5036 current->Global()->Set(v8_num(99), v8_num(101));
5037 // Try to read the properties from f and make sure that the access
5038 // gets stopped by the security checks on the other global object.
5039 Local<Script> access_f2 = v8_compile("f.foo");
5040 Local<Script> access_f3 = v8_compile("f[99]");
5041 for (int k = 0; k < 5; k++) {
5042 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5043 CHECK(access_f2->Run()->IsUndefined());
5044 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5045 CHECK(access_f3->Run()->IsUndefined());
5046 }
5047 other.Dispose();
5048}
5049
5050
5051THREADED_TEST(CrossDomainDelete) {
5052 v8::HandleScope handle_scope;
5053 LocalContext env1;
5054 v8::Persistent<Context> env2 = Context::New();
5055
5056 Local<Value> foo = v8_str("foo");
5057 Local<Value> bar = v8_str("bar");
5058
5059 // Set to the same domain.
5060 env1->SetSecurityToken(foo);
5061 env2->SetSecurityToken(foo);
5062
5063 env1->Global()->Set(v8_str("prop"), v8_num(3));
5064 env2->Global()->Set(v8_str("env1"), env1->Global());
5065
5066 // Change env2 to a different domain and delete env1.prop.
5067 env2->SetSecurityToken(bar);
5068 {
5069 Context::Scope scope_env2(env2);
5070 Local<Value> result =
5071 Script::Compile(v8_str("delete env1.prop"))->Run();
5072 CHECK(result->IsFalse());
5073 }
5074
5075 // Check that env1.prop still exists.
5076 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5077 CHECK(v->IsNumber());
5078 CHECK_EQ(3, v->Int32Value());
5079
5080 env2.Dispose();
5081}
5082
5083
ager@chromium.org870a0b62008-11-04 11:43:05 +00005084THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5085 v8::HandleScope handle_scope;
5086 LocalContext env1;
5087 v8::Persistent<Context> env2 = Context::New();
5088
5089 Local<Value> foo = v8_str("foo");
5090 Local<Value> bar = v8_str("bar");
5091
5092 // Set to the same domain.
5093 env1->SetSecurityToken(foo);
5094 env2->SetSecurityToken(foo);
5095
5096 env1->Global()->Set(v8_str("prop"), v8_num(3));
5097 env2->Global()->Set(v8_str("env1"), env1->Global());
5098
5099 // env1.prop is enumerable in env2.
5100 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5101 {
5102 Context::Scope scope_env2(env2);
5103 Local<Value> result = Script::Compile(test)->Run();
5104 CHECK(result->IsTrue());
5105 }
5106
5107 // Change env2 to a different domain and test again.
5108 env2->SetSecurityToken(bar);
5109 {
5110 Context::Scope scope_env2(env2);
5111 Local<Value> result = Script::Compile(test)->Run();
5112 CHECK(result->IsFalse());
5113 }
5114
5115 env2.Dispose();
5116}
5117
5118
ager@chromium.org236ad962008-09-25 09:45:57 +00005119THREADED_TEST(CrossDomainForIn) {
5120 v8::HandleScope handle_scope;
5121 LocalContext env1;
5122 v8::Persistent<Context> env2 = Context::New();
5123
5124 Local<Value> foo = v8_str("foo");
5125 Local<Value> bar = v8_str("bar");
5126
5127 // Set to the same domain.
5128 env1->SetSecurityToken(foo);
5129 env2->SetSecurityToken(foo);
5130
5131 env1->Global()->Set(v8_str("prop"), v8_num(3));
5132 env2->Global()->Set(v8_str("env1"), env1->Global());
5133
5134 // Change env2 to a different domain and set env1's global object
5135 // as the __proto__ of an object in env2 and enumerate properties
5136 // in for-in. It shouldn't enumerate properties on env1's global
5137 // object.
5138 env2->SetSecurityToken(bar);
5139 {
5140 Context::Scope scope_env2(env2);
5141 Local<Value> result =
5142 CompileRun("(function(){var obj = {'__proto__':env1};"
5143 "for (var p in obj)"
5144 " if (p == 'prop') return false;"
5145 "return true;})()");
5146 CHECK(result->IsTrue());
5147 }
5148 env2.Dispose();
5149}
5150
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005151
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005152TEST(ContextDetachGlobal) {
5153 v8::HandleScope handle_scope;
5154 LocalContext env1;
5155 v8::Persistent<Context> env2 = Context::New();
5156
5157 Local<v8::Object> global1 = env1->Global();
5158
5159 Local<Value> foo = v8_str("foo");
5160
5161 // Set to the same domain.
5162 env1->SetSecurityToken(foo);
5163 env2->SetSecurityToken(foo);
5164
5165 // Enter env2
5166 env2->Enter();
5167
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005168 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005169 Local<v8::Object> global2 = env2->Global();
5170 global2->Set(v8_str("prop"), v8::Integer::New(1));
5171 CompileRun("function getProp() {return prop;}");
5172
5173 env1->Global()->Set(v8_str("getProp"),
5174 global2->Get(v8_str("getProp")));
5175
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005176 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005177 env2->Exit();
5178 env2->DetachGlobal();
5179 // env2 has a new global object.
5180 CHECK(!env2->Global()->Equals(global2));
5181
5182 v8::Persistent<Context> env3 =
5183 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5184 env3->SetSecurityToken(v8_str("bar"));
5185 env3->Enter();
5186
5187 Local<v8::Object> global3 = env3->Global();
5188 CHECK_EQ(global2, global3);
5189 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5190 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5191 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5192 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5193 env3->Exit();
5194
5195 // Call getProp in env1, and it should return the value 1
5196 {
5197 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5198 CHECK(get_prop->IsFunction());
5199 v8::TryCatch try_catch;
5200 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5201 CHECK(!try_catch.HasCaught());
5202 CHECK_EQ(1, r->Int32Value());
5203 }
5204
5205 // Check that env3 is not accessible from env1
5206 {
5207 Local<Value> r = global3->Get(v8_str("prop2"));
5208 CHECK(r->IsUndefined());
5209 }
5210
5211 env2.Dispose();
5212 env3.Dispose();
5213}
5214
5215
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005216TEST(DetachAndReattachGlobal) {
5217 v8::HandleScope scope;
5218 LocalContext env1;
5219
5220 // Create second environment.
5221 v8::Persistent<Context> env2 = Context::New();
5222
5223 Local<Value> foo = v8_str("foo");
5224
5225 // Set same security token for env1 and env2.
5226 env1->SetSecurityToken(foo);
5227 env2->SetSecurityToken(foo);
5228
5229 // Create a property on the global object in env2.
5230 {
5231 v8::Context::Scope scope(env2);
5232 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5233 }
5234
5235 // Create a reference to env2 global from env1 global.
5236 env1->Global()->Set(v8_str("other"), env2->Global());
5237
5238 // Check that we have access to other.p in env2 from env1.
5239 Local<Value> result = CompileRun("other.p");
5240 CHECK(result->IsInt32());
5241 CHECK_EQ(42, result->Int32Value());
5242
5243 // Hold on to global from env2 and detach global from env2.
5244 Local<v8::Object> global2 = env2->Global();
5245 env2->DetachGlobal();
5246
5247 // Check that the global has been detached. No other.p property can
5248 // be found.
5249 result = CompileRun("other.p");
5250 CHECK(result->IsUndefined());
5251
5252 // Reuse global2 for env3.
5253 v8::Persistent<Context> env3 =
5254 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5255 CHECK_EQ(global2, env3->Global());
5256
5257 // Start by using the same security token for env3 as for env1 and env2.
5258 env3->SetSecurityToken(foo);
5259
5260 // Create a property on the global object in env3.
5261 {
5262 v8::Context::Scope scope(env3);
5263 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5264 }
5265
5266 // Check that other.p is now the property in env3 and that we have access.
5267 result = CompileRun("other.p");
5268 CHECK(result->IsInt32());
5269 CHECK_EQ(24, result->Int32Value());
5270
5271 // Change security token for env3 to something different from env1 and env2.
5272 env3->SetSecurityToken(v8_str("bar"));
5273
5274 // Check that we do not have access to other.p in env1. |other| is now
5275 // the global object for env3 which has a different security token,
5276 // so access should be blocked.
5277 result = CompileRun("other.p");
5278 CHECK(result->IsUndefined());
5279
5280 // Detach the global for env3 and reattach it to env2.
5281 env3->DetachGlobal();
5282 env2->ReattachGlobal(global2);
5283
5284 // Check that we have access to other.p again in env1. |other| is now
5285 // the global object for env2 which has the same security token as env1.
5286 result = CompileRun("other.p");
5287 CHECK(result->IsInt32());
5288 CHECK_EQ(42, result->Int32Value());
5289
5290 env2.Dispose();
5291 env3.Dispose();
5292}
5293
5294
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005295static bool NamedAccessBlocker(Local<v8::Object> global,
5296 Local<Value> name,
5297 v8::AccessType type,
5298 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005299 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005300}
5301
5302
5303static bool IndexedAccessBlocker(Local<v8::Object> global,
5304 uint32_t key,
5305 v8::AccessType type,
5306 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005307 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005308}
5309
5310
5311static int g_echo_value = -1;
5312static v8::Handle<Value> EchoGetter(Local<String> name,
5313 const AccessorInfo& info) {
5314 return v8_num(g_echo_value);
5315}
5316
5317
5318static void EchoSetter(Local<String> name,
5319 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005320 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005321 if (value->IsNumber())
5322 g_echo_value = value->Int32Value();
5323}
5324
5325
5326static v8::Handle<Value> UnreachableGetter(Local<String> name,
5327 const AccessorInfo& info) {
5328 CHECK(false); // This function should not be called..
5329 return v8::Undefined();
5330}
5331
5332
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005333static void UnreachableSetter(Local<String>, Local<Value>,
5334 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005335 CHECK(false); // This function should nto be called.
5336}
5337
5338
5339THREADED_TEST(AccessControl) {
5340 v8::HandleScope handle_scope;
5341 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5342
5343 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5344 IndexedAccessBlocker);
5345
5346 // Add an accessor accessible by cross-domain JS code.
5347 global_template->SetAccessor(
5348 v8_str("accessible_prop"),
5349 EchoGetter, EchoSetter,
5350 v8::Handle<Value>(),
5351 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5352
5353 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005354 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005355 UnreachableGetter, UnreachableSetter,
5356 v8::Handle<Value>(),
5357 v8::DEFAULT);
5358
5359 // Create an environment
5360 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5361 context0->Enter();
5362
5363 v8::Handle<v8::Object> global0 = context0->Global();
5364
5365 v8::HandleScope scope1;
5366
5367 v8::Persistent<Context> context1 = Context::New();
5368 context1->Enter();
5369
5370 v8::Handle<v8::Object> global1 = context1->Global();
5371 global1->Set(v8_str("other"), global0);
5372
5373 v8::Handle<Value> value;
5374
5375 // Access blocked property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005376 value = CompileRun("other.blocked_prop = 1");
5377 value = CompileRun("other.blocked_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005378 CHECK(value->IsUndefined());
5379
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005380 value = CompileRun(
5381 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
5382 CHECK(value->IsUndefined());
5383
5384 value = CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00005385 CHECK(value->IsFalse());
5386
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005387 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005388 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005389 CHECK(value->IsNumber());
5390 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005391 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005392
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005393 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005394 CHECK(value->IsNumber());
5395 CHECK_EQ(3, value->Int32Value());
5396
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005397 value = CompileRun(
5398 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5399 CHECK(value->IsNumber());
5400 CHECK_EQ(3, value->Int32Value());
5401
5402 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00005403 CHECK(value->IsTrue());
5404
5405 // Enumeration doesn't enumerate accessors from inaccessible objects in
5406 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005407 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00005408 CompileRun("(function(){var obj = {'__proto__':other};"
5409 "for (var p in obj)"
5410 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5411 " return false;"
5412 " }"
5413 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005414 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00005415
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005416 context1->Exit();
5417 context0->Exit();
5418 context1.Dispose();
5419 context0.Dispose();
5420}
5421
5422
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005423static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5424 Local<Value> name,
5425 v8::AccessType type,
5426 Local<Value> data) {
5427 return false;
5428}
5429
5430
5431static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5432 uint32_t key,
5433 v8::AccessType type,
5434 Local<Value> data) {
5435 return false;
5436}
5437
5438
5439THREADED_TEST(AccessControlGetOwnPropertyNames) {
5440 v8::HandleScope handle_scope;
5441 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5442
5443 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5444 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5445 GetOwnPropertyNamesIndexedBlocker);
5446
5447 // Create an environment
5448 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5449 context0->Enter();
5450
5451 v8::Handle<v8::Object> global0 = context0->Global();
5452
5453 v8::HandleScope scope1;
5454
5455 v8::Persistent<Context> context1 = Context::New();
5456 context1->Enter();
5457
5458 v8::Handle<v8::Object> global1 = context1->Global();
5459 global1->Set(v8_str("other"), global0);
5460 global1->Set(v8_str("object"), obj_template->NewInstance());
5461
5462 v8::Handle<Value> value;
5463
5464 // Attempt to get the property names of the other global object and
5465 // of an object that requires access checks. Accessing the other
5466 // global object should be blocked by access checks on the global
5467 // proxy object. Accessing the object that requires access checks
5468 // is blocked by the access checks on the object itself.
5469 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5470 CHECK(value->IsTrue());
5471
5472 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5473 CHECK(value->IsTrue());
5474
5475 context1->Exit();
5476 context0->Exit();
5477 context1.Dispose();
5478 context0.Dispose();
5479}
5480
5481
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00005482static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5483 v8::Handle<v8::Array> result = v8::Array::New(1);
5484 result->Set(0, v8_str("x"));
5485 return result;
5486}
5487
5488
5489THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5490 v8::HandleScope handle_scope;
5491 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5492
5493 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5494 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5495 NamedPropertyEnumerator);
5496
5497 LocalContext context;
5498 v8::Handle<v8::Object> global = context->Global();
5499 global->Set(v8_str("object"), obj_template->NewInstance());
5500
5501 v8::Handle<Value> value =
5502 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5503 CHECK_EQ(v8_str("x"), value);
5504}
5505
5506
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005507static v8::Handle<Value> ConstTenGetter(Local<String> name,
5508 const AccessorInfo& info) {
5509 return v8_num(10);
5510}
5511
5512
5513THREADED_TEST(CrossDomainAccessors) {
5514 v8::HandleScope handle_scope;
5515
5516 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5517
5518 v8::Handle<v8::ObjectTemplate> global_template =
5519 func_template->InstanceTemplate();
5520
5521 v8::Handle<v8::ObjectTemplate> proto_template =
5522 func_template->PrototypeTemplate();
5523
5524 // Add an accessor to proto that's accessible by cross-domain JS code.
5525 proto_template->SetAccessor(v8_str("accessible"),
5526 ConstTenGetter, 0,
5527 v8::Handle<Value>(),
5528 v8::ALL_CAN_READ);
5529
5530 // Add an accessor that is not accessible by cross-domain JS code.
5531 global_template->SetAccessor(v8_str("unreachable"),
5532 UnreachableGetter, 0,
5533 v8::Handle<Value>(),
5534 v8::DEFAULT);
5535
5536 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5537 context0->Enter();
5538
5539 Local<v8::Object> global = context0->Global();
5540 // Add a normal property that shadows 'accessible'
5541 global->Set(v8_str("accessible"), v8_num(11));
5542
5543 // Enter a new context.
5544 v8::HandleScope scope1;
5545 v8::Persistent<Context> context1 = Context::New();
5546 context1->Enter();
5547
5548 v8::Handle<v8::Object> global1 = context1->Global();
5549 global1->Set(v8_str("other"), global);
5550
5551 // Should return 10, instead of 11
5552 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5553 CHECK(value->IsNumber());
5554 CHECK_EQ(10, value->Int32Value());
5555
5556 value = v8_compile("other.unreachable")->Run();
5557 CHECK(value->IsUndefined());
5558
5559 context1->Exit();
5560 context0->Exit();
5561 context1.Dispose();
5562 context0.Dispose();
5563}
5564
5565
5566static int named_access_count = 0;
5567static int indexed_access_count = 0;
5568
5569static bool NamedAccessCounter(Local<v8::Object> global,
5570 Local<Value> name,
5571 v8::AccessType type,
5572 Local<Value> data) {
5573 named_access_count++;
5574 return true;
5575}
5576
5577
5578static bool IndexedAccessCounter(Local<v8::Object> global,
5579 uint32_t key,
5580 v8::AccessType type,
5581 Local<Value> data) {
5582 indexed_access_count++;
5583 return true;
5584}
5585
5586
5587// This one is too easily disturbed by other tests.
5588TEST(AccessControlIC) {
5589 named_access_count = 0;
5590 indexed_access_count = 0;
5591
5592 v8::HandleScope handle_scope;
5593
5594 // Create an environment.
5595 v8::Persistent<Context> context0 = Context::New();
5596 context0->Enter();
5597
5598 // Create an object that requires access-check functions to be
5599 // called for cross-domain access.
5600 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5601 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5602 IndexedAccessCounter);
5603 Local<v8::Object> object = object_template->NewInstance();
5604
5605 v8::HandleScope scope1;
5606
5607 // Create another environment.
5608 v8::Persistent<Context> context1 = Context::New();
5609 context1->Enter();
5610
5611 // Make easy access to the object from the other environment.
5612 v8::Handle<v8::Object> global1 = context1->Global();
5613 global1->Set(v8_str("obj"), object);
5614
5615 v8::Handle<Value> value;
5616
5617 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005618 CompileRun("function testProp(obj) {"
5619 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5620 " for (var j = 0; j < 10; j++) obj.prop;"
5621 " return obj.prop"
5622 "}");
5623 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005624 CHECK(value->IsNumber());
5625 CHECK_EQ(1, value->Int32Value());
5626 CHECK_EQ(21, named_access_count);
5627
5628 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005629 CompileRun("var p = 'prop';"
5630 "function testKeyed(obj) {"
5631 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5632 " for (var j = 0; j < 10; j++) obj[p];"
5633 " return obj[p];"
5634 "}");
5635 // Use obj which requires access checks. No inline caching is used
5636 // in that case.
5637 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005638 CHECK(value->IsNumber());
5639 CHECK_EQ(1, value->Int32Value());
5640 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005641 // Force the inline caches into generic state and try again.
5642 CompileRun("testKeyed({ a: 0 })");
5643 CompileRun("testKeyed({ b: 0 })");
5644 value = CompileRun("testKeyed(obj)");
5645 CHECK(value->IsNumber());
5646 CHECK_EQ(1, value->Int32Value());
5647 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648
5649 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005650 CompileRun("function testIndexed(obj) {"
5651 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5652 " for (var j = 0; j < 10; j++) obj[0];"
5653 " return obj[0]"
5654 "}");
5655 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005656 CHECK(value->IsNumber());
5657 CHECK_EQ(1, value->Int32Value());
5658 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005659 // Force the inline caches into generic state.
5660 CompileRun("testIndexed(new Array(1))");
5661 // Test that the indexed access check is called.
5662 value = CompileRun("testIndexed(obj)");
5663 CHECK(value->IsNumber());
5664 CHECK_EQ(1, value->Int32Value());
5665 CHECK_EQ(42, indexed_access_count);
5666
5667 // Check that the named access check is called when invoking
5668 // functions on an object that requires access checks.
5669 CompileRun("obj.f = function() {}");
5670 CompileRun("function testCallNormal(obj) {"
5671 " for (var i = 0; i < 10; i++) obj.f();"
5672 "}");
5673 CompileRun("testCallNormal(obj)");
5674 CHECK_EQ(74, named_access_count);
5675
5676 // Force obj into slow case.
5677 value = CompileRun("delete obj.prop");
5678 CHECK(value->BooleanValue());
5679 // Force inline caches into dictionary probing mode.
5680 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5681 // Test that the named access check is called.
5682 value = CompileRun("testProp(obj);");
5683 CHECK(value->IsNumber());
5684 CHECK_EQ(1, value->Int32Value());
5685 CHECK_EQ(96, named_access_count);
5686
5687 // Force the call inline cache into dictionary probing mode.
5688 CompileRun("o.f = function() {}; testCallNormal(o)");
5689 // Test that the named access check is still called for each
5690 // invocation of the function.
5691 value = CompileRun("testCallNormal(obj)");
5692 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005693
5694 context1->Exit();
5695 context0->Exit();
5696 context1.Dispose();
5697 context0.Dispose();
5698}
5699
5700
5701static bool NamedAccessFlatten(Local<v8::Object> global,
5702 Local<Value> name,
5703 v8::AccessType type,
5704 Local<Value> data) {
5705 char buf[100];
5706 int len;
5707
5708 CHECK(name->IsString());
5709
5710 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005712 CHECK_EQ(4, len);
5713
5714 uint16_t buf2[100];
5715
5716 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005717 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005718 CHECK_EQ(4, len);
5719
5720 return true;
5721}
5722
5723
5724static bool IndexedAccessFlatten(Local<v8::Object> global,
5725 uint32_t key,
5726 v8::AccessType type,
5727 Local<Value> data) {
5728 return true;
5729}
5730
5731
5732// Regression test. In access checks, operations that may cause
5733// garbage collection are not allowed. It used to be the case that
5734// using the Write operation on a string could cause a garbage
5735// collection due to flattening of the string. This is no longer the
5736// case.
5737THREADED_TEST(AccessControlFlatten) {
5738 named_access_count = 0;
5739 indexed_access_count = 0;
5740
5741 v8::HandleScope handle_scope;
5742
5743 // Create an environment.
5744 v8::Persistent<Context> context0 = Context::New();
5745 context0->Enter();
5746
5747 // Create an object that requires access-check functions to be
5748 // called for cross-domain access.
5749 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5750 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5751 IndexedAccessFlatten);
5752 Local<v8::Object> object = object_template->NewInstance();
5753
5754 v8::HandleScope scope1;
5755
5756 // Create another environment.
5757 v8::Persistent<Context> context1 = Context::New();
5758 context1->Enter();
5759
5760 // Make easy access to the object from the other environment.
5761 v8::Handle<v8::Object> global1 = context1->Global();
5762 global1->Set(v8_str("obj"), object);
5763
5764 v8::Handle<Value> value;
5765
5766 value = v8_compile("var p = 'as' + 'df';")->Run();
5767 value = v8_compile("obj[p];")->Run();
5768
5769 context1->Exit();
5770 context0->Exit();
5771 context1.Dispose();
5772 context0.Dispose();
5773}
5774
5775
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005776static v8::Handle<Value> AccessControlNamedGetter(
5777 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005778 return v8::Integer::New(42);
5779}
5780
5781
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005782static v8::Handle<Value> AccessControlNamedSetter(
5783 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005784 return value;
5785}
5786
5787
5788static v8::Handle<Value> AccessControlIndexedGetter(
5789 uint32_t index,
5790 const AccessorInfo& info) {
5791 return v8_num(42);
5792}
5793
5794
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005795static v8::Handle<Value> AccessControlIndexedSetter(
5796 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005797 return value;
5798}
5799
5800
5801THREADED_TEST(AccessControlInterceptorIC) {
5802 named_access_count = 0;
5803 indexed_access_count = 0;
5804
5805 v8::HandleScope handle_scope;
5806
5807 // Create an environment.
5808 v8::Persistent<Context> context0 = Context::New();
5809 context0->Enter();
5810
5811 // Create an object that requires access-check functions to be
5812 // called for cross-domain access. The object also has interceptors
5813 // interceptor.
5814 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5815 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5816 IndexedAccessCounter);
5817 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5818 AccessControlNamedSetter);
5819 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5820 AccessControlIndexedSetter);
5821 Local<v8::Object> object = object_template->NewInstance();
5822
5823 v8::HandleScope scope1;
5824
5825 // Create another environment.
5826 v8::Persistent<Context> context1 = Context::New();
5827 context1->Enter();
5828
5829 // Make easy access to the object from the other environment.
5830 v8::Handle<v8::Object> global1 = context1->Global();
5831 global1->Set(v8_str("obj"), object);
5832
5833 v8::Handle<Value> value;
5834
5835 // Check that the named access-control function is called every time
5836 // eventhough there is an interceptor on the object.
5837 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5838 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5839 "obj.x")->Run();
5840 CHECK(value->IsNumber());
5841 CHECK_EQ(42, value->Int32Value());
5842 CHECK_EQ(21, named_access_count);
5843
5844 value = v8_compile("var p = 'x';")->Run();
5845 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5846 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5847 "obj[p]")->Run();
5848 CHECK(value->IsNumber());
5849 CHECK_EQ(42, value->Int32Value());
5850 CHECK_EQ(42, named_access_count);
5851
5852 // Check that the indexed access-control function is called every
5853 // time eventhough there is an interceptor on the object.
5854 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5855 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5856 "obj[0]")->Run();
5857 CHECK(value->IsNumber());
5858 CHECK_EQ(42, value->Int32Value());
5859 CHECK_EQ(21, indexed_access_count);
5860
5861 context1->Exit();
5862 context0->Exit();
5863 context1.Dispose();
5864 context0.Dispose();
5865}
5866
5867
5868THREADED_TEST(Version) {
5869 v8::V8::GetVersion();
5870}
5871
5872
5873static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5874 ApiTestFuzzer::Fuzz();
5875 return v8_num(12);
5876}
5877
5878
5879THREADED_TEST(InstanceProperties) {
5880 v8::HandleScope handle_scope;
5881 LocalContext context;
5882
5883 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5884 Local<ObjectTemplate> instance = t->InstanceTemplate();
5885
5886 instance->Set(v8_str("x"), v8_num(42));
5887 instance->Set(v8_str("f"),
5888 v8::FunctionTemplate::New(InstanceFunctionCallback));
5889
5890 Local<Value> o = t->GetFunction()->NewInstance();
5891
5892 context->Global()->Set(v8_str("i"), o);
5893 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5894 CHECK_EQ(42, value->Int32Value());
5895
5896 value = Script::Compile(v8_str("i.f()"))->Run();
5897 CHECK_EQ(12, value->Int32Value());
5898}
5899
5900
5901static v8::Handle<Value>
5902GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5903 ApiTestFuzzer::Fuzz();
5904 return v8::Handle<Value>();
5905}
5906
5907
5908THREADED_TEST(GlobalObjectInstanceProperties) {
5909 v8::HandleScope handle_scope;
5910
5911 Local<Value> global_object;
5912
5913 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5914 t->InstanceTemplate()->SetNamedPropertyHandler(
5915 GlobalObjectInstancePropertiesGet);
5916 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5917 instance_template->Set(v8_str("x"), v8_num(42));
5918 instance_template->Set(v8_str("f"),
5919 v8::FunctionTemplate::New(InstanceFunctionCallback));
5920
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005921 // The script to check how Crankshaft compiles missing global function
5922 // invocations. function g is not defined and should throw on call.
5923 const char* script =
5924 "function wrapper(call) {"
5925 " var x = 0, y = 1;"
5926 " for (var i = 0; i < 1000; i++) {"
5927 " x += i * 100;"
5928 " y += i * 100;"
5929 " }"
5930 " if (call) g();"
5931 "}"
5932 "for (var i = 0; i < 17; i++) wrapper(false);"
5933 "var thrown = 0;"
5934 "try { wrapper(true); } catch (e) { thrown = 1; };"
5935 "thrown";
5936
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005937 {
5938 LocalContext env(NULL, instance_template);
5939 // Hold on to the global object so it can be used again in another
5940 // environment initialization.
5941 global_object = env->Global();
5942
5943 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5944 CHECK_EQ(42, value->Int32Value());
5945 value = Script::Compile(v8_str("f()"))->Run();
5946 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005947 value = Script::Compile(v8_str(script))->Run();
5948 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005949 }
5950
5951 {
5952 // Create new environment reusing the global object.
5953 LocalContext env(NULL, instance_template, global_object);
5954 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5955 CHECK_EQ(42, value->Int32Value());
5956 value = Script::Compile(v8_str("f()"))->Run();
5957 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005958 value = Script::Compile(v8_str(script))->Run();
5959 CHECK_EQ(1, value->Int32Value());
5960 }
5961}
5962
5963
5964THREADED_TEST(CallKnownGlobalReceiver) {
5965 v8::HandleScope handle_scope;
5966
5967 Local<Value> global_object;
5968
5969 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5970 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5971
5972 // The script to check that we leave global object not
5973 // global object proxy on stack when we deoptimize from inside
5974 // arguments evaluation.
5975 // To provoke error we need to both force deoptimization
5976 // from arguments evaluation and to force CallIC to take
5977 // CallIC_Miss code path that can't cope with global proxy.
5978 const char* script =
5979 "function bar(x, y) { try { } finally { } }"
5980 "function baz(x) { try { } finally { } }"
5981 "function bom(x) { try { } finally { } }"
5982 "function foo(x) { bar([x], bom(2)); }"
5983 "for (var i = 0; i < 10000; i++) foo(1);"
5984 "foo";
5985
5986 Local<Value> foo;
5987 {
5988 LocalContext env(NULL, instance_template);
5989 // Hold on to the global object so it can be used again in another
5990 // environment initialization.
5991 global_object = env->Global();
5992 foo = Script::Compile(v8_str(script))->Run();
5993 }
5994
5995 {
5996 // Create new environment reusing the global object.
5997 LocalContext env(NULL, instance_template, global_object);
5998 env->Global()->Set(v8_str("foo"), foo);
5999 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006000 }
6001}
6002
6003
6004static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6005 ApiTestFuzzer::Fuzz();
6006 return v8_num(42);
6007}
6008
6009
6010static int shadow_y;
6011static int shadow_y_setter_call_count;
6012static int shadow_y_getter_call_count;
6013
6014
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006015static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006016 shadow_y_setter_call_count++;
6017 shadow_y = 42;
6018}
6019
6020
6021static v8::Handle<Value> ShadowYGetter(Local<String> name,
6022 const AccessorInfo& info) {
6023 ApiTestFuzzer::Fuzz();
6024 shadow_y_getter_call_count++;
6025 return v8_num(shadow_y);
6026}
6027
6028
6029static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6030 const AccessorInfo& info) {
6031 return v8::Handle<Value>();
6032}
6033
6034
6035static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6036 const AccessorInfo&) {
6037 return v8::Handle<Value>();
6038}
6039
6040
6041THREADED_TEST(ShadowObject) {
6042 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6043 v8::HandleScope handle_scope;
6044
6045 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6046 LocalContext context(NULL, global_template);
6047
6048 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6049 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6050 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6051 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6052 Local<ObjectTemplate> instance = t->InstanceTemplate();
6053
6054 // Only allow calls of f on instances of t.
6055 Local<v8::Signature> signature = v8::Signature::New(t);
6056 proto->Set(v8_str("f"),
6057 v8::FunctionTemplate::New(ShadowFunctionCallback,
6058 Local<Value>(),
6059 signature));
6060 proto->Set(v8_str("x"), v8_num(12));
6061
6062 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6063
6064 Local<Value> o = t->GetFunction()->NewInstance();
6065 context->Global()->Set(v8_str("__proto__"), o);
6066
6067 Local<Value> value =
6068 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6069 CHECK(value->IsBoolean());
6070 CHECK(!value->BooleanValue());
6071
6072 value = Script::Compile(v8_str("x"))->Run();
6073 CHECK_EQ(12, value->Int32Value());
6074
6075 value = Script::Compile(v8_str("f()"))->Run();
6076 CHECK_EQ(42, value->Int32Value());
6077
6078 Script::Compile(v8_str("y = 42"))->Run();
6079 CHECK_EQ(1, shadow_y_setter_call_count);
6080 value = Script::Compile(v8_str("y"))->Run();
6081 CHECK_EQ(1, shadow_y_getter_call_count);
6082 CHECK_EQ(42, value->Int32Value());
6083}
6084
6085
6086THREADED_TEST(HiddenPrototype) {
6087 v8::HandleScope handle_scope;
6088 LocalContext context;
6089
6090 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6091 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6092 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6093 t1->SetHiddenPrototype(true);
6094 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6095 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6096 t2->SetHiddenPrototype(true);
6097 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6098 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6099 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6100
6101 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6102 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6103 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6104 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6105
6106 // Setting the prototype on an object skips hidden prototypes.
6107 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6108 o0->Set(v8_str("__proto__"), o1);
6109 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6110 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6111 o0->Set(v8_str("__proto__"), o2);
6112 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6113 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6114 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6115 o0->Set(v8_str("__proto__"), o3);
6116 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6117 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6118 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6119 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6120
6121 // Getting the prototype of o0 should get the first visible one
6122 // which is o3. Therefore, z should not be defined on the prototype
6123 // object.
6124 Local<Value> proto = o0->Get(v8_str("__proto__"));
6125 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006126 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006127}
6128
6129
ager@chromium.org5c838252010-02-19 08:53:10 +00006130THREADED_TEST(SetPrototype) {
6131 v8::HandleScope handle_scope;
6132 LocalContext context;
6133
6134 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6135 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6136 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6137 t1->SetHiddenPrototype(true);
6138 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6139 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6140 t2->SetHiddenPrototype(true);
6141 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6142 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6143 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6144
6145 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6146 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6147 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6148 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6149
6150 // Setting the prototype on an object does not skip hidden prototypes.
6151 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6152 CHECK(o0->SetPrototype(o1));
6153 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6154 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6155 CHECK(o1->SetPrototype(o2));
6156 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6157 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6158 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6159 CHECK(o2->SetPrototype(o3));
6160 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6161 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6162 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6163 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6164
6165 // Getting the prototype of o0 should get the first visible one
6166 // which is o3. Therefore, z should not be defined on the prototype
6167 // object.
6168 Local<Value> proto = o0->Get(v8_str("__proto__"));
6169 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006170 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006171
6172 // However, Object::GetPrototype ignores hidden prototype.
6173 Local<Value> proto0 = o0->GetPrototype();
6174 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006176
6177 Local<Value> proto1 = o1->GetPrototype();
6178 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006179 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006180
6181 Local<Value> proto2 = o2->GetPrototype();
6182 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006184}
6185
6186
6187THREADED_TEST(SetPrototypeThrows) {
6188 v8::HandleScope handle_scope;
6189 LocalContext context;
6190
6191 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6192
6193 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6194 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6195
6196 CHECK(o0->SetPrototype(o1));
6197 // If setting the prototype leads to the cycle, SetPrototype should
6198 // return false and keep VM in sane state.
6199 v8::TryCatch try_catch;
6200 CHECK(!o1->SetPrototype(o0));
6201 CHECK(!try_catch.HasCaught());
6202 ASSERT(!i::Top::has_pending_exception());
6203
6204 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6205}
6206
6207
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006208THREADED_TEST(GetterSetterExceptions) {
6209 v8::HandleScope handle_scope;
6210 LocalContext context;
6211 CompileRun(
6212 "function Foo() { };"
6213 "function Throw() { throw 5; };"
6214 "var x = { };"
6215 "x.__defineSetter__('set', Throw);"
6216 "x.__defineGetter__('get', Throw);");
6217 Local<v8::Object> x =
6218 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6219 v8::TryCatch try_catch;
6220 x->Set(v8_str("set"), v8::Integer::New(8));
6221 x->Get(v8_str("get"));
6222 x->Set(v8_str("set"), v8::Integer::New(8));
6223 x->Get(v8_str("get"));
6224 x->Set(v8_str("set"), v8::Integer::New(8));
6225 x->Get(v8_str("get"));
6226 x->Set(v8_str("set"), v8::Integer::New(8));
6227 x->Get(v8_str("get"));
6228}
6229
6230
6231THREADED_TEST(Constructor) {
6232 v8::HandleScope handle_scope;
6233 LocalContext context;
6234 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6235 templ->SetClassName(v8_str("Fun"));
6236 Local<Function> cons = templ->GetFunction();
6237 context->Global()->Set(v8_str("Fun"), cons);
6238 Local<v8::Object> inst = cons->NewInstance();
6239 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6240 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6241 CHECK(value->BooleanValue());
6242}
6243
6244THREADED_TEST(FunctionDescriptorException) {
6245 v8::HandleScope handle_scope;
6246 LocalContext context;
6247 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6248 templ->SetClassName(v8_str("Fun"));
6249 Local<Function> cons = templ->GetFunction();
6250 context->Global()->Set(v8_str("Fun"), cons);
6251 Local<Value> value = CompileRun(
6252 "function test() {"
6253 " try {"
6254 " (new Fun()).blah()"
6255 " } catch (e) {"
6256 " var str = String(e);"
6257 " if (str.indexOf('TypeError') == -1) return 1;"
6258 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00006259 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006260 " return 0;"
6261 " }"
6262 " return 4;"
6263 "}"
6264 "test();");
6265 CHECK_EQ(0, value->Int32Value());
6266}
6267
6268
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006269THREADED_TEST(EvalAliasedDynamic) {
6270 v8::HandleScope scope;
6271 LocalContext current;
6272
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006273 // Tests where aliased eval can only be resolved dynamically.
6274 Local<Script> script =
6275 Script::Compile(v8_str("function f(x) { "
6276 " var foo = 2;"
6277 " with (x) { return eval('foo'); }"
6278 "}"
6279 "foo = 0;"
6280 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006281 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006282 "var x = new Object();"
6283 "x.eval = function(x) { return 1; };"
6284 "result3 = f(x);"));
6285 script->Run();
6286 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6287 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6288 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6289
6290 v8::TryCatch try_catch;
6291 script =
6292 Script::Compile(v8_str("function f(x) { "
6293 " var bar = 2;"
6294 " with (x) { return eval('bar'); }"
6295 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006296 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006297 script->Run();
6298 CHECK(try_catch.HasCaught());
6299 try_catch.Reset();
6300}
6301
6302
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006303THREADED_TEST(CrossEval) {
6304 v8::HandleScope scope;
6305 LocalContext other;
6306 LocalContext current;
6307
6308 Local<String> token = v8_str("<security token>");
6309 other->SetSecurityToken(token);
6310 current->SetSecurityToken(token);
6311
6312 // Setup reference from current to other.
6313 current->Global()->Set(v8_str("other"), other->Global());
6314
6315 // Check that new variables are introduced in other context.
6316 Local<Script> script =
6317 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6318 script->Run();
6319 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6320 CHECK_EQ(1234, foo->Int32Value());
6321 CHECK(!current->Global()->Has(v8_str("foo")));
6322
6323 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006324 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006325 script =
6326 Script::Compile(v8_str("other.eval('na = 1234')"));
6327 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006328 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6329 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006330
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006331 // Check that global variables in current context are not visible in other
6332 // context.
6333 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006334 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006335 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006336 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006337 CHECK(try_catch.HasCaught());
6338 try_catch.Reset();
6339
6340 // Check that local variables in current context are not visible in other
6341 // context.
6342 script =
6343 Script::Compile(v8_str("(function() { "
6344 " var baz = 87;"
6345 " return other.eval('baz');"
6346 "})();"));
6347 result = script->Run();
6348 CHECK(try_catch.HasCaught());
6349 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006350
6351 // Check that global variables in the other environment are visible
6352 // when evaluting code.
6353 other->Global()->Set(v8_str("bis"), v8_num(1234));
6354 script = Script::Compile(v8_str("other.eval('bis')"));
6355 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006356 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006357
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006358 // Check that the 'this' pointer points to the global object evaluating
6359 // code.
6360 other->Global()->Set(v8_str("t"), other->Global());
6361 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006362 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006363 CHECK(result->IsTrue());
6364 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006365
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006366 // Check that variables introduced in with-statement are not visible in
6367 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006368 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006369 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006370 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006371 CHECK(try_catch.HasCaught());
6372 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006373
6374 // Check that you cannot use 'eval.call' with another object than the
6375 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006376 script =
6377 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6378 result = script->Run();
6379 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006380}
6381
6382
ager@chromium.orge2902be2009-06-08 12:21:35 +00006383// Test that calling eval in a context which has been detached from
6384// its global throws an exception. This behavior is consistent with
6385// other JavaScript implementations.
6386THREADED_TEST(EvalInDetachedGlobal) {
6387 v8::HandleScope scope;
6388
6389 v8::Persistent<Context> context0 = Context::New();
6390 v8::Persistent<Context> context1 = Context::New();
6391
6392 // Setup function in context0 that uses eval from context0.
6393 context0->Enter();
6394 v8::Handle<v8::Value> fun =
6395 CompileRun("var x = 42;"
6396 "(function() {"
6397 " var e = eval;"
6398 " return function(s) { return e(s); }"
6399 "})()");
6400 context0->Exit();
6401
6402 // Put the function into context1 and call it before and after
6403 // detaching the global. Before detaching, the call succeeds and
6404 // after detaching and exception is thrown.
6405 context1->Enter();
6406 context1->Global()->Set(v8_str("fun"), fun);
6407 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6408 CHECK_EQ(42, x_value->Int32Value());
6409 context0->DetachGlobal();
6410 v8::TryCatch catcher;
6411 x_value = CompileRun("fun('x')");
6412 CHECK(x_value.IsEmpty());
6413 CHECK(catcher.HasCaught());
6414 context1->Exit();
6415
6416 context1.Dispose();
6417 context0.Dispose();
6418}
6419
6420
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006421THREADED_TEST(CrossLazyLoad) {
6422 v8::HandleScope scope;
6423 LocalContext other;
6424 LocalContext current;
6425
6426 Local<String> token = v8_str("<security token>");
6427 other->SetSecurityToken(token);
6428 current->SetSecurityToken(token);
6429
6430 // Setup reference from current to other.
6431 current->Global()->Set(v8_str("other"), other->Global());
6432
6433 // Trigger lazy loading in other context.
6434 Local<Script> script =
6435 Script::Compile(v8_str("other.eval('new Date(42)')"));
6436 Local<Value> value = script->Run();
6437 CHECK_EQ(42.0, value->NumberValue());
6438}
6439
6440
6441static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6442 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006443 if (args.IsConstructCall()) {
6444 if (args[0]->IsInt32()) {
6445 return v8_num(-args[0]->Int32Value());
6446 }
6447 }
6448
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006449 return args[0];
6450}
6451
6452
6453// Test that a call handler can be set for objects which will allow
6454// non-function objects created through the API to be called as
6455// functions.
6456THREADED_TEST(CallAsFunction) {
6457 v8::HandleScope scope;
6458 LocalContext context;
6459
6460 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6461 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6462 instance_template->SetCallAsFunctionHandler(call_as_function);
6463 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6464 context->Global()->Set(v8_str("obj"), instance);
6465 v8::TryCatch try_catch;
6466 Local<Value> value;
6467 CHECK(!try_catch.HasCaught());
6468
ager@chromium.org9085a012009-05-11 19:22:57 +00006469 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006470 CHECK(!try_catch.HasCaught());
6471 CHECK_EQ(42, value->Int32Value());
6472
ager@chromium.org9085a012009-05-11 19:22:57 +00006473 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006474 CHECK(!try_catch.HasCaught());
6475 CHECK_EQ(49, value->Int32Value());
6476
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006477 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00006478 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006479 CHECK(!try_catch.HasCaught());
6480 CHECK_EQ(45, value->Int32Value());
6481
ager@chromium.org9085a012009-05-11 19:22:57 +00006482 value = CompileRun("obj.call = Function.prototype.call;"
6483 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006484 CHECK(!try_catch.HasCaught());
6485 CHECK_EQ(87, value->Int32Value());
6486
6487 // Regression tests for bug #1116356: Calling call through call/apply
6488 // must work for non-function receivers.
6489 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00006490 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006491 CHECK(!try_catch.HasCaught());
6492 CHECK_EQ(99, value->Int32Value());
6493
6494 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00006495 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006496 CHECK(!try_catch.HasCaught());
6497 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00006498
6499 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006500 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006501 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00006502 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006503 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006504}
6505
6506
6507static int CountHandles() {
6508 return v8::HandleScope::NumberOfHandles();
6509}
6510
6511
6512static int Recurse(int depth, int iterations) {
6513 v8::HandleScope scope;
6514 if (depth == 0) return CountHandles();
6515 for (int i = 0; i < iterations; i++) {
6516 Local<v8::Number> n = v8::Integer::New(42);
6517 }
6518 return Recurse(depth - 1, iterations);
6519}
6520
6521
6522THREADED_TEST(HandleIteration) {
6523 static const int kIterations = 500;
6524 static const int kNesting = 200;
6525 CHECK_EQ(0, CountHandles());
6526 {
6527 v8::HandleScope scope1;
6528 CHECK_EQ(0, CountHandles());
6529 for (int i = 0; i < kIterations; i++) {
6530 Local<v8::Number> n = v8::Integer::New(42);
6531 CHECK_EQ(i + 1, CountHandles());
6532 }
6533
6534 CHECK_EQ(kIterations, CountHandles());
6535 {
6536 v8::HandleScope scope2;
6537 for (int j = 0; j < kIterations; j++) {
6538 Local<v8::Number> n = v8::Integer::New(42);
6539 CHECK_EQ(j + 1 + kIterations, CountHandles());
6540 }
6541 }
6542 CHECK_EQ(kIterations, CountHandles());
6543 }
6544 CHECK_EQ(0, CountHandles());
6545 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6546}
6547
6548
6549static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6550 Local<String> name,
6551 const AccessorInfo& info) {
6552 ApiTestFuzzer::Fuzz();
6553 return v8::Handle<Value>();
6554}
6555
6556
6557THREADED_TEST(InterceptorHasOwnProperty) {
6558 v8::HandleScope scope;
6559 LocalContext context;
6560 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6561 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6562 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6563 Local<Function> function = fun_templ->GetFunction();
6564 context->Global()->Set(v8_str("constructor"), function);
6565 v8::Handle<Value> value = CompileRun(
6566 "var o = new constructor();"
6567 "o.hasOwnProperty('ostehaps');");
6568 CHECK_EQ(false, value->BooleanValue());
6569 value = CompileRun(
6570 "o.ostehaps = 42;"
6571 "o.hasOwnProperty('ostehaps');");
6572 CHECK_EQ(true, value->BooleanValue());
6573 value = CompileRun(
6574 "var p = new constructor();"
6575 "p.hasOwnProperty('ostehaps');");
6576 CHECK_EQ(false, value->BooleanValue());
6577}
6578
6579
ager@chromium.org9085a012009-05-11 19:22:57 +00006580static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6581 Local<String> name,
6582 const AccessorInfo& info) {
6583 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006584 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00006585 return v8::Handle<Value>();
6586}
6587
6588
6589THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6590 v8::HandleScope scope;
6591 LocalContext context;
6592 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6593 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6594 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6595 Local<Function> function = fun_templ->GetFunction();
6596 context->Global()->Set(v8_str("constructor"), function);
6597 // Let's first make some stuff so we can be sure to get a good GC.
6598 CompileRun(
6599 "function makestr(size) {"
6600 " switch (size) {"
6601 " case 1: return 'f';"
6602 " case 2: return 'fo';"
6603 " case 3: return 'foo';"
6604 " }"
6605 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6606 "}"
6607 "var x = makestr(12345);"
6608 "x = makestr(31415);"
6609 "x = makestr(23456);");
6610 v8::Handle<Value> value = CompileRun(
6611 "var o = new constructor();"
6612 "o.__proto__ = new String(x);"
6613 "o.hasOwnProperty('ostehaps');");
6614 CHECK_EQ(false, value->BooleanValue());
6615}
6616
6617
ager@chromium.orge2902be2009-06-08 12:21:35 +00006618typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6619 const AccessorInfo& info);
6620
6621
6622static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6623 const char* source,
6624 int expected) {
6625 v8::HandleScope scope;
6626 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006627 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00006628 LocalContext context;
6629 context->Global()->Set(v8_str("o"), templ->NewInstance());
6630 v8::Handle<Value> value = CompileRun(source);
6631 CHECK_EQ(expected, value->Int32Value());
6632}
6633
6634
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006635static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6636 const AccessorInfo& info) {
6637 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006638 CHECK_EQ(v8_str("data"), info.Data());
6639 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006640 return v8::Integer::New(42);
6641}
6642
6643
6644// This test should hit the load IC for the interceptor case.
6645THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00006646 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006647 "var result = 0;"
6648 "for (var i = 0; i < 1000; i++) {"
6649 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006650 "}",
6651 42);
6652}
6653
6654
6655// Below go several tests which verify that JITing for various
6656// configurations of interceptor and explicit fields works fine
6657// (those cases are special cased to get better performance).
6658
6659static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6660 const AccessorInfo& info) {
6661 ApiTestFuzzer::Fuzz();
6662 return v8_str("x")->Equals(name)
6663 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6664}
6665
6666
6667THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6668 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6669 "var result = 0;"
6670 "o.y = 239;"
6671 "for (var i = 0; i < 1000; i++) {"
6672 " result = o.y;"
6673 "}",
6674 239);
6675}
6676
6677
6678THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6679 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6680 "var result = 0;"
6681 "o.__proto__ = { 'y': 239 };"
6682 "for (var i = 0; i < 1000; i++) {"
6683 " result = o.y + o.x;"
6684 "}",
6685 239 + 42);
6686}
6687
6688
6689THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6690 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6691 "var result = 0;"
6692 "o.__proto__.y = 239;"
6693 "for (var i = 0; i < 1000; i++) {"
6694 " result = o.y + o.x;"
6695 "}",
6696 239 + 42);
6697}
6698
6699
6700THREADED_TEST(InterceptorLoadICUndefined) {
6701 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6702 "var result = 0;"
6703 "for (var i = 0; i < 1000; i++) {"
6704 " result = (o.y == undefined) ? 239 : 42;"
6705 "}",
6706 239);
6707}
6708
6709
6710THREADED_TEST(InterceptorLoadICWithOverride) {
6711 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6712 "fst = new Object(); fst.__proto__ = o;"
6713 "snd = new Object(); snd.__proto__ = fst;"
6714 "var result1 = 0;"
6715 "for (var i = 0; i < 1000; i++) {"
6716 " result1 = snd.x;"
6717 "}"
6718 "fst.x = 239;"
6719 "var result = 0;"
6720 "for (var i = 0; i < 1000; i++) {"
6721 " result = snd.x;"
6722 "}"
6723 "result + result1",
6724 239 + 42);
6725}
6726
6727
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006728// Test the case when we stored field into
6729// a stub, but interceptor produced value on its own.
6730THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6731 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6732 "proto = new Object();"
6733 "o.__proto__ = proto;"
6734 "proto.x = 239;"
6735 "for (var i = 0; i < 1000; i++) {"
6736 " o.x;"
6737 // Now it should be ICed and keep a reference to x defined on proto
6738 "}"
6739 "var result = 0;"
6740 "for (var i = 0; i < 1000; i++) {"
6741 " result += o.x;"
6742 "}"
6743 "result;",
6744 42 * 1000);
6745}
6746
6747
6748// Test the case when we stored field into
6749// a stub, but it got invalidated later on.
6750THREADED_TEST(InterceptorLoadICInvalidatedField) {
6751 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6752 "proto1 = new Object();"
6753 "proto2 = new Object();"
6754 "o.__proto__ = proto1;"
6755 "proto1.__proto__ = proto2;"
6756 "proto2.y = 239;"
6757 "for (var i = 0; i < 1000; i++) {"
6758 " o.y;"
6759 // Now it should be ICed and keep a reference to y defined on proto2
6760 "}"
6761 "proto1.y = 42;"
6762 "var result = 0;"
6763 "for (var i = 0; i < 1000; i++) {"
6764 " result += o.y;"
6765 "}"
6766 "result;",
6767 42 * 1000);
6768}
6769
6770
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00006771static int interceptor_load_not_handled_calls = 0;
6772static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6773 const AccessorInfo& info) {
6774 ++interceptor_load_not_handled_calls;
6775 return v8::Handle<v8::Value>();
6776}
6777
6778
6779// Test how post-interceptor lookups are done in the non-cacheable
6780// case: the interceptor should not be invoked during this lookup.
6781THREADED_TEST(InterceptorLoadICPostInterceptor) {
6782 interceptor_load_not_handled_calls = 0;
6783 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6784 "receiver = new Object();"
6785 "receiver.__proto__ = o;"
6786 "proto = new Object();"
6787 "/* Make proto a slow-case object. */"
6788 "for (var i = 0; i < 1000; i++) {"
6789 " proto[\"xxxxxxxx\" + i] = [];"
6790 "}"
6791 "proto.x = 17;"
6792 "o.__proto__ = proto;"
6793 "var result = 0;"
6794 "for (var i = 0; i < 1000; i++) {"
6795 " result += receiver.x;"
6796 "}"
6797 "result;",
6798 17 * 1000);
6799 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6800}
6801
6802
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006803// Test the case when we stored field into
6804// a stub, but it got invalidated later on due to override on
6805// global object which is between interceptor and fields' holders.
6806THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6807 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6808 "o.__proto__ = this;" // set a global to be a proto of o.
6809 "this.__proto__.y = 239;"
6810 "for (var i = 0; i < 10; i++) {"
6811 " if (o.y != 239) throw 'oops: ' + o.y;"
6812 // Now it should be ICed and keep a reference to y defined on field_holder.
6813 "}"
6814 "this.y = 42;" // Assign on a global.
6815 "var result = 0;"
6816 "for (var i = 0; i < 10; i++) {"
6817 " result += o.y;"
6818 "}"
6819 "result;",
6820 42 * 10);
6821}
6822
6823
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006824static void SetOnThis(Local<String> name,
6825 Local<Value> value,
6826 const AccessorInfo& info) {
6827 info.This()->ForceSet(name, value);
6828}
6829
6830
6831THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6832 v8::HandleScope scope;
6833 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6834 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6835 templ->SetAccessor(v8_str("y"), Return239);
6836 LocalContext context;
6837 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006838
6839 // Check the case when receiver and interceptor's holder
6840 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006841 v8::Handle<Value> value = CompileRun(
6842 "var result = 0;"
6843 "for (var i = 0; i < 7; i++) {"
6844 " result = o.y;"
6845 "}");
6846 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006847
6848 // Check the case when interceptor's holder is in proto chain
6849 // of receiver.
6850 value = CompileRun(
6851 "r = { __proto__: o };"
6852 "var result = 0;"
6853 "for (var i = 0; i < 7; i++) {"
6854 " result = r.y;"
6855 "}");
6856 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006857}
6858
6859
6860THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6861 v8::HandleScope scope;
6862 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6863 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6864 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6865 templ_p->SetAccessor(v8_str("y"), Return239);
6866
6867 LocalContext context;
6868 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6869 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6870
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006871 // Check the case when receiver and interceptor's holder
6872 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006873 v8::Handle<Value> value = CompileRun(
6874 "o.__proto__ = p;"
6875 "var result = 0;"
6876 "for (var i = 0; i < 7; i++) {"
6877 " result = o.x + o.y;"
6878 "}");
6879 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006880
6881 // Check the case when interceptor's holder is in proto chain
6882 // of receiver.
6883 value = CompileRun(
6884 "r = { __proto__: o };"
6885 "var result = 0;"
6886 "for (var i = 0; i < 7; i++) {"
6887 " result = r.x + r.y;"
6888 "}");
6889 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006890}
6891
6892
6893THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6894 v8::HandleScope scope;
6895 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6896 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6897 templ->SetAccessor(v8_str("y"), Return239);
6898
6899 LocalContext context;
6900 context->Global()->Set(v8_str("o"), templ->NewInstance());
6901
6902 v8::Handle<Value> value = CompileRun(
6903 "fst = new Object(); fst.__proto__ = o;"
6904 "snd = new Object(); snd.__proto__ = fst;"
6905 "var result1 = 0;"
6906 "for (var i = 0; i < 7; i++) {"
6907 " result1 = snd.x;"
6908 "}"
6909 "fst.x = 239;"
6910 "var result = 0;"
6911 "for (var i = 0; i < 7; i++) {"
6912 " result = snd.x;"
6913 "}"
6914 "result + result1");
6915 CHECK_EQ(239 + 42, value->Int32Value());
6916}
6917
6918
6919// Test the case when we stored callback into
6920// a stub, but interceptor produced value on its own.
6921THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6922 v8::HandleScope scope;
6923 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6924 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6925 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6926 templ_p->SetAccessor(v8_str("y"), Return239);
6927
6928 LocalContext context;
6929 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6930 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6931
6932 v8::Handle<Value> value = CompileRun(
6933 "o.__proto__ = p;"
6934 "for (var i = 0; i < 7; i++) {"
6935 " o.x;"
6936 // Now it should be ICed and keep a reference to x defined on p
6937 "}"
6938 "var result = 0;"
6939 "for (var i = 0; i < 7; i++) {"
6940 " result += o.x;"
6941 "}"
6942 "result");
6943 CHECK_EQ(42 * 7, value->Int32Value());
6944}
6945
6946
6947// Test the case when we stored callback into
6948// a stub, but it got invalidated later on.
6949THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6950 v8::HandleScope scope;
6951 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6952 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6953 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6954 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6955
6956 LocalContext context;
6957 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6958 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6959
6960 v8::Handle<Value> value = CompileRun(
6961 "inbetween = new Object();"
6962 "o.__proto__ = inbetween;"
6963 "inbetween.__proto__ = p;"
6964 "for (var i = 0; i < 10; i++) {"
6965 " o.y;"
6966 // Now it should be ICed and keep a reference to y defined on p
6967 "}"
6968 "inbetween.y = 42;"
6969 "var result = 0;"
6970 "for (var i = 0; i < 10; i++) {"
6971 " result += o.y;"
6972 "}"
6973 "result");
6974 CHECK_EQ(42 * 10, value->Int32Value());
6975}
6976
6977
6978// Test the case when we stored callback into
6979// a stub, but it got invalidated later on due to override on
6980// global object which is between interceptor and callbacks' holders.
6981THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6982 v8::HandleScope scope;
6983 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6984 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6985 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6986 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6987
6988 LocalContext context;
6989 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6990 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6991
6992 v8::Handle<Value> value = CompileRun(
6993 "o.__proto__ = this;"
6994 "this.__proto__ = p;"
6995 "for (var i = 0; i < 10; i++) {"
6996 " if (o.y != 239) throw 'oops: ' + o.y;"
6997 // Now it should be ICed and keep a reference to y defined on p
6998 "}"
6999 "this.y = 42;"
7000 "var result = 0;"
7001 "for (var i = 0; i < 10; i++) {"
7002 " result += o.y;"
7003 "}"
7004 "result");
7005 CHECK_EQ(42 * 10, value->Int32Value());
7006}
7007
7008
ager@chromium.orge2902be2009-06-08 12:21:35 +00007009static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7010 const AccessorInfo& info) {
7011 ApiTestFuzzer::Fuzz();
7012 CHECK(v8_str("x")->Equals(name));
7013 return v8::Integer::New(0);
7014}
7015
7016
7017THREADED_TEST(InterceptorReturningZero) {
7018 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7019 "o.x == undefined ? 1 : 0",
7020 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007021}
7022
7023
7024static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007025 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007026 CHECK(v8_str("x")->Equals(key));
7027 CHECK_EQ(42, value->Int32Value());
7028 return value;
7029}
7030
7031
7032// This test should hit the store IC for the interceptor case.
7033THREADED_TEST(InterceptorStoreIC) {
7034 v8::HandleScope scope;
7035 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7036 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007037 InterceptorStoreICSetter,
7038 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007039 LocalContext context;
7040 context->Global()->Set(v8_str("o"), templ->NewInstance());
7041 v8::Handle<Value> value = CompileRun(
7042 "for (var i = 0; i < 1000; i++) {"
7043 " o.x = 42;"
7044 "}");
7045}
7046
7047
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007048THREADED_TEST(InterceptorStoreICWithNoSetter) {
7049 v8::HandleScope scope;
7050 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7051 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7052 LocalContext context;
7053 context->Global()->Set(v8_str("o"), templ->NewInstance());
7054 v8::Handle<Value> value = CompileRun(
7055 "for (var i = 0; i < 1000; i++) {"
7056 " o.y = 239;"
7057 "}"
7058 "42 + o.y");
7059 CHECK_EQ(239 + 42, value->Int32Value());
7060}
7061
7062
7063
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007064
7065v8::Handle<Value> call_ic_function;
7066v8::Handle<Value> call_ic_function2;
7067v8::Handle<Value> call_ic_function3;
7068
7069static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7070 const AccessorInfo& info) {
7071 ApiTestFuzzer::Fuzz();
7072 CHECK(v8_str("x")->Equals(name));
7073 return call_ic_function;
7074}
7075
7076
7077// This test should hit the call IC for the interceptor case.
7078THREADED_TEST(InterceptorCallIC) {
7079 v8::HandleScope scope;
7080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7081 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7082 LocalContext context;
7083 context->Global()->Set(v8_str("o"), templ->NewInstance());
7084 call_ic_function =
7085 v8_compile("function f(x) { return x + 1; }; f")->Run();
7086 v8::Handle<Value> value = CompileRun(
7087 "var result = 0;"
7088 "for (var i = 0; i < 1000; i++) {"
7089 " result = o.x(41);"
7090 "}");
7091 CHECK_EQ(42, value->Int32Value());
7092}
7093
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007094
7095// This test checks that if interceptor doesn't provide
7096// a value, we can fetch regular value.
7097THREADED_TEST(InterceptorCallICSeesOthers) {
7098 v8::HandleScope scope;
7099 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7100 templ->SetNamedPropertyHandler(NoBlockGetterX);
7101 LocalContext context;
7102 context->Global()->Set(v8_str("o"), templ->NewInstance());
7103 v8::Handle<Value> value = CompileRun(
7104 "o.x = function f(x) { return x + 1; };"
7105 "var result = 0;"
7106 "for (var i = 0; i < 7; i++) {"
7107 " result = o.x(41);"
7108 "}");
7109 CHECK_EQ(42, value->Int32Value());
7110}
7111
7112
7113static v8::Handle<Value> call_ic_function4;
7114static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7115 const AccessorInfo& info) {
7116 ApiTestFuzzer::Fuzz();
7117 CHECK(v8_str("x")->Equals(name));
7118 return call_ic_function4;
7119}
7120
7121
7122// This test checks that if interceptor provides a function,
7123// even if we cached shadowed variant, interceptor's function
7124// is invoked
7125THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7126 v8::HandleScope scope;
7127 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7128 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7129 LocalContext context;
7130 context->Global()->Set(v8_str("o"), templ->NewInstance());
7131 call_ic_function4 =
7132 v8_compile("function f(x) { return x - 1; }; f")->Run();
7133 v8::Handle<Value> value = CompileRun(
7134 "o.__proto__.x = function(x) { return x + 1; };"
7135 "var result = 0;"
7136 "for (var i = 0; i < 1000; i++) {"
7137 " result = o.x(42);"
7138 "}");
7139 CHECK_EQ(41, value->Int32Value());
7140}
7141
7142
7143// Test the case when we stored cacheable lookup into
7144// a stub, but it got invalidated later on
7145THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7146 v8::HandleScope scope;
7147 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7148 templ->SetNamedPropertyHandler(NoBlockGetterX);
7149 LocalContext context;
7150 context->Global()->Set(v8_str("o"), templ->NewInstance());
7151 v8::Handle<Value> value = CompileRun(
7152 "proto1 = new Object();"
7153 "proto2 = new Object();"
7154 "o.__proto__ = proto1;"
7155 "proto1.__proto__ = proto2;"
7156 "proto2.y = function(x) { return x + 1; };"
7157 // Invoke it many times to compile a stub
7158 "for (var i = 0; i < 7; i++) {"
7159 " o.y(42);"
7160 "}"
7161 "proto1.y = function(x) { return x - 1; };"
7162 "var result = 0;"
7163 "for (var i = 0; i < 7; i++) {"
7164 " result += o.y(42);"
7165 "}");
7166 CHECK_EQ(41 * 7, value->Int32Value());
7167}
7168
7169
7170static v8::Handle<Value> call_ic_function5;
7171static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7172 const AccessorInfo& info) {
7173 ApiTestFuzzer::Fuzz();
7174 if (v8_str("x")->Equals(name))
7175 return call_ic_function5;
7176 else
7177 return Local<Value>();
7178}
7179
7180
7181// This test checks that if interceptor doesn't provide a function,
7182// cached constant function is used
7183THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7184 v8::HandleScope scope;
7185 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7186 templ->SetNamedPropertyHandler(NoBlockGetterX);
7187 LocalContext context;
7188 context->Global()->Set(v8_str("o"), templ->NewInstance());
7189 v8::Handle<Value> value = CompileRun(
7190 "function inc(x) { return x + 1; };"
7191 "inc(1);"
7192 "o.x = inc;"
7193 "var result = 0;"
7194 "for (var i = 0; i < 1000; i++) {"
7195 " result = o.x(42);"
7196 "}");
7197 CHECK_EQ(43, value->Int32Value());
7198}
7199
7200
7201// This test checks that if interceptor provides a function,
7202// even if we cached constant function, interceptor's function
7203// is invoked
7204THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7205 v8::HandleScope scope;
7206 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7207 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7208 LocalContext context;
7209 context->Global()->Set(v8_str("o"), templ->NewInstance());
7210 call_ic_function5 =
7211 v8_compile("function f(x) { return x - 1; }; f")->Run();
7212 v8::Handle<Value> value = CompileRun(
7213 "function inc(x) { return x + 1; };"
7214 "inc(1);"
7215 "o.x = inc;"
7216 "var result = 0;"
7217 "for (var i = 0; i < 1000; i++) {"
7218 " result = o.x(42);"
7219 "}");
7220 CHECK_EQ(41, value->Int32Value());
7221}
7222
7223
7224// Test the case when we stored constant function into
7225// a stub, but it got invalidated later on
7226THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7227 v8::HandleScope scope;
7228 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7229 templ->SetNamedPropertyHandler(NoBlockGetterX);
7230 LocalContext context;
7231 context->Global()->Set(v8_str("o"), templ->NewInstance());
7232 v8::Handle<Value> value = CompileRun(
7233 "function inc(x) { return x + 1; };"
7234 "inc(1);"
7235 "proto1 = new Object();"
7236 "proto2 = new Object();"
7237 "o.__proto__ = proto1;"
7238 "proto1.__proto__ = proto2;"
7239 "proto2.y = inc;"
7240 // Invoke it many times to compile a stub
7241 "for (var i = 0; i < 7; i++) {"
7242 " o.y(42);"
7243 "}"
7244 "proto1.y = function(x) { return x - 1; };"
7245 "var result = 0;"
7246 "for (var i = 0; i < 7; i++) {"
7247 " result += o.y(42);"
7248 "}");
7249 CHECK_EQ(41 * 7, value->Int32Value());
7250}
7251
7252
7253// Test the case when we stored constant function into
7254// a stub, but it got invalidated later on due to override on
7255// global object which is between interceptor and constant function' holders.
7256THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7257 v8::HandleScope scope;
7258 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7259 templ->SetNamedPropertyHandler(NoBlockGetterX);
7260 LocalContext context;
7261 context->Global()->Set(v8_str("o"), templ->NewInstance());
7262 v8::Handle<Value> value = CompileRun(
7263 "function inc(x) { return x + 1; };"
7264 "inc(1);"
7265 "o.__proto__ = this;"
7266 "this.__proto__.y = inc;"
7267 // Invoke it many times to compile a stub
7268 "for (var i = 0; i < 7; i++) {"
7269 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7270 "}"
7271 "this.y = function(x) { return x - 1; };"
7272 "var result = 0;"
7273 "for (var i = 0; i < 7; i++) {"
7274 " result += o.y(42);"
7275 "}");
7276 CHECK_EQ(41 * 7, value->Int32Value());
7277}
7278
7279
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007280// Test the case when actual function to call sits on global object.
7281THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7282 v8::HandleScope scope;
7283 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7284 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7285
7286 LocalContext context;
7287 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7288
7289 v8::Handle<Value> value = CompileRun(
7290 "try {"
7291 " o.__proto__ = this;"
7292 " for (var i = 0; i < 10; i++) {"
7293 " var v = o.parseFloat('239');"
7294 " if (v != 239) throw v;"
7295 // Now it should be ICed and keep a reference to parseFloat.
7296 " }"
7297 " var result = 0;"
7298 " for (var i = 0; i < 10; i++) {"
7299 " result += o.parseFloat('239');"
7300 " }"
7301 " result"
7302 "} catch(e) {"
7303 " e"
7304 "};");
7305 CHECK_EQ(239 * 10, value->Int32Value());
7306}
7307
ager@chromium.org5c838252010-02-19 08:53:10 +00007308static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7309 const AccessorInfo& info) {
7310 ApiTestFuzzer::Fuzz();
7311 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7312 ++(*call_count);
7313 if ((*call_count) % 20 == 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00007314 i::Heap::CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00007315 }
7316 return v8::Handle<Value>();
7317}
7318
7319static v8::Handle<Value> FastApiCallback_TrivialSignature(
7320 const v8::Arguments& args) {
7321 ApiTestFuzzer::Fuzz();
7322 CHECK_EQ(args.This(), args.Holder());
7323 CHECK(args.Data()->Equals(v8_str("method_data")));
7324 return v8::Integer::New(args[0]->Int32Value() + 1);
7325}
7326
7327static v8::Handle<Value> FastApiCallback_SimpleSignature(
7328 const v8::Arguments& args) {
7329 ApiTestFuzzer::Fuzz();
7330 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7331 CHECK(args.Data()->Equals(v8_str("method_data")));
7332 // Note, we're using HasRealNamedProperty instead of Has to avoid
7333 // invoking the interceptor again.
7334 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7335 return v8::Integer::New(args[0]->Int32Value() + 1);
7336}
7337
7338// Helper to maximize the odds of object moving.
7339static void GenerateSomeGarbage() {
7340 CompileRun(
7341 "var garbage;"
7342 "for (var i = 0; i < 1000; i++) {"
7343 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7344 "}"
7345 "garbage = undefined;");
7346}
7347
7348THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7349 int interceptor_call_count = 0;
7350 v8::HandleScope scope;
7351 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7352 v8::Handle<v8::FunctionTemplate> method_templ =
7353 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7354 v8_str("method_data"),
7355 v8::Handle<v8::Signature>());
7356 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7357 proto_templ->Set(v8_str("method"), method_templ);
7358 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7359 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7360 NULL, NULL, NULL, NULL,
7361 v8::External::Wrap(&interceptor_call_count));
7362 LocalContext context;
7363 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7364 GenerateSomeGarbage();
7365 context->Global()->Set(v8_str("o"), fun->NewInstance());
7366 v8::Handle<Value> value = CompileRun(
7367 "var result = 0;"
7368 "for (var i = 0; i < 100; i++) {"
7369 " result = o.method(41);"
7370 "}");
7371 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7372 CHECK_EQ(100, interceptor_call_count);
7373}
7374
7375THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7376 int interceptor_call_count = 0;
7377 v8::HandleScope scope;
7378 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7379 v8::Handle<v8::FunctionTemplate> method_templ =
7380 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7381 v8_str("method_data"),
7382 v8::Signature::New(fun_templ));
7383 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7384 proto_templ->Set(v8_str("method"), method_templ);
7385 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7386 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7387 NULL, NULL, NULL, NULL,
7388 v8::External::Wrap(&interceptor_call_count));
7389 LocalContext context;
7390 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7391 GenerateSomeGarbage();
7392 context->Global()->Set(v8_str("o"), fun->NewInstance());
7393 v8::Handle<Value> value = CompileRun(
7394 "o.foo = 17;"
7395 "var receiver = {};"
7396 "receiver.__proto__ = o;"
7397 "var result = 0;"
7398 "for (var i = 0; i < 100; i++) {"
7399 " result = receiver.method(41);"
7400 "}");
7401 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7402 CHECK_EQ(100, interceptor_call_count);
7403}
7404
7405THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7406 int interceptor_call_count = 0;
7407 v8::HandleScope scope;
7408 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7409 v8::Handle<v8::FunctionTemplate> method_templ =
7410 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7411 v8_str("method_data"),
7412 v8::Signature::New(fun_templ));
7413 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7414 proto_templ->Set(v8_str("method"), method_templ);
7415 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7416 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7417 NULL, NULL, NULL, NULL,
7418 v8::External::Wrap(&interceptor_call_count));
7419 LocalContext context;
7420 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7421 GenerateSomeGarbage();
7422 context->Global()->Set(v8_str("o"), fun->NewInstance());
7423 v8::Handle<Value> value = CompileRun(
7424 "o.foo = 17;"
7425 "var receiver = {};"
7426 "receiver.__proto__ = o;"
7427 "var result = 0;"
7428 "var saved_result = 0;"
7429 "for (var i = 0; i < 100; i++) {"
7430 " result = receiver.method(41);"
7431 " if (i == 50) {"
7432 " saved_result = result;"
7433 " receiver = {method: function(x) { return x - 1 }};"
7434 " }"
7435 "}");
7436 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7437 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7438 CHECK_GE(interceptor_call_count, 50);
7439}
7440
7441THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7442 int interceptor_call_count = 0;
7443 v8::HandleScope scope;
7444 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7445 v8::Handle<v8::FunctionTemplate> method_templ =
7446 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7447 v8_str("method_data"),
7448 v8::Signature::New(fun_templ));
7449 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7450 proto_templ->Set(v8_str("method"), method_templ);
7451 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7452 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7453 NULL, NULL, NULL, NULL,
7454 v8::External::Wrap(&interceptor_call_count));
7455 LocalContext context;
7456 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7457 GenerateSomeGarbage();
7458 context->Global()->Set(v8_str("o"), fun->NewInstance());
7459 v8::Handle<Value> value = CompileRun(
7460 "o.foo = 17;"
7461 "var receiver = {};"
7462 "receiver.__proto__ = o;"
7463 "var result = 0;"
7464 "var saved_result = 0;"
7465 "for (var i = 0; i < 100; i++) {"
7466 " result = receiver.method(41);"
7467 " if (i == 50) {"
7468 " saved_result = result;"
7469 " o.method = function(x) { return x - 1 };"
7470 " }"
7471 "}");
7472 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7473 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7474 CHECK_GE(interceptor_call_count, 50);
7475}
7476
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007477THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7478 int interceptor_call_count = 0;
7479 v8::HandleScope scope;
7480 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7481 v8::Handle<v8::FunctionTemplate> method_templ =
7482 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7483 v8_str("method_data"),
7484 v8::Signature::New(fun_templ));
7485 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7486 proto_templ->Set(v8_str("method"), method_templ);
7487 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7488 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7489 NULL, NULL, NULL, NULL,
7490 v8::External::Wrap(&interceptor_call_count));
7491 LocalContext context;
7492 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7493 GenerateSomeGarbage();
7494 context->Global()->Set(v8_str("o"), fun->NewInstance());
7495 v8::TryCatch try_catch;
7496 v8::Handle<Value> value = CompileRun(
7497 "o.foo = 17;"
7498 "var receiver = {};"
7499 "receiver.__proto__ = o;"
7500 "var result = 0;"
7501 "var saved_result = 0;"
7502 "for (var i = 0; i < 100; i++) {"
7503 " result = receiver.method(41);"
7504 " if (i == 50) {"
7505 " saved_result = result;"
7506 " receiver = 333;"
7507 " }"
7508 "}");
7509 CHECK(try_catch.HasCaught());
7510 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7511 try_catch.Exception()->ToString());
7512 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7513 CHECK_GE(interceptor_call_count, 50);
7514}
7515
ager@chromium.org5c838252010-02-19 08:53:10 +00007516THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7517 int interceptor_call_count = 0;
7518 v8::HandleScope scope;
7519 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7520 v8::Handle<v8::FunctionTemplate> method_templ =
7521 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7522 v8_str("method_data"),
7523 v8::Signature::New(fun_templ));
7524 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7525 proto_templ->Set(v8_str("method"), method_templ);
7526 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7527 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7528 NULL, NULL, NULL, NULL,
7529 v8::External::Wrap(&interceptor_call_count));
7530 LocalContext context;
7531 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7532 GenerateSomeGarbage();
7533 context->Global()->Set(v8_str("o"), fun->NewInstance());
7534 v8::TryCatch try_catch;
7535 v8::Handle<Value> value = CompileRun(
7536 "o.foo = 17;"
7537 "var receiver = {};"
7538 "receiver.__proto__ = o;"
7539 "var result = 0;"
7540 "var saved_result = 0;"
7541 "for (var i = 0; i < 100; i++) {"
7542 " result = receiver.method(41);"
7543 " if (i == 50) {"
7544 " saved_result = result;"
7545 " receiver = {method: receiver.method};"
7546 " }"
7547 "}");
7548 CHECK(try_catch.HasCaught());
7549 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7550 try_catch.Exception()->ToString());
7551 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7552 CHECK_GE(interceptor_call_count, 50);
7553}
7554
7555THREADED_TEST(CallICFastApi_TrivialSignature) {
7556 v8::HandleScope scope;
7557 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7558 v8::Handle<v8::FunctionTemplate> method_templ =
7559 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7560 v8_str("method_data"),
7561 v8::Handle<v8::Signature>());
7562 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7563 proto_templ->Set(v8_str("method"), method_templ);
7564 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7565 LocalContext context;
7566 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7567 GenerateSomeGarbage();
7568 context->Global()->Set(v8_str("o"), fun->NewInstance());
7569 v8::Handle<Value> value = CompileRun(
7570 "var result = 0;"
7571 "for (var i = 0; i < 100; i++) {"
7572 " result = o.method(41);"
7573 "}");
7574
7575 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7576}
7577
7578THREADED_TEST(CallICFastApi_SimpleSignature) {
7579 v8::HandleScope scope;
7580 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7581 v8::Handle<v8::FunctionTemplate> method_templ =
7582 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7583 v8_str("method_data"),
7584 v8::Signature::New(fun_templ));
7585 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7586 proto_templ->Set(v8_str("method"), method_templ);
7587 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7588 LocalContext context;
7589 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7590 GenerateSomeGarbage();
7591 context->Global()->Set(v8_str("o"), fun->NewInstance());
7592 v8::Handle<Value> value = CompileRun(
7593 "o.foo = 17;"
7594 "var receiver = {};"
7595 "receiver.__proto__ = o;"
7596 "var result = 0;"
7597 "for (var i = 0; i < 100; i++) {"
7598 " result = receiver.method(41);"
7599 "}");
7600
7601 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7602}
7603
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007604THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007605 v8::HandleScope scope;
7606 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7607 v8::Handle<v8::FunctionTemplate> method_templ =
7608 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7609 v8_str("method_data"),
7610 v8::Signature::New(fun_templ));
7611 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7612 proto_templ->Set(v8_str("method"), method_templ);
7613 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7614 LocalContext context;
7615 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7616 GenerateSomeGarbage();
7617 context->Global()->Set(v8_str("o"), fun->NewInstance());
7618 v8::Handle<Value> value = CompileRun(
7619 "o.foo = 17;"
7620 "var receiver = {};"
7621 "receiver.__proto__ = o;"
7622 "var result = 0;"
7623 "var saved_result = 0;"
7624 "for (var i = 0; i < 100; i++) {"
7625 " result = receiver.method(41);"
7626 " if (i == 50) {"
7627 " saved_result = result;"
7628 " receiver = {method: function(x) { return x - 1 }};"
7629 " }"
7630 "}");
7631 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7632 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7633}
7634
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007635THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7636 v8::HandleScope scope;
7637 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7638 v8::Handle<v8::FunctionTemplate> method_templ =
7639 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7640 v8_str("method_data"),
7641 v8::Signature::New(fun_templ));
7642 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7643 proto_templ->Set(v8_str("method"), method_templ);
7644 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7645 LocalContext context;
7646 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7647 GenerateSomeGarbage();
7648 context->Global()->Set(v8_str("o"), fun->NewInstance());
7649 v8::TryCatch try_catch;
7650 v8::Handle<Value> value = CompileRun(
7651 "o.foo = 17;"
7652 "var receiver = {};"
7653 "receiver.__proto__ = o;"
7654 "var result = 0;"
7655 "var saved_result = 0;"
7656 "for (var i = 0; i < 100; i++) {"
7657 " result = receiver.method(41);"
7658 " if (i == 50) {"
7659 " saved_result = result;"
7660 " receiver = 333;"
7661 " }"
7662 "}");
7663 CHECK(try_catch.HasCaught());
7664 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7665 try_catch.Exception()->ToString());
7666 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7667}
7668
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007669
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007670v8::Handle<Value> keyed_call_ic_function;
7671
7672static v8::Handle<Value> InterceptorKeyedCallICGetter(
7673 Local<String> name, const AccessorInfo& info) {
7674 ApiTestFuzzer::Fuzz();
7675 if (v8_str("x")->Equals(name)) {
7676 return keyed_call_ic_function;
7677 }
7678 return v8::Handle<Value>();
7679}
7680
7681
7682// Test the case when we stored cacheable lookup into
7683// a stub, but the function name changed (to another cacheable function).
7684THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7685 v8::HandleScope scope;
7686 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7687 templ->SetNamedPropertyHandler(NoBlockGetterX);
7688 LocalContext context;
7689 context->Global()->Set(v8_str("o"), templ->NewInstance());
7690 v8::Handle<Value> value = CompileRun(
7691 "proto = new Object();"
7692 "proto.y = function(x) { return x + 1; };"
7693 "proto.z = function(x) { return x - 1; };"
7694 "o.__proto__ = proto;"
7695 "var result = 0;"
7696 "var method = 'y';"
7697 "for (var i = 0; i < 10; i++) {"
7698 " if (i == 5) { method = 'z'; };"
7699 " result += o[method](41);"
7700 "}");
7701 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7702}
7703
7704
7705// Test the case when we stored cacheable lookup into
7706// a stub, but the function name changed (and the new function is present
7707// both before and after the interceptor in the prototype chain).
7708THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7709 v8::HandleScope scope;
7710 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7711 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7712 LocalContext context;
7713 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7714 keyed_call_ic_function =
7715 v8_compile("function f(x) { return x - 1; }; f")->Run();
7716 v8::Handle<Value> value = CompileRun(
7717 "o = new Object();"
7718 "proto2 = new Object();"
7719 "o.y = function(x) { return x + 1; };"
7720 "proto2.y = function(x) { return x + 2; };"
7721 "o.__proto__ = proto1;"
7722 "proto1.__proto__ = proto2;"
7723 "var result = 0;"
7724 "var method = 'x';"
7725 "for (var i = 0; i < 10; i++) {"
7726 " if (i == 5) { method = 'y'; };"
7727 " result += o[method](41);"
7728 "}");
7729 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7730}
7731
7732
7733// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7734// on the global object.
7735THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7736 v8::HandleScope scope;
7737 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7738 templ->SetNamedPropertyHandler(NoBlockGetterX);
7739 LocalContext context;
7740 context->Global()->Set(v8_str("o"), templ->NewInstance());
7741 v8::Handle<Value> value = CompileRun(
7742 "function inc(x) { return x + 1; };"
7743 "inc(1);"
7744 "function dec(x) { return x - 1; };"
7745 "dec(1);"
7746 "o.__proto__ = this;"
7747 "this.__proto__.x = inc;"
7748 "this.__proto__.y = dec;"
7749 "var result = 0;"
7750 "var method = 'x';"
7751 "for (var i = 0; i < 10; i++) {"
7752 " if (i == 5) { method = 'y'; };"
7753 " result += o[method](41);"
7754 "}");
7755 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7756}
7757
7758
7759// Test the case when actual function to call sits on global object.
7760THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7761 v8::HandleScope scope;
7762 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7763 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7764 LocalContext context;
7765 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7766
7767 v8::Handle<Value> value = CompileRun(
7768 "function len(x) { return x.length; };"
7769 "o.__proto__ = this;"
7770 "var m = 'parseFloat';"
7771 "var result = 0;"
7772 "for (var i = 0; i < 10; i++) {"
7773 " if (i == 5) {"
7774 " m = 'len';"
7775 " saved_result = result;"
7776 " };"
7777 " result = o[m]('239');"
7778 "}");
7779 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7780 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7781}
7782
7783// Test the map transition before the interceptor.
7784THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7785 v8::HandleScope scope;
7786 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7787 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7788 LocalContext context;
7789 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7790
7791 v8::Handle<Value> value = CompileRun(
7792 "var o = new Object();"
7793 "o.__proto__ = proto;"
7794 "o.method = function(x) { return x + 1; };"
7795 "var m = 'method';"
7796 "var result = 0;"
7797 "for (var i = 0; i < 10; i++) {"
7798 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
7799 " result += o[m](41);"
7800 "}");
7801 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7802}
7803
7804
7805// Test the map transition after the interceptor.
7806THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7807 v8::HandleScope scope;
7808 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7809 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7810 LocalContext context;
7811 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7812
7813 v8::Handle<Value> value = CompileRun(
7814 "var proto = new Object();"
7815 "o.__proto__ = proto;"
7816 "proto.method = function(x) { return x + 1; };"
7817 "var m = 'method';"
7818 "var result = 0;"
7819 "for (var i = 0; i < 10; i++) {"
7820 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7821 " result += o[m](41);"
7822 "}");
7823 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7824}
7825
7826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007827static int interceptor_call_count = 0;
7828
7829static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7830 const AccessorInfo& info) {
7831 ApiTestFuzzer::Fuzz();
7832 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7833 return call_ic_function2;
7834 }
7835 return v8::Handle<Value>();
7836}
7837
7838
7839// This test should hit load and call ICs for the interceptor case.
7840// Once in a while, the interceptor will reply that a property was not
7841// found in which case we should get a reference error.
7842THREADED_TEST(InterceptorICReferenceErrors) {
7843 v8::HandleScope scope;
7844 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7845 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7846 LocalContext context(0, templ, v8::Handle<Value>());
7847 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7848 v8::Handle<Value> value = CompileRun(
7849 "function f() {"
7850 " for (var i = 0; i < 1000; i++) {"
7851 " try { x; } catch(e) { return true; }"
7852 " }"
7853 " return false;"
7854 "};"
7855 "f();");
7856 CHECK_EQ(true, value->BooleanValue());
7857 interceptor_call_count = 0;
7858 value = CompileRun(
7859 "function g() {"
7860 " for (var i = 0; i < 1000; i++) {"
7861 " try { x(42); } catch(e) { return true; }"
7862 " }"
7863 " return false;"
7864 "};"
7865 "g();");
7866 CHECK_EQ(true, value->BooleanValue());
7867}
7868
7869
7870static int interceptor_ic_exception_get_count = 0;
7871
7872static v8::Handle<Value> InterceptorICExceptionGetter(
7873 Local<String> name,
7874 const AccessorInfo& info) {
7875 ApiTestFuzzer::Fuzz();
7876 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7877 return call_ic_function3;
7878 }
7879 if (interceptor_ic_exception_get_count == 20) {
7880 return v8::ThrowException(v8_num(42));
7881 }
7882 // Do not handle get for properties other than x.
7883 return v8::Handle<Value>();
7884}
7885
7886// Test interceptor load/call IC where the interceptor throws an
7887// exception once in a while.
7888THREADED_TEST(InterceptorICGetterExceptions) {
7889 interceptor_ic_exception_get_count = 0;
7890 v8::HandleScope scope;
7891 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7892 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7893 LocalContext context(0, templ, v8::Handle<Value>());
7894 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7895 v8::Handle<Value> value = CompileRun(
7896 "function f() {"
7897 " for (var i = 0; i < 100; i++) {"
7898 " try { x; } catch(e) { return true; }"
7899 " }"
7900 " return false;"
7901 "};"
7902 "f();");
7903 CHECK_EQ(true, value->BooleanValue());
7904 interceptor_ic_exception_get_count = 0;
7905 value = CompileRun(
7906 "function f() {"
7907 " for (var i = 0; i < 100; i++) {"
7908 " try { x(42); } catch(e) { return true; }"
7909 " }"
7910 " return false;"
7911 "};"
7912 "f();");
7913 CHECK_EQ(true, value->BooleanValue());
7914}
7915
7916
7917static int interceptor_ic_exception_set_count = 0;
7918
7919static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007920 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007921 ApiTestFuzzer::Fuzz();
7922 if (++interceptor_ic_exception_set_count > 20) {
7923 return v8::ThrowException(v8_num(42));
7924 }
7925 // Do not actually handle setting.
7926 return v8::Handle<Value>();
7927}
7928
7929// Test interceptor store IC where the interceptor throws an exception
7930// once in a while.
7931THREADED_TEST(InterceptorICSetterExceptions) {
7932 interceptor_ic_exception_set_count = 0;
7933 v8::HandleScope scope;
7934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7935 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7936 LocalContext context(0, templ, v8::Handle<Value>());
7937 v8::Handle<Value> value = CompileRun(
7938 "function f() {"
7939 " for (var i = 0; i < 100; i++) {"
7940 " try { x = 42; } catch(e) { return true; }"
7941 " }"
7942 " return false;"
7943 "};"
7944 "f();");
7945 CHECK_EQ(true, value->BooleanValue());
7946}
7947
7948
7949// Test that we ignore null interceptors.
7950THREADED_TEST(NullNamedInterceptor) {
7951 v8::HandleScope scope;
7952 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7953 templ->SetNamedPropertyHandler(0);
7954 LocalContext context;
7955 templ->Set("x", v8_num(42));
7956 v8::Handle<v8::Object> obj = templ->NewInstance();
7957 context->Global()->Set(v8_str("obj"), obj);
7958 v8::Handle<Value> value = CompileRun("obj.x");
7959 CHECK(value->IsInt32());
7960 CHECK_EQ(42, value->Int32Value());
7961}
7962
7963
7964// Test that we ignore null interceptors.
7965THREADED_TEST(NullIndexedInterceptor) {
7966 v8::HandleScope scope;
7967 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7968 templ->SetIndexedPropertyHandler(0);
7969 LocalContext context;
7970 templ->Set("42", v8_num(42));
7971 v8::Handle<v8::Object> obj = templ->NewInstance();
7972 context->Global()->Set(v8_str("obj"), obj);
7973 v8::Handle<Value> value = CompileRun("obj[42]");
7974 CHECK(value->IsInt32());
7975 CHECK_EQ(42, value->Int32Value());
7976}
7977
7978
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007979THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7980 v8::HandleScope scope;
7981 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7982 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7983 LocalContext env;
7984 env->Global()->Set(v8_str("obj"),
7985 templ->GetFunction()->NewInstance());
7986 ExpectTrue("obj.x === 42");
7987 ExpectTrue("!obj.propertyIsEnumerable('x')");
7988}
7989
7990
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007991static v8::Handle<Value> ParentGetter(Local<String> name,
7992 const AccessorInfo& info) {
7993 ApiTestFuzzer::Fuzz();
7994 return v8_num(1);
7995}
7996
7997
7998static v8::Handle<Value> ChildGetter(Local<String> name,
7999 const AccessorInfo& info) {
8000 ApiTestFuzzer::Fuzz();
8001 return v8_num(42);
8002}
8003
8004
8005THREADED_TEST(Overriding) {
8006 v8::HandleScope scope;
8007 LocalContext context;
8008
8009 // Parent template.
8010 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8011 Local<ObjectTemplate> parent_instance_templ =
8012 parent_templ->InstanceTemplate();
8013 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8014
8015 // Template that inherits from the parent template.
8016 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8017 Local<ObjectTemplate> child_instance_templ =
8018 child_templ->InstanceTemplate();
8019 child_templ->Inherit(parent_templ);
8020 // Override 'f'. The child version of 'f' should get called for child
8021 // instances.
8022 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8023 // Add 'g' twice. The 'g' added last should get called for instances.
8024 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8025 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8026
8027 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8028 // so 'h' can be shadowed on the instance object.
8029 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8030 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8031 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8032
8033 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8034 // but the attribute does not have effect because it is duplicated with
8035 // NULL setter.
8036 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8037 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8038
8039
8040
8041 // Instantiate the child template.
8042 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8043
8044 // Check that the child function overrides the parent one.
8045 context->Global()->Set(v8_str("o"), instance);
8046 Local<Value> value = v8_compile("o.f")->Run();
8047 // Check that the 'g' that was added last is hit.
8048 CHECK_EQ(42, value->Int32Value());
8049 value = v8_compile("o.g")->Run();
8050 CHECK_EQ(42, value->Int32Value());
8051
8052 // Check 'h' can be shadowed.
8053 value = v8_compile("o.h = 3; o.h")->Run();
8054 CHECK_EQ(3, value->Int32Value());
8055
8056 // Check 'i' is cannot be shadowed or changed.
8057 value = v8_compile("o.i = 3; o.i")->Run();
8058 CHECK_EQ(42, value->Int32Value());
8059}
8060
8061
8062static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8063 ApiTestFuzzer::Fuzz();
8064 if (args.IsConstructCall()) {
8065 return v8::Boolean::New(true);
8066 }
8067 return v8::Boolean::New(false);
8068}
8069
8070
8071THREADED_TEST(IsConstructCall) {
8072 v8::HandleScope scope;
8073
8074 // Function template with call handler.
8075 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8076 templ->SetCallHandler(IsConstructHandler);
8077
8078 LocalContext context;
8079
8080 context->Global()->Set(v8_str("f"), templ->GetFunction());
8081 Local<Value> value = v8_compile("f()")->Run();
8082 CHECK(!value->BooleanValue());
8083 value = v8_compile("new f()")->Run();
8084 CHECK(value->BooleanValue());
8085}
8086
8087
8088THREADED_TEST(ObjectProtoToString) {
8089 v8::HandleScope scope;
8090 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8091 templ->SetClassName(v8_str("MyClass"));
8092
8093 LocalContext context;
8094
8095 Local<String> customized_tostring = v8_str("customized toString");
8096
8097 // Replace Object.prototype.toString
8098 v8_compile("Object.prototype.toString = function() {"
8099 " return 'customized toString';"
8100 "}")->Run();
8101
8102 // Normal ToString call should call replaced Object.prototype.toString
8103 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8104 Local<String> value = instance->ToString();
8105 CHECK(value->IsString() && value->Equals(customized_tostring));
8106
8107 // ObjectProtoToString should not call replace toString function.
8108 value = instance->ObjectProtoToString();
8109 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8110
8111 // Check global
8112 value = context->Global()->ObjectProtoToString();
8113 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8114
8115 // Check ordinary object
8116 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008117 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008118 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8119}
8120
8121
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008122THREADED_TEST(ObjectGetConstructorName) {
8123 v8::HandleScope scope;
8124 LocalContext context;
8125 v8_compile("function Parent() {};"
8126 "function Child() {};"
8127 "Child.prototype = new Parent();"
8128 "var outer = { inner: function() { } };"
8129 "var p = new Parent();"
8130 "var c = new Child();"
8131 "var x = new outer.inner();")->Run();
8132
8133 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8134 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8135 v8_str("Parent")));
8136
8137 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8138 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8139 v8_str("Child")));
8140
8141 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8142 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8143 v8_str("outer.inner")));
8144}
8145
8146
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008147bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008148i::Semaphore* ApiTestFuzzer::all_tests_done_=
8149 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008150int ApiTestFuzzer::active_tests_;
8151int ApiTestFuzzer::tests_being_run_;
8152int ApiTestFuzzer::current_;
8153
8154
8155// We are in a callback and want to switch to another thread (if we
8156// are currently running the thread fuzzing test).
8157void ApiTestFuzzer::Fuzz() {
8158 if (!fuzzing_) return;
8159 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8160 test->ContextSwitch();
8161}
8162
8163
8164// Let the next thread go. Since it is also waiting on the V8 lock it may
8165// not start immediately.
8166bool ApiTestFuzzer::NextThread() {
8167 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008168 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008169 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008170 if (kLogThreading)
8171 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008172 return false;
8173 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008174 if (kLogThreading) {
8175 printf("Switch from %s to %s\n",
8176 test_name,
8177 RegisterThreadedTest::nth(test_position)->name());
8178 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008179 current_ = test_position;
8180 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8181 return true;
8182}
8183
8184
8185void ApiTestFuzzer::Run() {
8186 // When it is our turn...
8187 gate_->Wait();
8188 {
8189 // ... get the V8 lock and start running the test.
8190 v8::Locker locker;
8191 CallTest();
8192 }
8193 // This test finished.
8194 active_ = false;
8195 active_tests_--;
8196 // If it was the last then signal that fact.
8197 if (active_tests_ == 0) {
8198 all_tests_done_->Signal();
8199 } else {
8200 // Otherwise select a new test and start that.
8201 NextThread();
8202 }
8203}
8204
8205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008206static unsigned linear_congruential_generator;
8207
8208
8209void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008210 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008211 fuzzing_ = true;
8212 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8213 int end = (part == FIRST_PART)
8214 ? (RegisterThreadedTest::count() >> 1)
8215 : RegisterThreadedTest::count();
8216 active_tests_ = tests_being_run_ = end - start;
8217 for (int i = 0; i < tests_being_run_; i++) {
8218 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8219 }
8220 for (int i = 0; i < active_tests_; i++) {
8221 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8222 }
8223}
8224
8225
8226static void CallTestNumber(int test_number) {
8227 (RegisterThreadedTest::nth(test_number)->callback())();
8228}
8229
8230
8231void ApiTestFuzzer::RunAllTests() {
8232 // Set off the first test.
8233 current_ = -1;
8234 NextThread();
8235 // Wait till they are all done.
8236 all_tests_done_->Wait();
8237}
8238
8239
8240int ApiTestFuzzer::GetNextTestNumber() {
8241 int next_test;
8242 do {
8243 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8244 linear_congruential_generator *= 1664525u;
8245 linear_congruential_generator += 1013904223u;
8246 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8247 return next_test;
8248}
8249
8250
8251void ApiTestFuzzer::ContextSwitch() {
8252 // If the new thread is the same as the current thread there is nothing to do.
8253 if (NextThread()) {
8254 // Now it can start.
8255 v8::Unlocker unlocker;
8256 // Wait till someone starts us again.
8257 gate_->Wait();
8258 // And we're off.
8259 }
8260}
8261
8262
8263void ApiTestFuzzer::TearDown() {
8264 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00008265 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8266 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8267 if (fuzzer != NULL) fuzzer->Join();
8268 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008269}
8270
8271
8272// Lets not be needlessly self-referential.
8273TEST(Threading) {
8274 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8275 ApiTestFuzzer::RunAllTests();
8276 ApiTestFuzzer::TearDown();
8277}
8278
8279TEST(Threading2) {
8280 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8281 ApiTestFuzzer::RunAllTests();
8282 ApiTestFuzzer::TearDown();
8283}
8284
8285
8286void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008287 if (kLogThreading)
8288 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008289 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008290 if (kLogThreading)
8291 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008292}
8293
8294
8295static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008296 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008297 ApiTestFuzzer::Fuzz();
8298 v8::Unlocker unlocker;
8299 const char* code = "throw 7;";
8300 {
8301 v8::Locker nested_locker;
8302 v8::HandleScope scope;
8303 v8::Handle<Value> exception;
8304 { v8::TryCatch try_catch;
8305 v8::Handle<Value> value = CompileRun(code);
8306 CHECK(value.IsEmpty());
8307 CHECK(try_catch.HasCaught());
8308 // Make sure to wrap the exception in a new handle because
8309 // the handle returned from the TryCatch is destroyed
8310 // when the TryCatch is destroyed.
8311 exception = Local<Value>::New(try_catch.Exception());
8312 }
8313 return v8::ThrowException(exception);
8314 }
8315}
8316
8317
8318static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008319 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008320 ApiTestFuzzer::Fuzz();
8321 v8::Unlocker unlocker;
8322 const char* code = "throw 7;";
8323 {
8324 v8::Locker nested_locker;
8325 v8::HandleScope scope;
8326 v8::Handle<Value> value = CompileRun(code);
8327 CHECK(value.IsEmpty());
8328 return v8_str("foo");
8329 }
8330}
8331
8332
8333// These are locking tests that don't need to be run again
8334// as part of the locking aggregation tests.
8335TEST(NestedLockers) {
8336 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008337 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008338 v8::HandleScope scope;
8339 LocalContext env;
8340 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8341 Local<Function> fun = fun_templ->GetFunction();
8342 env->Global()->Set(v8_str("throw_in_js"), fun);
8343 Local<Script> script = v8_compile("(function () {"
8344 " try {"
8345 " throw_in_js();"
8346 " return 42;"
8347 " } catch (e) {"
8348 " return e * 13;"
8349 " }"
8350 "})();");
8351 CHECK_EQ(91, script->Run()->Int32Value());
8352}
8353
8354
8355// These are locking tests that don't need to be run again
8356// as part of the locking aggregation tests.
8357TEST(NestedLockersNoTryCatch) {
8358 v8::Locker locker;
8359 v8::HandleScope scope;
8360 LocalContext env;
8361 Local<v8::FunctionTemplate> fun_templ =
8362 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8363 Local<Function> fun = fun_templ->GetFunction();
8364 env->Global()->Set(v8_str("throw_in_js"), fun);
8365 Local<Script> script = v8_compile("(function () {"
8366 " try {"
8367 " throw_in_js();"
8368 " return 42;"
8369 " } catch (e) {"
8370 " return e * 13;"
8371 " }"
8372 "})();");
8373 CHECK_EQ(91, script->Run()->Int32Value());
8374}
8375
8376
8377THREADED_TEST(RecursiveLocking) {
8378 v8::Locker locker;
8379 {
8380 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008381 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008382 }
8383}
8384
8385
8386static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8387 ApiTestFuzzer::Fuzz();
8388 v8::Unlocker unlocker;
8389 return v8::Undefined();
8390}
8391
8392
8393THREADED_TEST(LockUnlockLock) {
8394 {
8395 v8::Locker locker;
8396 v8::HandleScope scope;
8397 LocalContext env;
8398 Local<v8::FunctionTemplate> fun_templ =
8399 v8::FunctionTemplate::New(UnlockForAMoment);
8400 Local<Function> fun = fun_templ->GetFunction();
8401 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8402 Local<Script> script = v8_compile("(function () {"
8403 " unlock_for_a_moment();"
8404 " return 42;"
8405 "})();");
8406 CHECK_EQ(42, script->Run()->Int32Value());
8407 }
8408 {
8409 v8::Locker locker;
8410 v8::HandleScope scope;
8411 LocalContext env;
8412 Local<v8::FunctionTemplate> fun_templ =
8413 v8::FunctionTemplate::New(UnlockForAMoment);
8414 Local<Function> fun = fun_templ->GetFunction();
8415 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8416 Local<Script> script = v8_compile("(function () {"
8417 " unlock_for_a_moment();"
8418 " return 42;"
8419 "})();");
8420 CHECK_EQ(42, script->Run()->Int32Value());
8421 }
8422}
8423
8424
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008425static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008426 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008427 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008428 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8429 if (object->IsJSGlobalObject()) count++;
8430 return count;
8431}
8432
8433
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008434static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008435 // We need to collect all garbage twice to be sure that everything
8436 // has been collected. This is because inline caches are cleared in
8437 // the first garbage collection but some of the maps have already
8438 // been marked at that point. Therefore some of the maps are not
8439 // collected until the second garbage collection.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008440 i::Heap::CollectAllGarbage(false);
8441 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008442 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008443#ifdef DEBUG
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008444 if (count != expected) i::Heap::TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008445#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008446 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008447}
8448
8449
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008450TEST(DontLeakGlobalObjects) {
8451 // Regression test for issues 1139850 and 1174891.
8452
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008453 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008454
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008455 for (int i = 0; i < 5; i++) {
8456 { v8::HandleScope scope;
8457 LocalContext context;
8458 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008459 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008460
8461 { v8::HandleScope scope;
8462 LocalContext context;
8463 v8_compile("Date")->Run();
8464 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008465 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008466
8467 { v8::HandleScope scope;
8468 LocalContext context;
8469 v8_compile("/aaa/")->Run();
8470 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008471 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008472
8473 { v8::HandleScope scope;
8474 const char* extension_list[] = { "v8/gc" };
8475 v8::ExtensionConfiguration extensions(1, extension_list);
8476 LocalContext context(&extensions);
8477 v8_compile("gc();")->Run();
8478 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008479 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008480 }
8481}
8482
8483
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008484v8::Persistent<v8::Object> some_object;
8485v8::Persistent<v8::Object> bad_handle;
8486
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008487void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008488 v8::HandleScope scope;
8489 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008490 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008491}
8492
8493
8494THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8495 LocalContext context;
8496
8497 v8::Persistent<v8::Object> handle1, handle2;
8498 {
8499 v8::HandleScope scope;
8500 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8501 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8502 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8503 }
8504 // Note: order is implementation dependent alas: currently
8505 // global handle nodes are processed by PostGarbageCollectionProcessing
8506 // in reverse allocation order, so if second allocated handle is deleted,
8507 // weak callback of the first handle would be able to 'reallocate' it.
8508 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8509 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008510 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008511}
8512
8513
8514v8::Persistent<v8::Object> to_be_disposed;
8515
8516void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8517 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008518 i::Heap::CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008519 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008520}
8521
8522
8523THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8524 LocalContext context;
8525
8526 v8::Persistent<v8::Object> handle1, handle2;
8527 {
8528 v8::HandleScope scope;
8529 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8530 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8531 }
8532 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8533 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008534 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008535}
8536
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008537void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8538 handle.Dispose();
8539}
8540
8541void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8542 v8::HandleScope scope;
8543 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008544 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008545}
8546
8547
8548THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8549 LocalContext context;
8550
8551 v8::Persistent<v8::Object> handle1, handle2, handle3;
8552 {
8553 v8::HandleScope scope;
8554 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8555 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8556 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8557 }
8558 handle2.MakeWeak(NULL, DisposingCallback);
8559 handle3.MakeWeak(NULL, HandleCreatingCallback);
8560 i::Heap::CollectAllGarbage(false);
8561}
8562
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008563
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008564THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008565 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008566
8567 const int nof = 2;
8568 const char* sources[nof] = {
8569 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8570 "Object()"
8571 };
8572
8573 for (int i = 0; i < nof; i++) {
8574 const char* source = sources[i];
8575 { v8::HandleScope scope;
8576 LocalContext context;
8577 CompileRun(source);
8578 }
8579 { v8::HandleScope scope;
8580 LocalContext context;
8581 CompileRun(source);
8582 }
8583 }
8584}
8585
8586
8587static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8588 v8::HandleScope inner;
8589 env->Enter();
8590 v8::Handle<Value> three = v8_num(3);
8591 v8::Handle<Value> value = inner.Close(three);
8592 env->Exit();
8593 return value;
8594}
8595
8596
8597THREADED_TEST(NestedHandleScopeAndContexts) {
8598 v8::HandleScope outer;
8599 v8::Persistent<Context> env = Context::New();
8600 env->Enter();
8601 v8::Handle<Value> value = NestedScope(env);
8602 v8::Handle<String> str = value->ToString();
8603 env->Exit();
8604 env.Dispose();
8605}
8606
8607
8608THREADED_TEST(ExternalAllocatedMemory) {
8609 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008610 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008611 const int kSize = 1024*1024;
8612 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8613 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8614}
8615
8616
8617THREADED_TEST(DisposeEnteredContext) {
8618 v8::HandleScope scope;
8619 LocalContext outer;
8620 { v8::Persistent<v8::Context> inner = v8::Context::New();
8621 inner->Enter();
8622 inner.Dispose();
8623 inner.Clear();
8624 inner->Exit();
8625 }
8626}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008627
8628
8629// Regression test for issue 54, object templates with internal fields
8630// but no accessors or interceptors did not get their internal field
8631// count set on instances.
8632THREADED_TEST(Regress54) {
8633 v8::HandleScope outer;
8634 LocalContext context;
8635 static v8::Persistent<v8::ObjectTemplate> templ;
8636 if (templ.IsEmpty()) {
8637 v8::HandleScope inner;
8638 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8639 local->SetInternalFieldCount(1);
8640 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8641 }
8642 v8::Handle<v8::Object> result = templ->NewInstance();
8643 CHECK_EQ(1, result->InternalFieldCount());
8644}
8645
8646
8647// If part of the threaded tests, this test makes ThreadingTest fail
8648// on mac.
8649TEST(CatchStackOverflow) {
8650 v8::HandleScope scope;
8651 LocalContext context;
8652 v8::TryCatch try_catch;
8653 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8654 "function f() {"
8655 " return f();"
8656 "}"
8657 ""
8658 "f();"));
8659 v8::Handle<v8::Value> result = script->Run();
8660 CHECK(result.IsEmpty());
8661}
8662
8663
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008664static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8665 const char* resource_name,
8666 int line_offset) {
8667 v8::HandleScope scope;
8668 v8::TryCatch try_catch;
8669 v8::Handle<v8::Value> result = script->Run();
8670 CHECK(result.IsEmpty());
8671 CHECK(try_catch.HasCaught());
8672 v8::Handle<v8::Message> message = try_catch.Message();
8673 CHECK(!message.IsEmpty());
8674 CHECK_EQ(10 + line_offset, message->GetLineNumber());
8675 CHECK_EQ(91, message->GetStartPosition());
8676 CHECK_EQ(92, message->GetEndPosition());
8677 CHECK_EQ(2, message->GetStartColumn());
8678 CHECK_EQ(3, message->GetEndColumn());
8679 v8::String::AsciiValue line(message->GetSourceLine());
8680 CHECK_EQ(" throw 'nirk';", *line);
8681 v8::String::AsciiValue name(message->GetScriptResourceName());
8682 CHECK_EQ(resource_name, *name);
8683}
8684
8685
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008686THREADED_TEST(TryCatchSourceInfo) {
8687 v8::HandleScope scope;
8688 LocalContext context;
8689 v8::Handle<v8::String> source = v8::String::New(
8690 "function Foo() {\n"
8691 " return Bar();\n"
8692 "}\n"
8693 "\n"
8694 "function Bar() {\n"
8695 " return Baz();\n"
8696 "}\n"
8697 "\n"
8698 "function Baz() {\n"
8699 " throw 'nirk';\n"
8700 "}\n"
8701 "\n"
8702 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008703
8704 const char* resource_name;
8705 v8::Handle<v8::Script> script;
8706 resource_name = "test.js";
8707 script = v8::Script::Compile(source, v8::String::New(resource_name));
8708 CheckTryCatchSourceInfo(script, resource_name, 0);
8709
8710 resource_name = "test1.js";
8711 v8::ScriptOrigin origin1(v8::String::New(resource_name));
8712 script = v8::Script::Compile(source, &origin1);
8713 CheckTryCatchSourceInfo(script, resource_name, 0);
8714
8715 resource_name = "test2.js";
8716 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8717 script = v8::Script::Compile(source, &origin2);
8718 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008719}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008720
8721
8722THREADED_TEST(CompilationCache) {
8723 v8::HandleScope scope;
8724 LocalContext context;
8725 v8::Handle<v8::String> source0 = v8::String::New("1234");
8726 v8::Handle<v8::String> source1 = v8::String::New("1234");
8727 v8::Handle<v8::Script> script0 =
8728 v8::Script::Compile(source0, v8::String::New("test.js"));
8729 v8::Handle<v8::Script> script1 =
8730 v8::Script::Compile(source1, v8::String::New("test.js"));
8731 v8::Handle<v8::Script> script2 =
8732 v8::Script::Compile(source0); // different origin
8733 CHECK_EQ(1234, script0->Run()->Int32Value());
8734 CHECK_EQ(1234, script1->Run()->Int32Value());
8735 CHECK_EQ(1234, script2->Run()->Int32Value());
8736}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008737
8738
8739static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8740 ApiTestFuzzer::Fuzz();
8741 return v8_num(42);
8742}
8743
8744
8745THREADED_TEST(CallbackFunctionName) {
8746 v8::HandleScope scope;
8747 LocalContext context;
8748 Local<ObjectTemplate> t = ObjectTemplate::New();
8749 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8750 context->Global()->Set(v8_str("obj"), t->NewInstance());
8751 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8752 CHECK(value->IsString());
8753 v8::String::AsciiValue name(value);
8754 CHECK_EQ("asdf", *name);
8755}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008756
8757
8758THREADED_TEST(DateAccess) {
8759 v8::HandleScope scope;
8760 LocalContext context;
8761 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8762 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008763 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008764}
8765
8766
8767void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008768 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008769 v8::Handle<v8::Array> props = obj->GetPropertyNames();
8770 CHECK_EQ(elmc, props->Length());
8771 for (int i = 0; i < elmc; i++) {
8772 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8773 CHECK_EQ(elmv[i], *elm);
8774 }
8775}
8776
8777
8778THREADED_TEST(PropertyEnumeration) {
8779 v8::HandleScope scope;
8780 LocalContext context;
8781 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8782 "var result = [];"
8783 "result[0] = {};"
8784 "result[1] = {a: 1, b: 2};"
8785 "result[2] = [1, 2, 3];"
8786 "var proto = {x: 1, y: 2, z: 3};"
8787 "var x = { __proto__: proto, w: 0, z: 1 };"
8788 "result[3] = x;"
8789 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008790 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008791 CHECK_EQ(4, elms->Length());
8792 int elmc0 = 0;
8793 const char** elmv0 = NULL;
8794 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8795 int elmc1 = 2;
8796 const char* elmv1[] = {"a", "b"};
8797 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8798 int elmc2 = 3;
8799 const char* elmv2[] = {"0", "1", "2"};
8800 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8801 int elmc3 = 4;
8802 const char* elmv3[] = {"w", "z", "x", "y"};
8803 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8804}
ager@chromium.org870a0b62008-11-04 11:43:05 +00008805
8806
ager@chromium.org870a0b62008-11-04 11:43:05 +00008807static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8808 Local<Value> name,
8809 v8::AccessType type,
8810 Local<Value> data) {
8811 return type != v8::ACCESS_SET;
8812}
8813
8814
8815static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8816 uint32_t key,
8817 v8::AccessType type,
8818 Local<Value> data) {
8819 return type != v8::ACCESS_SET;
8820}
8821
8822
8823THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8824 v8::HandleScope scope;
8825 LocalContext context;
8826 Local<ObjectTemplate> templ = ObjectTemplate::New();
8827 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8828 IndexedSetAccessBlocker);
8829 templ->Set(v8_str("x"), v8::True());
8830 Local<v8::Object> instance = templ->NewInstance();
8831 context->Global()->Set(v8_str("obj"), instance);
8832 Local<Value> value = CompileRun("obj.x");
8833 CHECK(value->BooleanValue());
8834}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008835
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008836
ager@chromium.org32912102009-01-16 10:38:43 +00008837static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8838 Local<Value> name,
8839 v8::AccessType type,
8840 Local<Value> data) {
8841 return false;
8842}
8843
8844
8845static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8846 uint32_t key,
8847 v8::AccessType type,
8848 Local<Value> data) {
8849 return false;
8850}
8851
8852
8853
8854THREADED_TEST(AccessChecksReenabledCorrectly) {
8855 v8::HandleScope scope;
8856 LocalContext context;
8857 Local<ObjectTemplate> templ = ObjectTemplate::New();
8858 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8859 IndexedGetAccessBlocker);
8860 templ->Set(v8_str("a"), v8_str("a"));
8861 // Add more than 8 (see kMaxFastProperties) properties
8862 // so that the constructor will force copying map.
8863 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008864 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00008865 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008866 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00008867 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008868 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00008869 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008870 buf[2] = k;
8871 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00008872 templ->Set(v8_str(buf), v8::Number::New(k));
8873 }
8874 }
8875 }
8876
8877 Local<v8::Object> instance_1 = templ->NewInstance();
8878 context->Global()->Set(v8_str("obj_1"), instance_1);
8879
8880 Local<Value> value_1 = CompileRun("obj_1.a");
8881 CHECK(value_1->IsUndefined());
8882
8883 Local<v8::Object> instance_2 = templ->NewInstance();
8884 context->Global()->Set(v8_str("obj_2"), instance_2);
8885
8886 Local<Value> value_2 = CompileRun("obj_2.a");
8887 CHECK(value_2->IsUndefined());
8888}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008889
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008890
ager@chromium.org8bb60582008-12-11 12:02:20 +00008891// This tests that access check information remains on the global
8892// object template when creating contexts.
8893THREADED_TEST(AccessControlRepeatedContextCreation) {
8894 v8::HandleScope handle_scope;
8895 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8896 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8897 IndexedSetAccessBlocker);
8898 i::Handle<i::ObjectTemplateInfo> internal_template =
8899 v8::Utils::OpenHandle(*global_template);
8900 CHECK(!internal_template->constructor()->IsUndefined());
8901 i::Handle<i::FunctionTemplateInfo> constructor(
8902 i::FunctionTemplateInfo::cast(internal_template->constructor()));
8903 CHECK(!constructor->access_check_info()->IsUndefined());
8904 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8905 CHECK(!constructor->access_check_info()->IsUndefined());
8906}
8907
8908
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008909THREADED_TEST(TurnOnAccessCheck) {
8910 v8::HandleScope handle_scope;
8911
8912 // Create an environment with access check to the global object disabled by
8913 // default.
8914 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8915 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8916 IndexedGetAccessBlocker,
8917 v8::Handle<v8::Value>(),
8918 false);
8919 v8::Persistent<Context> context = Context::New(NULL, global_template);
8920 Context::Scope context_scope(context);
8921
8922 // Set up a property and a number of functions.
8923 context->Global()->Set(v8_str("a"), v8_num(1));
8924 CompileRun("function f1() {return a;}"
8925 "function f2() {return a;}"
8926 "function g1() {return h();}"
8927 "function g2() {return h();}"
8928 "function h() {return 1;}");
8929 Local<Function> f1 =
8930 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8931 Local<Function> f2 =
8932 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8933 Local<Function> g1 =
8934 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8935 Local<Function> g2 =
8936 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8937 Local<Function> h =
8938 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8939
8940 // Get the global object.
8941 v8::Handle<v8::Object> global = context->Global();
8942
8943 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8944 // uses the runtime system to retreive property a whereas f2 uses global load
8945 // inline cache.
8946 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8947 for (int i = 0; i < 4; i++) {
8948 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8949 }
8950
8951 // Same for g1 and g2.
8952 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8953 for (int i = 0; i < 4; i++) {
8954 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8955 }
8956
8957 // Detach the global and turn on access check.
8958 context->DetachGlobal();
8959 context->Global()->TurnOnAccessCheck();
8960
8961 // Failing access check to property get results in undefined.
8962 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8963 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8964
8965 // Failing access check to function call results in exception.
8966 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8967 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8968
8969 // No failing access check when just returning a constant.
8970 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8971}
8972
8973
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008974v8::Handle<v8::String> a;
8975v8::Handle<v8::String> h;
8976
8977static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8978 Local<Value> name,
8979 v8::AccessType type,
8980 Local<Value> data) {
8981 return !(name->Equals(a) || name->Equals(h));
8982}
8983
8984
8985THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8986 v8::HandleScope handle_scope;
8987
8988 // Create an environment with access check to the global object disabled by
8989 // default. When the registered access checker will block access to properties
8990 // a and h
8991 a = v8_str("a");
8992 h = v8_str("h");
8993 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8994 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8995 IndexedGetAccessBlocker,
8996 v8::Handle<v8::Value>(),
8997 false);
8998 v8::Persistent<Context> context = Context::New(NULL, global_template);
8999 Context::Scope context_scope(context);
9000
9001 // Set up a property and a number of functions.
9002 context->Global()->Set(v8_str("a"), v8_num(1));
9003 static const char* source = "function f1() {return a;}"
9004 "function f2() {return a;}"
9005 "function g1() {return h();}"
9006 "function g2() {return h();}"
9007 "function h() {return 1;}";
9008
9009 CompileRun(source);
9010 Local<Function> f1;
9011 Local<Function> f2;
9012 Local<Function> g1;
9013 Local<Function> g2;
9014 Local<Function> h;
9015 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9016 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9017 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9018 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9019 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9020
9021 // Get the global object.
9022 v8::Handle<v8::Object> global = context->Global();
9023
9024 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9025 // uses the runtime system to retreive property a whereas f2 uses global load
9026 // inline cache.
9027 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9028 for (int i = 0; i < 4; i++) {
9029 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9030 }
9031
9032 // Same for g1 and g2.
9033 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9034 for (int i = 0; i < 4; i++) {
9035 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9036 }
9037
9038 // Detach the global and turn on access check now blocking access to property
9039 // a and function h.
9040 context->DetachGlobal();
9041 context->Global()->TurnOnAccessCheck();
9042
9043 // Failing access check to property get results in undefined.
9044 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9045 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9046
9047 // Failing access check to function call results in exception.
9048 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9049 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9050
9051 // No failing access check when just returning a constant.
9052 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9053
9054 // Now compile the source again. And get the newly compiled functions, except
9055 // for h for which access is blocked.
9056 CompileRun(source);
9057 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9058 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9059 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9060 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9061 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9062
9063 // Failing access check to property get results in undefined.
9064 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9065 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9066
9067 // Failing access check to function call results in exception.
9068 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9069 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9070}
9071
9072
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009073// This test verifies that pre-compilation (aka preparsing) can be called
9074// without initializing the whole VM. Thus we cannot run this test in a
9075// multi-threaded setup.
9076TEST(PreCompile) {
9077 // TODO(155): This test would break without the initialization of V8. This is
9078 // a workaround for now to make this test not fail.
9079 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009080 const char* script = "function foo(a) { return a+1; }";
9081 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009082 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009083 CHECK_NE(sd->Length(), 0);
9084 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009085 CHECK(!sd->HasError());
9086 delete sd;
9087}
9088
9089
9090TEST(PreCompileWithError) {
9091 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009092 const char* script = "function foo(a) { return 1 * * 2; }";
9093 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009094 v8::ScriptData::PreCompile(script, i::StrLength(script));
9095 CHECK(sd->HasError());
9096 delete sd;
9097}
9098
9099
9100TEST(Regress31661) {
9101 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009102 const char* script = " The Definintive Guide";
9103 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009104 v8::ScriptData::PreCompile(script, i::StrLength(script));
9105 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009106 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009107}
9108
9109
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009110// Tests that ScriptData can be serialized and deserialized.
9111TEST(PreCompileSerialization) {
9112 v8::V8::Initialize();
9113 const char* script = "function foo(a) { return a+1; }";
9114 v8::ScriptData* sd =
9115 v8::ScriptData::PreCompile(script, i::StrLength(script));
9116
9117 // Serialize.
9118 int serialized_data_length = sd->Length();
9119 char* serialized_data = i::NewArray<char>(serialized_data_length);
9120 memcpy(serialized_data, sd->Data(), serialized_data_length);
9121
9122 // Deserialize.
9123 v8::ScriptData* deserialized_sd =
9124 v8::ScriptData::New(serialized_data, serialized_data_length);
9125
9126 // Verify that the original is the same as the deserialized.
9127 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9128 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9129 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9130
9131 delete sd;
9132 delete deserialized_sd;
9133}
9134
9135
9136// Attempts to deserialize bad data.
9137TEST(PreCompileDeserializationError) {
9138 v8::V8::Initialize();
9139 const char* data = "DONT CARE";
9140 int invalid_size = 3;
9141 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9142
9143 CHECK_EQ(0, sd->Length());
9144
9145 delete sd;
9146}
9147
9148
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009149// Attempts to deserialize bad data.
9150TEST(PreCompileInvalidPreparseDataError) {
9151 v8::V8::Initialize();
9152 v8::HandleScope scope;
9153 LocalContext context;
9154
9155 const char* script = "function foo(){ return 5;}\n"
9156 "function bar(){ return 6 + 7;} foo();";
9157 v8::ScriptData* sd =
9158 v8::ScriptData::PreCompile(script, i::StrLength(script));
9159 CHECK(!sd->HasError());
9160 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009161 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009162 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009163 const int kFunctionEntryStartOffset = 0;
9164 const int kFunctionEntryEndOffset = 1;
9165 unsigned* sd_data =
9166 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009167
9168 // Overwrite function bar's end position with 0.
9169 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9170 v8::TryCatch try_catch;
9171
9172 Local<String> source = String::New(script);
9173 Local<Script> compiled_script = Script::New(source, NULL, sd);
9174 CHECK(try_catch.HasCaught());
9175 String::AsciiValue exception_value(try_catch.Message()->Get());
9176 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9177 *exception_value);
9178
9179 try_catch.Reset();
9180 // Overwrite function bar's start position with 200. The function entry
9181 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009182 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9183 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009184 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9185 200;
9186 compiled_script = Script::New(source, NULL, sd);
9187 CHECK(try_catch.HasCaught());
9188 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9189 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9190 *second_exception_value);
9191
9192 delete sd;
9193}
9194
9195
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009196// Verifies that the Handle<String> and const char* versions of the API produce
9197// the same results (at least for one trivial case).
9198TEST(PreCompileAPIVariationsAreSame) {
9199 v8::V8::Initialize();
9200 v8::HandleScope scope;
9201
9202 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009203
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009204 v8::ScriptData* sd_from_cstring =
9205 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9206
9207 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009208 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009209 v8::String::NewExternal(resource));
9210
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009211 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9212 v8::String::New(cstring));
9213
9214 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009215 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009216 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009217 sd_from_cstring->Length()));
9218
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009219 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9220 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9221 sd_from_string->Data(),
9222 sd_from_cstring->Length()));
9223
9224
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009225 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009226 delete sd_from_external_string;
9227 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009228}
9229
9230
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009231// This tests that we do not allow dictionary load/call inline caches
9232// to use functions that have not yet been compiled. The potential
9233// problem of loading a function that has not yet been compiled can
9234// arise because we share code between contexts via the compilation
9235// cache.
9236THREADED_TEST(DictionaryICLoadedFunction) {
9237 v8::HandleScope scope;
9238 // Test LoadIC.
9239 for (int i = 0; i < 2; i++) {
9240 LocalContext context;
9241 context->Global()->Set(v8_str("tmp"), v8::True());
9242 context->Global()->Delete(v8_str("tmp"));
9243 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9244 }
9245 // Test CallIC.
9246 for (int i = 0; i < 2; i++) {
9247 LocalContext context;
9248 context->Global()->Set(v8_str("tmp"), v8::True());
9249 context->Global()->Delete(v8_str("tmp"));
9250 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9251 }
9252}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009253
9254
9255// Test that cross-context new calls use the context of the callee to
9256// create the new JavaScript object.
9257THREADED_TEST(CrossContextNew) {
9258 v8::HandleScope scope;
9259 v8::Persistent<Context> context0 = Context::New();
9260 v8::Persistent<Context> context1 = Context::New();
9261
9262 // Allow cross-domain access.
9263 Local<String> token = v8_str("<security token>");
9264 context0->SetSecurityToken(token);
9265 context1->SetSecurityToken(token);
9266
9267 // Set an 'x' property on the Object prototype and define a
9268 // constructor function in context0.
9269 context0->Enter();
9270 CompileRun("Object.prototype.x = 42; function C() {};");
9271 context0->Exit();
9272
9273 // Call the constructor function from context0 and check that the
9274 // result has the 'x' property.
9275 context1->Enter();
9276 context1->Global()->Set(v8_str("other"), context0->Global());
9277 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9278 CHECK(value->IsInt32());
9279 CHECK_EQ(42, value->Int32Value());
9280 context1->Exit();
9281
9282 // Dispose the contexts to allow them to be garbage collected.
9283 context0.Dispose();
9284 context1.Dispose();
9285}
ager@chromium.org381abbb2009-02-25 13:23:22 +00009286
9287
9288class RegExpInterruptTest {
9289 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009290 RegExpInterruptTest() : block_(NULL) {}
9291 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009292 void RunTest() {
9293 block_ = i::OS::CreateSemaphore(0);
9294 gc_count_ = 0;
9295 gc_during_regexp_ = 0;
9296 regexp_success_ = false;
9297 gc_success_ = false;
9298 GCThread gc_thread(this);
9299 gc_thread.Start();
9300 v8::Locker::StartPreemption(1);
9301
9302 LongRunningRegExp();
9303 {
9304 v8::Unlocker unlock;
9305 gc_thread.Join();
9306 }
9307 v8::Locker::StopPreemption();
9308 CHECK(regexp_success_);
9309 CHECK(gc_success_);
9310 }
9311 private:
9312 // Number of garbage collections required.
9313 static const int kRequiredGCs = 5;
9314
9315 class GCThread : public i::Thread {
9316 public:
9317 explicit GCThread(RegExpInterruptTest* test)
9318 : test_(test) {}
9319 virtual void Run() {
9320 test_->CollectGarbage();
9321 }
9322 private:
9323 RegExpInterruptTest* test_;
9324 };
9325
9326 void CollectGarbage() {
9327 block_->Wait();
9328 while (gc_during_regexp_ < kRequiredGCs) {
9329 {
9330 v8::Locker lock;
9331 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009332 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009333 gc_count_++;
9334 }
9335 i::OS::Sleep(1);
9336 }
9337 gc_success_ = true;
9338 }
9339
9340 void LongRunningRegExp() {
9341 block_->Signal(); // Enable garbage collection thread on next preemption.
9342 int rounds = 0;
9343 while (gc_during_regexp_ < kRequiredGCs) {
9344 int gc_before = gc_count_;
9345 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009346 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009347 const char* c_source =
9348 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9349 ".exec('aaaaaaaaaaaaaaab') === null";
9350 Local<String> source = String::New(c_source);
9351 Local<Script> script = Script::Compile(source);
9352 Local<Value> result = script->Run();
9353 if (!result->BooleanValue()) {
9354 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9355 return;
9356 }
9357 }
9358 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009359 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009360 const char* c_source =
9361 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9362 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9363 Local<String> source = String::New(c_source);
9364 Local<Script> script = Script::Compile(source);
9365 Local<Value> result = script->Run();
9366 if (!result->BooleanValue()) {
9367 gc_during_regexp_ = kRequiredGCs;
9368 return;
9369 }
9370 }
9371 int gc_after = gc_count_;
9372 gc_during_regexp_ += gc_after - gc_before;
9373 rounds++;
9374 i::OS::Sleep(1);
9375 }
9376 regexp_success_ = true;
9377 }
9378
9379 i::Semaphore* block_;
9380 int gc_count_;
9381 int gc_during_regexp_;
9382 bool regexp_success_;
9383 bool gc_success_;
9384};
9385
9386
9387// Test that a regular expression execution can be interrupted and
9388// survive a garbage collection.
9389TEST(RegExpInterruption) {
9390 v8::Locker lock;
9391 v8::V8::Initialize();
9392 v8::HandleScope scope;
9393 Local<Context> local_env;
9394 {
9395 LocalContext env;
9396 local_env = env.local();
9397 }
9398
9399 // Local context should still be live.
9400 CHECK(!local_env.IsEmpty());
9401 local_env->Enter();
9402
9403 // Should complete without problems.
9404 RegExpInterruptTest().RunTest();
9405
9406 local_env->Exit();
9407}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009408
9409
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009410class ApplyInterruptTest {
9411 public:
9412 ApplyInterruptTest() : block_(NULL) {}
9413 ~ApplyInterruptTest() { delete block_; }
9414 void RunTest() {
9415 block_ = i::OS::CreateSemaphore(0);
9416 gc_count_ = 0;
9417 gc_during_apply_ = 0;
9418 apply_success_ = false;
9419 gc_success_ = false;
9420 GCThread gc_thread(this);
9421 gc_thread.Start();
9422 v8::Locker::StartPreemption(1);
9423
9424 LongRunningApply();
9425 {
9426 v8::Unlocker unlock;
9427 gc_thread.Join();
9428 }
9429 v8::Locker::StopPreemption();
9430 CHECK(apply_success_);
9431 CHECK(gc_success_);
9432 }
9433 private:
9434 // Number of garbage collections required.
9435 static const int kRequiredGCs = 2;
9436
9437 class GCThread : public i::Thread {
9438 public:
9439 explicit GCThread(ApplyInterruptTest* test)
9440 : test_(test) {}
9441 virtual void Run() {
9442 test_->CollectGarbage();
9443 }
9444 private:
9445 ApplyInterruptTest* test_;
9446 };
9447
9448 void CollectGarbage() {
9449 block_->Wait();
9450 while (gc_during_apply_ < kRequiredGCs) {
9451 {
9452 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009453 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009454 gc_count_++;
9455 }
9456 i::OS::Sleep(1);
9457 }
9458 gc_success_ = true;
9459 }
9460
9461 void LongRunningApply() {
9462 block_->Signal();
9463 int rounds = 0;
9464 while (gc_during_apply_ < kRequiredGCs) {
9465 int gc_before = gc_count_;
9466 {
9467 const char* c_source =
9468 "function do_very_little(bar) {"
9469 " this.foo = bar;"
9470 "}"
9471 "for (var i = 0; i < 100000; i++) {"
9472 " do_very_little.apply(this, ['bar']);"
9473 "}";
9474 Local<String> source = String::New(c_source);
9475 Local<Script> script = Script::Compile(source);
9476 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009477 // Check that no exception was thrown.
9478 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009479 }
9480 int gc_after = gc_count_;
9481 gc_during_apply_ += gc_after - gc_before;
9482 rounds++;
9483 }
9484 apply_success_ = true;
9485 }
9486
9487 i::Semaphore* block_;
9488 int gc_count_;
9489 int gc_during_apply_;
9490 bool apply_success_;
9491 bool gc_success_;
9492};
9493
9494
9495// Test that nothing bad happens if we get a preemption just when we were
9496// about to do an apply().
9497TEST(ApplyInterruption) {
9498 v8::Locker lock;
9499 v8::V8::Initialize();
9500 v8::HandleScope scope;
9501 Local<Context> local_env;
9502 {
9503 LocalContext env;
9504 local_env = env.local();
9505 }
9506
9507 // Local context should still be live.
9508 CHECK(!local_env.IsEmpty());
9509 local_env->Enter();
9510
9511 // Should complete without problems.
9512 ApplyInterruptTest().RunTest();
9513
9514 local_env->Exit();
9515}
9516
9517
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009518// Verify that we can clone an object
9519TEST(ObjectClone) {
9520 v8::HandleScope scope;
9521 LocalContext env;
9522
9523 const char* sample =
9524 "var rv = {};" \
9525 "rv.alpha = 'hello';" \
9526 "rv.beta = 123;" \
9527 "rv;";
9528
9529 // Create an object, verify basics.
9530 Local<Value> val = CompileRun(sample);
9531 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009532 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009533 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9534
9535 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9536 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9537 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9538
9539 // Clone it.
9540 Local<v8::Object> clone = obj->Clone();
9541 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9542 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9543 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9544
9545 // Set a property on the clone, verify each object.
9546 clone->Set(v8_str("beta"), v8::Integer::New(456));
9547 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9548 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9549}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009550
9551
ager@chromium.org5ec48922009-05-05 07:25:34 +00009552class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9553 public:
9554 explicit AsciiVectorResource(i::Vector<const char> vector)
9555 : data_(vector) {}
9556 virtual ~AsciiVectorResource() {}
9557 virtual size_t length() const { return data_.length(); }
9558 virtual const char* data() const { return data_.start(); }
9559 private:
9560 i::Vector<const char> data_;
9561};
9562
9563
9564class UC16VectorResource : public v8::String::ExternalStringResource {
9565 public:
9566 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9567 : data_(vector) {}
9568 virtual ~UC16VectorResource() {}
9569 virtual size_t length() const { return data_.length(); }
9570 virtual const i::uc16* data() const { return data_.start(); }
9571 private:
9572 i::Vector<const i::uc16> data_;
9573};
9574
9575
9576static void MorphAString(i::String* string,
9577 AsciiVectorResource* ascii_resource,
9578 UC16VectorResource* uc16_resource) {
9579 CHECK(i::StringShape(string).IsExternal());
9580 if (string->IsAsciiRepresentation()) {
9581 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009582 CHECK(string->map() == i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009583 // Morph external string to be TwoByte string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009584 string->set_map(i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009585 i::ExternalTwoByteString* morphed =
9586 i::ExternalTwoByteString::cast(string);
9587 morphed->set_resource(uc16_resource);
9588 } else {
9589 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009590 CHECK(string->map() == i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009591 // Morph external string to be ASCII string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009592 string->set_map(i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009593 i::ExternalAsciiString* morphed =
9594 i::ExternalAsciiString::cast(string);
9595 morphed->set_resource(ascii_resource);
9596 }
9597}
9598
9599
9600// Test that we can still flatten a string if the components it is built up
9601// from have been turned into 16 bit strings in the mean time.
9602THREADED_TEST(MorphCompositeStringTest) {
9603 const char* c_string = "Now is the time for all good men"
9604 " to come to the aid of the party";
9605 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9606 {
9607 v8::HandleScope scope;
9608 LocalContext env;
9609 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009610 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009611 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009612 i::Vector<const uint16_t>(two_byte_string,
9613 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009614
9615 Local<String> lhs(v8::Utils::ToLocal(
9616 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9617 Local<String> rhs(v8::Utils::ToLocal(
9618 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9619
9620 env->Global()->Set(v8_str("lhs"), lhs);
9621 env->Global()->Set(v8_str("rhs"), rhs);
9622
9623 CompileRun(
9624 "var cons = lhs + rhs;"
9625 "var slice = lhs.substring(1, lhs.length - 1);"
9626 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9627
9628 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9629 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9630
9631 // Now do some stuff to make sure the strings are flattened, etc.
9632 CompileRun(
9633 "/[^a-z]/.test(cons);"
9634 "/[^a-z]/.test(slice);"
9635 "/[^a-z]/.test(slice_on_cons);");
9636 const char* expected_cons =
9637 "Now is the time for all good men to come to the aid of the party"
9638 "Now is the time for all good men to come to the aid of the party";
9639 const char* expected_slice =
9640 "ow is the time for all good men to come to the aid of the part";
9641 const char* expected_slice_on_cons =
9642 "ow is the time for all good men to come to the aid of the party"
9643 "Now is the time for all good men to come to the aid of the part";
9644 CHECK_EQ(String::New(expected_cons),
9645 env->Global()->Get(v8_str("cons")));
9646 CHECK_EQ(String::New(expected_slice),
9647 env->Global()->Get(v8_str("slice")));
9648 CHECK_EQ(String::New(expected_slice_on_cons),
9649 env->Global()->Get(v8_str("slice_on_cons")));
9650 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009651 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009652}
9653
9654
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009655TEST(CompileExternalTwoByteSource) {
9656 v8::HandleScope scope;
9657 LocalContext context;
9658
9659 // This is a very short list of sources, which currently is to check for a
9660 // regression caused by r2703.
9661 const char* ascii_sources[] = {
9662 "0.5",
9663 "-0.5", // This mainly testes PushBack in the Scanner.
9664 "--0.5", // This mainly testes PushBack in the Scanner.
9665 NULL
9666 };
9667
9668 // Compile the sources as external two byte strings.
9669 for (int i = 0; ascii_sources[i] != NULL; i++) {
9670 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9671 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009672 i::Vector<const uint16_t>(two_byte_string,
9673 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009674 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9675 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009676 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009677 }
9678}
9679
9680
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009681class RegExpStringModificationTest {
9682 public:
9683 RegExpStringModificationTest()
9684 : block_(i::OS::CreateSemaphore(0)),
9685 morphs_(0),
9686 morphs_during_regexp_(0),
9687 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9688 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9689 ~RegExpStringModificationTest() { delete block_; }
9690 void RunTest() {
9691 regexp_success_ = false;
9692 morph_success_ = false;
9693
9694 // Initialize the contents of two_byte_content_ to be a uc16 representation
9695 // of "aaaaaaaaaaaaaab".
9696 for (int i = 0; i < 14; i++) {
9697 two_byte_content_[i] = 'a';
9698 }
9699 two_byte_content_[14] = 'b';
9700
9701 // Create the input string for the regexp - the one we are going to change
9702 // properties of.
9703 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9704
9705 // Inject the input as a global variable.
9706 i::Handle<i::String> input_name =
9707 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009708 i::Top::global_context()->global()->SetProperty(*input_name,
9709 *input_,
9710 NONE)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009711
9712
9713 MorphThread morph_thread(this);
9714 morph_thread.Start();
9715 v8::Locker::StartPreemption(1);
9716 LongRunningRegExp();
9717 {
9718 v8::Unlocker unlock;
9719 morph_thread.Join();
9720 }
9721 v8::Locker::StopPreemption();
9722 CHECK(regexp_success_);
9723 CHECK(morph_success_);
9724 }
9725 private:
9726
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009727 // Number of string modifications required.
9728 static const int kRequiredModifications = 5;
9729 static const int kMaxModifications = 100;
9730
9731 class MorphThread : public i::Thread {
9732 public:
9733 explicit MorphThread(RegExpStringModificationTest* test)
9734 : test_(test) {}
9735 virtual void Run() {
9736 test_->MorphString();
9737 }
9738 private:
9739 RegExpStringModificationTest* test_;
9740 };
9741
9742 void MorphString() {
9743 block_->Wait();
9744 while (morphs_during_regexp_ < kRequiredModifications &&
9745 morphs_ < kMaxModifications) {
9746 {
9747 v8::Locker lock;
9748 // Swap string between ascii and two-byte representation.
9749 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +00009750 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009751 morphs_++;
9752 }
9753 i::OS::Sleep(1);
9754 }
9755 morph_success_ = true;
9756 }
9757
9758 void LongRunningRegExp() {
9759 block_->Signal(); // Enable morphing thread on next preemption.
9760 while (morphs_during_regexp_ < kRequiredModifications &&
9761 morphs_ < kMaxModifications) {
9762 int morphs_before = morphs_;
9763 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009764 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009765 // Match 15-30 "a"'s against 14 and a "b".
9766 const char* c_source =
9767 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9768 ".exec(input) === null";
9769 Local<String> source = String::New(c_source);
9770 Local<Script> script = Script::Compile(source);
9771 Local<Value> result = script->Run();
9772 CHECK(result->IsTrue());
9773 }
9774 int morphs_after = morphs_;
9775 morphs_during_regexp_ += morphs_after - morphs_before;
9776 }
9777 regexp_success_ = true;
9778 }
9779
9780 i::uc16 two_byte_content_[15];
9781 i::Semaphore* block_;
9782 int morphs_;
9783 int morphs_during_regexp_;
9784 bool regexp_success_;
9785 bool morph_success_;
9786 i::Handle<i::String> input_;
9787 AsciiVectorResource ascii_resource_;
9788 UC16VectorResource uc16_resource_;
9789};
9790
9791
9792// Test that a regular expression execution can be interrupted and
9793// the string changed without failing.
9794TEST(RegExpStringModification) {
9795 v8::Locker lock;
9796 v8::V8::Initialize();
9797 v8::HandleScope scope;
9798 Local<Context> local_env;
9799 {
9800 LocalContext env;
9801 local_env = env.local();
9802 }
9803
9804 // Local context should still be live.
9805 CHECK(!local_env.IsEmpty());
9806 local_env->Enter();
9807
9808 // Should complete without problems.
9809 RegExpStringModificationTest().RunTest();
9810
9811 local_env->Exit();
9812}
9813
9814
9815// Test that we can set a property on the global object even if there
9816// is a read-only property in the prototype chain.
9817TEST(ReadOnlyPropertyInGlobalProto) {
9818 v8::HandleScope scope;
9819 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9820 LocalContext context(0, templ);
9821 v8::Handle<v8::Object> global = context->Global();
9822 v8::Handle<v8::Object> global_proto =
9823 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9824 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9825 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9826 // Check without 'eval' or 'with'.
9827 v8::Handle<v8::Value> res =
9828 CompileRun("function f() { x = 42; return x; }; f()");
9829 // Check with 'eval'.
9830 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9831 CHECK_EQ(v8::Integer::New(42), res);
9832 // Check with 'with'.
9833 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9834 CHECK_EQ(v8::Integer::New(42), res);
9835}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009836
9837static int force_set_set_count = 0;
9838static int force_set_get_count = 0;
9839bool pass_on_get = false;
9840
9841static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9842 const v8::AccessorInfo& info) {
9843 force_set_get_count++;
9844 if (pass_on_get) {
9845 return v8::Handle<v8::Value>();
9846 } else {
9847 return v8::Int32::New(3);
9848 }
9849}
9850
9851static void ForceSetSetter(v8::Local<v8::String> name,
9852 v8::Local<v8::Value> value,
9853 const v8::AccessorInfo& info) {
9854 force_set_set_count++;
9855}
9856
9857static v8::Handle<v8::Value> ForceSetInterceptSetter(
9858 v8::Local<v8::String> name,
9859 v8::Local<v8::Value> value,
9860 const v8::AccessorInfo& info) {
9861 force_set_set_count++;
9862 return v8::Undefined();
9863}
9864
9865TEST(ForceSet) {
9866 force_set_get_count = 0;
9867 force_set_set_count = 0;
9868 pass_on_get = false;
9869
9870 v8::HandleScope scope;
9871 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9872 v8::Handle<v8::String> access_property = v8::String::New("a");
9873 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9874 LocalContext context(NULL, templ);
9875 v8::Handle<v8::Object> global = context->Global();
9876
9877 // Ordinary properties
9878 v8::Handle<v8::String> simple_property = v8::String::New("p");
9879 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9880 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9881 // This should fail because the property is read-only
9882 global->Set(simple_property, v8::Int32::New(5));
9883 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9884 // This should succeed even though the property is read-only
9885 global->ForceSet(simple_property, v8::Int32::New(6));
9886 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9887
9888 // Accessors
9889 CHECK_EQ(0, force_set_set_count);
9890 CHECK_EQ(0, force_set_get_count);
9891 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9892 // CHECK_EQ the property shouldn't override it, just call the setter
9893 // which in this case does nothing.
9894 global->Set(access_property, v8::Int32::New(7));
9895 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9896 CHECK_EQ(1, force_set_set_count);
9897 CHECK_EQ(2, force_set_get_count);
9898 // Forcing the property to be set should override the accessor without
9899 // calling it
9900 global->ForceSet(access_property, v8::Int32::New(8));
9901 CHECK_EQ(8, global->Get(access_property)->Int32Value());
9902 CHECK_EQ(1, force_set_set_count);
9903 CHECK_EQ(2, force_set_get_count);
9904}
9905
9906TEST(ForceSetWithInterceptor) {
9907 force_set_get_count = 0;
9908 force_set_set_count = 0;
9909 pass_on_get = false;
9910
9911 v8::HandleScope scope;
9912 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9913 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9914 LocalContext context(NULL, templ);
9915 v8::Handle<v8::Object> global = context->Global();
9916
9917 v8::Handle<v8::String> some_property = v8::String::New("a");
9918 CHECK_EQ(0, force_set_set_count);
9919 CHECK_EQ(0, force_set_get_count);
9920 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9921 // Setting the property shouldn't override it, just call the setter
9922 // which in this case does nothing.
9923 global->Set(some_property, v8::Int32::New(7));
9924 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9925 CHECK_EQ(1, force_set_set_count);
9926 CHECK_EQ(2, force_set_get_count);
9927 // Getting the property when the interceptor returns an empty handle
9928 // should yield undefined, since the property isn't present on the
9929 // object itself yet.
9930 pass_on_get = true;
9931 CHECK(global->Get(some_property)->IsUndefined());
9932 CHECK_EQ(1, force_set_set_count);
9933 CHECK_EQ(3, force_set_get_count);
9934 // Forcing the property to be set should cause the value to be
9935 // set locally without calling the interceptor.
9936 global->ForceSet(some_property, v8::Int32::New(8));
9937 CHECK_EQ(8, global->Get(some_property)->Int32Value());
9938 CHECK_EQ(1, force_set_set_count);
9939 CHECK_EQ(4, force_set_get_count);
9940 // Reenabling the interceptor should cause it to take precedence over
9941 // the property
9942 pass_on_get = false;
9943 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9944 CHECK_EQ(1, force_set_set_count);
9945 CHECK_EQ(5, force_set_get_count);
9946 // The interceptor should also work for other properties
9947 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9948 CHECK_EQ(1, force_set_set_count);
9949 CHECK_EQ(6, force_set_get_count);
9950}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00009951
9952
ager@chromium.orge2902be2009-06-08 12:21:35 +00009953THREADED_TEST(ForceDelete) {
9954 v8::HandleScope scope;
9955 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9956 LocalContext context(NULL, templ);
9957 v8::Handle<v8::Object> global = context->Global();
9958
9959 // Ordinary properties
9960 v8::Handle<v8::String> simple_property = v8::String::New("p");
9961 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9962 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9963 // This should fail because the property is dont-delete.
9964 CHECK(!global->Delete(simple_property));
9965 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9966 // This should succeed even though the property is dont-delete.
9967 CHECK(global->ForceDelete(simple_property));
9968 CHECK(global->Get(simple_property)->IsUndefined());
9969}
9970
9971
9972static int force_delete_interceptor_count = 0;
9973static bool pass_on_delete = false;
9974
9975
9976static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9977 v8::Local<v8::String> name,
9978 const v8::AccessorInfo& info) {
9979 force_delete_interceptor_count++;
9980 if (pass_on_delete) {
9981 return v8::Handle<v8::Boolean>();
9982 } else {
9983 return v8::True();
9984 }
9985}
9986
9987
9988THREADED_TEST(ForceDeleteWithInterceptor) {
9989 force_delete_interceptor_count = 0;
9990 pass_on_delete = false;
9991
9992 v8::HandleScope scope;
9993 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9994 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9995 LocalContext context(NULL, templ);
9996 v8::Handle<v8::Object> global = context->Global();
9997
9998 v8::Handle<v8::String> some_property = v8::String::New("a");
9999 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
10000
10001 // Deleting a property should get intercepted and nothing should
10002 // happen.
10003 CHECK_EQ(0, force_delete_interceptor_count);
10004 CHECK(global->Delete(some_property));
10005 CHECK_EQ(1, force_delete_interceptor_count);
10006 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10007 // Deleting the property when the interceptor returns an empty
10008 // handle should not delete the property since it is DontDelete.
10009 pass_on_delete = true;
10010 CHECK(!global->Delete(some_property));
10011 CHECK_EQ(2, force_delete_interceptor_count);
10012 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10013 // Forcing the property to be deleted should delete the value
10014 // without calling the interceptor.
10015 CHECK(global->ForceDelete(some_property));
10016 CHECK(global->Get(some_property)->IsUndefined());
10017 CHECK_EQ(2, force_delete_interceptor_count);
10018}
10019
10020
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010021// Make sure that forcing a delete invalidates any IC stubs, so we
10022// don't read the hole value.
10023THREADED_TEST(ForceDeleteIC) {
10024 v8::HandleScope scope;
10025 LocalContext context;
10026 // Create a DontDelete variable on the global object.
10027 CompileRun("this.__proto__ = { foo: 'horse' };"
10028 "var foo = 'fish';"
10029 "function f() { return foo.length; }");
10030 // Initialize the IC for foo in f.
10031 CompileRun("for (var i = 0; i < 4; i++) f();");
10032 // Make sure the value of foo is correct before the deletion.
10033 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10034 // Force the deletion of foo.
10035 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10036 // Make sure the value for foo is read from the prototype, and that
10037 // we don't get in trouble with reading the deleted cell value
10038 // sentinel.
10039 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10040}
10041
10042
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010043v8::Persistent<Context> calling_context0;
10044v8::Persistent<Context> calling_context1;
10045v8::Persistent<Context> calling_context2;
10046
10047
10048// Check that the call to the callback is initiated in
10049// calling_context2, the directly calling context is calling_context1
10050// and the callback itself is in calling_context0.
10051static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10052 ApiTestFuzzer::Fuzz();
10053 CHECK(Context::GetCurrent() == calling_context0);
10054 CHECK(Context::GetCalling() == calling_context1);
10055 CHECK(Context::GetEntered() == calling_context2);
10056 return v8::Integer::New(42);
10057}
10058
10059
10060THREADED_TEST(GetCallingContext) {
10061 v8::HandleScope scope;
10062
10063 calling_context0 = Context::New();
10064 calling_context1 = Context::New();
10065 calling_context2 = Context::New();
10066
10067 // Allow cross-domain access.
10068 Local<String> token = v8_str("<security token>");
10069 calling_context0->SetSecurityToken(token);
10070 calling_context1->SetSecurityToken(token);
10071 calling_context2->SetSecurityToken(token);
10072
10073 // Create an object with a C++ callback in context0.
10074 calling_context0->Enter();
10075 Local<v8::FunctionTemplate> callback_templ =
10076 v8::FunctionTemplate::New(GetCallingContextCallback);
10077 calling_context0->Global()->Set(v8_str("callback"),
10078 callback_templ->GetFunction());
10079 calling_context0->Exit();
10080
10081 // Expose context0 in context1 and setup a function that calls the
10082 // callback function.
10083 calling_context1->Enter();
10084 calling_context1->Global()->Set(v8_str("context0"),
10085 calling_context0->Global());
10086 CompileRun("function f() { context0.callback() }");
10087 calling_context1->Exit();
10088
10089 // Expose context1 in context2 and call the callback function in
10090 // context0 indirectly through f in context1.
10091 calling_context2->Enter();
10092 calling_context2->Global()->Set(v8_str("context1"),
10093 calling_context1->Global());
10094 CompileRun("context1.f()");
10095 calling_context2->Exit();
10096
10097 // Dispose the contexts to allow them to be garbage collected.
10098 calling_context0.Dispose();
10099 calling_context1.Dispose();
10100 calling_context2.Dispose();
10101 calling_context0.Clear();
10102 calling_context1.Clear();
10103 calling_context2.Clear();
10104}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010105
10106
10107// Check that a variable declaration with no explicit initialization
10108// value does not shadow an existing property in the prototype chain.
10109//
10110// This is consistent with Firefox and Safari.
10111//
10112// See http://crbug.com/12548.
10113THREADED_TEST(InitGlobalVarInProtoChain) {
10114 v8::HandleScope scope;
10115 LocalContext context;
10116 // Introduce a variable in the prototype chain.
10117 CompileRun("__proto__.x = 42");
10118 v8::Handle<v8::Value> result = CompileRun("var x; x");
10119 CHECK(!result->IsUndefined());
10120 CHECK_EQ(42, result->Int32Value());
10121}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010122
10123
10124// Regression test for issue 398.
10125// If a function is added to an object, creating a constant function
10126// field, and the result is cloned, replacing the constant function on the
10127// original should not affect the clone.
10128// See http://code.google.com/p/v8/issues/detail?id=398
10129THREADED_TEST(ReplaceConstantFunction) {
10130 v8::HandleScope scope;
10131 LocalContext context;
10132 v8::Handle<v8::Object> obj = v8::Object::New();
10133 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10134 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10135 obj->Set(foo_string, func_templ->GetFunction());
10136 v8::Handle<v8::Object> obj_clone = obj->Clone();
10137 obj_clone->Set(foo_string, v8::String::New("Hello"));
10138 CHECK(!obj->Get(foo_string)->IsUndefined());
10139}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010140
10141
10142// Regression test for http://crbug.com/16276.
10143THREADED_TEST(Regress16276) {
10144 v8::HandleScope scope;
10145 LocalContext context;
10146 // Force the IC in f to be a dictionary load IC.
10147 CompileRun("function f(obj) { return obj.x; }\n"
10148 "var obj = { x: { foo: 42 }, y: 87 };\n"
10149 "var x = obj.x;\n"
10150 "delete obj.y;\n"
10151 "for (var i = 0; i < 5; i++) f(obj);");
10152 // Detach the global object to make 'this' refer directly to the
10153 // global object (not the proxy), and make sure that the dictionary
10154 // load IC doesn't mess up loading directly from the global object.
10155 context->DetachGlobal();
10156 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10157}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010158
10159
10160THREADED_TEST(PixelArray) {
10161 v8::HandleScope scope;
10162 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010163 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010164 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10165 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10166 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010167 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010168 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010169 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010170 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010171 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010172 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010173 CHECK_EQ(i % 256, pixels->get(i));
10174 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010175 }
10176
10177 v8::Handle<v8::Object> obj = v8::Object::New();
10178 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10179 // Set the elements to be the pixels.
10180 // jsobj->set_elements(*pixels);
10181 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010182 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010183 obj->Set(v8_str("field"), v8::Int32::New(1503));
10184 context->Global()->Set(v8_str("pixels"), obj);
10185 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10186 CHECK_EQ(1503, result->Int32Value());
10187 result = CompileRun("pixels[1]");
10188 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010189
10190 result = CompileRun("var sum = 0;"
10191 "for (var i = 0; i < 8; i++) {"
10192 " sum += pixels[i] = pixels[i] = -i;"
10193 "}"
10194 "sum;");
10195 CHECK_EQ(-28, result->Int32Value());
10196
10197 result = CompileRun("var sum = 0;"
10198 "for (var i = 0; i < 8; i++) {"
10199 " sum += pixels[i] = pixels[i] = 0;"
10200 "}"
10201 "sum;");
10202 CHECK_EQ(0, result->Int32Value());
10203
10204 result = CompileRun("var sum = 0;"
10205 "for (var i = 0; i < 8; i++) {"
10206 " sum += pixels[i] = pixels[i] = 255;"
10207 "}"
10208 "sum;");
10209 CHECK_EQ(8 * 255, result->Int32Value());
10210
10211 result = CompileRun("var sum = 0;"
10212 "for (var i = 0; i < 8; i++) {"
10213 " sum += pixels[i] = pixels[i] = 256 + i;"
10214 "}"
10215 "sum;");
10216 CHECK_EQ(2076, result->Int32Value());
10217
10218 result = CompileRun("var sum = 0;"
10219 "for (var i = 0; i < 8; i++) {"
10220 " sum += pixels[i] = pixels[i] = i;"
10221 "}"
10222 "sum;");
10223 CHECK_EQ(28, result->Int32Value());
10224
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010225 result = CompileRun("var sum = 0;"
10226 "for (var i = 0; i < 8; i++) {"
10227 " sum += pixels[i];"
10228 "}"
10229 "sum;");
10230 CHECK_EQ(28, result->Int32Value());
10231
10232 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10233 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010234 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010235 *value.location() = i::Smi::FromInt(256);
10236 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010237 CHECK_EQ(255,
10238 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010239 *value.location() = i::Smi::FromInt(-1);
10240 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010241 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010242
10243 result = CompileRun("for (var i = 0; i < 8; i++) {"
10244 " pixels[i] = (i * 65) - 109;"
10245 "}"
10246 "pixels[1] + pixels[6];");
10247 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010248 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10249 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10250 CHECK_EQ(21,
10251 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10252 CHECK_EQ(86,
10253 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10254 CHECK_EQ(151,
10255 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10256 CHECK_EQ(216,
10257 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10258 CHECK_EQ(255,
10259 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10260 CHECK_EQ(255,
10261 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010262 result = CompileRun("var sum = 0;"
10263 "for (var i = 0; i < 8; i++) {"
10264 " sum += pixels[i];"
10265 "}"
10266 "sum;");
10267 CHECK_EQ(984, result->Int32Value());
10268
10269 result = CompileRun("for (var i = 0; i < 8; i++) {"
10270 " pixels[i] = (i * 1.1);"
10271 "}"
10272 "pixels[1] + pixels[6];");
10273 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010274 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10275 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10276 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10277 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10278 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10279 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10280 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10281 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010282
10283 result = CompileRun("for (var i = 0; i < 8; i++) {"
10284 " pixels[7] = undefined;"
10285 "}"
10286 "pixels[7];");
10287 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010288 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010289
10290 result = CompileRun("for (var i = 0; i < 8; i++) {"
10291 " pixels[6] = '2.3';"
10292 "}"
10293 "pixels[6];");
10294 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010295 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010296
10297 result = CompileRun("for (var i = 0; i < 8; i++) {"
10298 " pixels[5] = NaN;"
10299 "}"
10300 "pixels[5];");
10301 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010302 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010303
10304 result = CompileRun("for (var i = 0; i < 8; i++) {"
10305 " pixels[8] = Infinity;"
10306 "}"
10307 "pixels[8];");
10308 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010309 CHECK_EQ(255,
10310 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010311
10312 result = CompileRun("for (var i = 0; i < 8; i++) {"
10313 " pixels[9] = -Infinity;"
10314 "}"
10315 "pixels[9];");
10316 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010317 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010318
10319 result = CompileRun("pixels[3] = 33;"
10320 "delete pixels[3];"
10321 "pixels[3];");
10322 CHECK_EQ(33, result->Int32Value());
10323
10324 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10325 "pixels[2] = 12; pixels[3] = 13;"
10326 "pixels.__defineGetter__('2',"
10327 "function() { return 120; });"
10328 "pixels[2];");
10329 CHECK_EQ(12, result->Int32Value());
10330
10331 result = CompileRun("var js_array = new Array(40);"
10332 "js_array[0] = 77;"
10333 "js_array;");
10334 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10335
10336 result = CompileRun("pixels[1] = 23;"
10337 "pixels.__proto__ = [];"
10338 "js_array.__proto__ = pixels;"
10339 "js_array.concat(pixels);");
10340 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10341 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10342
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010343 result = CompileRun("pixels[1] = 23;");
10344 CHECK_EQ(23, result->Int32Value());
10345
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010346 // Test for index greater than 255. Regression test for:
10347 // http://code.google.com/p/chromium/issues/detail?id=26337.
10348 result = CompileRun("pixels[256] = 255;");
10349 CHECK_EQ(255, result->Int32Value());
10350 result = CompileRun("var i = 0;"
10351 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10352 "i");
10353 CHECK_EQ(255, result->Int32Value());
10354
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010355 free(pixel_data);
10356}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010357
ager@chromium.org96c75b52009-08-26 09:13:16 +000010358
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010359THREADED_TEST(PixelArrayInfo) {
10360 v8::HandleScope scope;
10361 LocalContext context;
10362 for (int size = 0; size < 100; size += 10) {
10363 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10364 v8::Handle<v8::Object> obj = v8::Object::New();
10365 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10366 CHECK(obj->HasIndexedPropertiesInPixelData());
10367 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10368 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10369 free(pixel_data);
10370 }
10371}
10372
10373
10374static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10375 switch (array_type) {
10376 case v8::kExternalByteArray:
10377 case v8::kExternalUnsignedByteArray:
10378 return 1;
10379 break;
10380 case v8::kExternalShortArray:
10381 case v8::kExternalUnsignedShortArray:
10382 return 2;
10383 break;
10384 case v8::kExternalIntArray:
10385 case v8::kExternalUnsignedIntArray:
10386 case v8::kExternalFloatArray:
10387 return 4;
10388 break;
10389 default:
10390 UNREACHABLE();
10391 return -1;
10392 }
10393 UNREACHABLE();
10394 return -1;
10395}
10396
10397
ager@chromium.org3811b432009-10-28 14:53:37 +000010398template <class ExternalArrayClass, class ElementType>
10399static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10400 int64_t low,
10401 int64_t high) {
10402 v8::HandleScope scope;
10403 LocalContext context;
10404 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010405 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000010406 ElementType* array_data =
10407 static_cast<ElementType*>(malloc(kElementCount * element_size));
10408 i::Handle<ExternalArrayClass> array =
10409 i::Handle<ExternalArrayClass>::cast(
10410 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10411 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10412 for (int i = 0; i < kElementCount; i++) {
10413 array->set(i, static_cast<ElementType>(i));
10414 }
10415 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10416 for (int i = 0; i < kElementCount; i++) {
10417 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10418 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10419 }
10420
10421 v8::Handle<v8::Object> obj = v8::Object::New();
10422 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10423 // Set the elements to be the external array.
10424 obj->SetIndexedPropertiesToExternalArrayData(array_data,
10425 array_type,
10426 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010427 CHECK_EQ(
10428 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010429 obj->Set(v8_str("field"), v8::Int32::New(1503));
10430 context->Global()->Set(v8_str("ext_array"), obj);
10431 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10432 CHECK_EQ(1503, result->Int32Value());
10433 result = CompileRun("ext_array[1]");
10434 CHECK_EQ(1, result->Int32Value());
10435
10436 // Check pass through of assigned smis
10437 result = CompileRun("var sum = 0;"
10438 "for (var i = 0; i < 8; i++) {"
10439 " sum += ext_array[i] = ext_array[i] = -i;"
10440 "}"
10441 "sum;");
10442 CHECK_EQ(-28, result->Int32Value());
10443
10444 // Check assigned smis
10445 result = CompileRun("for (var i = 0; i < 8; i++) {"
10446 " ext_array[i] = i;"
10447 "}"
10448 "var sum = 0;"
10449 "for (var i = 0; i < 8; i++) {"
10450 " sum += ext_array[i];"
10451 "}"
10452 "sum;");
10453 CHECK_EQ(28, result->Int32Value());
10454
10455 // Check assigned smis in reverse order
10456 result = CompileRun("for (var i = 8; --i >= 0; ) {"
10457 " ext_array[i] = i;"
10458 "}"
10459 "var sum = 0;"
10460 "for (var i = 0; i < 8; i++) {"
10461 " sum += ext_array[i];"
10462 "}"
10463 "sum;");
10464 CHECK_EQ(28, result->Int32Value());
10465
10466 // Check pass through of assigned HeapNumbers
10467 result = CompileRun("var sum = 0;"
10468 "for (var i = 0; i < 16; i+=2) {"
10469 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10470 "}"
10471 "sum;");
10472 CHECK_EQ(-28, result->Int32Value());
10473
10474 // Check assigned HeapNumbers
10475 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10476 " ext_array[i] = (i * 0.5);"
10477 "}"
10478 "var sum = 0;"
10479 "for (var i = 0; i < 16; i+=2) {"
10480 " sum += ext_array[i];"
10481 "}"
10482 "sum;");
10483 CHECK_EQ(28, result->Int32Value());
10484
10485 // Check assigned HeapNumbers in reverse order
10486 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10487 " ext_array[i] = (i * 0.5);"
10488 "}"
10489 "var sum = 0;"
10490 "for (var i = 0; i < 16; i+=2) {"
10491 " sum += ext_array[i];"
10492 "}"
10493 "sum;");
10494 CHECK_EQ(28, result->Int32Value());
10495
10496 i::ScopedVector<char> test_buf(1024);
10497
10498 // Check legal boundary conditions.
10499 // The repeated loads and stores ensure the ICs are exercised.
10500 const char* boundary_program =
10501 "var res = 0;"
10502 "for (var i = 0; i < 16; i++) {"
10503 " ext_array[i] = %lld;"
10504 " if (i > 8) {"
10505 " res = ext_array[i];"
10506 " }"
10507 "}"
10508 "res;";
10509 i::OS::SNPrintF(test_buf,
10510 boundary_program,
10511 low);
10512 result = CompileRun(test_buf.start());
10513 CHECK_EQ(low, result->IntegerValue());
10514
10515 i::OS::SNPrintF(test_buf,
10516 boundary_program,
10517 high);
10518 result = CompileRun(test_buf.start());
10519 CHECK_EQ(high, result->IntegerValue());
10520
10521 // Check misprediction of type in IC.
10522 result = CompileRun("var tmp_array = ext_array;"
10523 "var sum = 0;"
10524 "for (var i = 0; i < 8; i++) {"
10525 " tmp_array[i] = i;"
10526 " sum += tmp_array[i];"
10527 " if (i == 4) {"
10528 " tmp_array = {};"
10529 " }"
10530 "}"
10531 "sum;");
10532 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10533 CHECK_EQ(28, result->Int32Value());
10534
10535 // Make sure out-of-range loads do not throw.
10536 i::OS::SNPrintF(test_buf,
10537 "var caught_exception = false;"
10538 "try {"
10539 " ext_array[%d];"
10540 "} catch (e) {"
10541 " caught_exception = true;"
10542 "}"
10543 "caught_exception;",
10544 kElementCount);
10545 result = CompileRun(test_buf.start());
10546 CHECK_EQ(false, result->BooleanValue());
10547
10548 // Make sure out-of-range stores do not throw.
10549 i::OS::SNPrintF(test_buf,
10550 "var caught_exception = false;"
10551 "try {"
10552 " ext_array[%d] = 1;"
10553 "} catch (e) {"
10554 " caught_exception = true;"
10555 "}"
10556 "caught_exception;",
10557 kElementCount);
10558 result = CompileRun(test_buf.start());
10559 CHECK_EQ(false, result->BooleanValue());
10560
10561 // Check other boundary conditions, values and operations.
10562 result = CompileRun("for (var i = 0; i < 8; i++) {"
10563 " ext_array[7] = undefined;"
10564 "}"
10565 "ext_array[7];");
10566 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010567 CHECK_EQ(
10568 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010569
10570 result = CompileRun("for (var i = 0; i < 8; i++) {"
10571 " ext_array[6] = '2.3';"
10572 "}"
10573 "ext_array[6];");
10574 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010575 CHECK_EQ(
10576 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010577
10578 if (array_type != v8::kExternalFloatArray) {
10579 // Though the specification doesn't state it, be explicit about
10580 // converting NaNs and +/-Infinity to zero.
10581 result = CompileRun("for (var i = 0; i < 8; i++) {"
10582 " ext_array[i] = 5;"
10583 "}"
10584 "for (var i = 0; i < 8; i++) {"
10585 " ext_array[i] = NaN;"
10586 "}"
10587 "ext_array[5];");
10588 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010589 CHECK_EQ(0,
10590 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010591
10592 result = CompileRun("for (var i = 0; i < 8; i++) {"
10593 " ext_array[i] = 5;"
10594 "}"
10595 "for (var i = 0; i < 8; i++) {"
10596 " ext_array[i] = Infinity;"
10597 "}"
10598 "ext_array[5];");
10599 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010600 CHECK_EQ(0,
10601 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010602
10603 result = CompileRun("for (var i = 0; i < 8; i++) {"
10604 " ext_array[i] = 5;"
10605 "}"
10606 "for (var i = 0; i < 8; i++) {"
10607 " ext_array[i] = -Infinity;"
10608 "}"
10609 "ext_array[5];");
10610 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010611 CHECK_EQ(0,
10612 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000010613
10614 // Check truncation behavior of integral arrays.
10615 const char* unsigned_data =
10616 "var source_data = [0.6, 10.6];"
10617 "var expected_results = [0, 10];";
10618 const char* signed_data =
10619 "var source_data = [0.6, 10.6, -0.6, -10.6];"
10620 "var expected_results = [0, 10, 0, -10];";
10621 bool is_unsigned =
10622 (array_type == v8::kExternalUnsignedByteArray ||
10623 array_type == v8::kExternalUnsignedShortArray ||
10624 array_type == v8::kExternalUnsignedIntArray);
10625
10626 i::OS::SNPrintF(test_buf,
10627 "%s"
10628 "var all_passed = true;"
10629 "for (var i = 0; i < source_data.length; i++) {"
10630 " for (var j = 0; j < 8; j++) {"
10631 " ext_array[j] = source_data[i];"
10632 " }"
10633 " all_passed = all_passed &&"
10634 " (ext_array[5] == expected_results[i]);"
10635 "}"
10636 "all_passed;",
10637 (is_unsigned ? unsigned_data : signed_data));
10638 result = CompileRun(test_buf.start());
10639 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000010640 }
10641
10642 result = CompileRun("ext_array[3] = 33;"
10643 "delete ext_array[3];"
10644 "ext_array[3];");
10645 CHECK_EQ(33, result->Int32Value());
10646
10647 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10648 "ext_array[2] = 12; ext_array[3] = 13;"
10649 "ext_array.__defineGetter__('2',"
10650 "function() { return 120; });"
10651 "ext_array[2];");
10652 CHECK_EQ(12, result->Int32Value());
10653
10654 result = CompileRun("var js_array = new Array(40);"
10655 "js_array[0] = 77;"
10656 "js_array;");
10657 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10658
10659 result = CompileRun("ext_array[1] = 23;"
10660 "ext_array.__proto__ = [];"
10661 "js_array.__proto__ = ext_array;"
10662 "js_array.concat(ext_array);");
10663 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10664 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10665
10666 result = CompileRun("ext_array[1] = 23;");
10667 CHECK_EQ(23, result->Int32Value());
10668
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010669 // Test more complex manipulations which cause eax to contain values
10670 // that won't be completely overwritten by loads from the arrays.
10671 // This catches bugs in the instructions used for the KeyedLoadIC
10672 // for byte and word types.
10673 {
10674 const int kXSize = 300;
10675 const int kYSize = 300;
10676 const int kLargeElementCount = kXSize * kYSize * 4;
10677 ElementType* large_array_data =
10678 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10679 i::Handle<ExternalArrayClass> large_array =
10680 i::Handle<ExternalArrayClass>::cast(
10681 i::Factory::NewExternalArray(kLargeElementCount,
10682 array_type,
10683 array_data));
10684 v8::Handle<v8::Object> large_obj = v8::Object::New();
10685 // Set the elements to be the external array.
10686 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10687 array_type,
10688 kLargeElementCount);
10689 context->Global()->Set(v8_str("large_array"), large_obj);
10690 // Initialize contents of a few rows.
10691 for (int x = 0; x < 300; x++) {
10692 int row = 0;
10693 int offset = row * 300 * 4;
10694 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10695 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10696 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10697 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10698 row = 150;
10699 offset = row * 300 * 4;
10700 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10701 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10702 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10703 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10704 row = 298;
10705 offset = row * 300 * 4;
10706 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10707 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10708 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10709 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10710 }
10711 // The goal of the code below is to make "offset" large enough
10712 // that the computation of the index (which goes into eax) has
10713 // high bits set which will not be overwritten by a byte or short
10714 // load.
10715 result = CompileRun("var failed = false;"
10716 "var offset = 0;"
10717 "for (var i = 0; i < 300; i++) {"
10718 " if (large_array[4 * i] != 127 ||"
10719 " large_array[4 * i + 1] != 0 ||"
10720 " large_array[4 * i + 2] != 0 ||"
10721 " large_array[4 * i + 3] != 127) {"
10722 " failed = true;"
10723 " }"
10724 "}"
10725 "offset = 150 * 300 * 4;"
10726 "for (var i = 0; i < 300; i++) {"
10727 " if (large_array[offset + 4 * i] != 127 ||"
10728 " large_array[offset + 4 * i + 1] != 0 ||"
10729 " large_array[offset + 4 * i + 2] != 0 ||"
10730 " large_array[offset + 4 * i + 3] != 127) {"
10731 " failed = true;"
10732 " }"
10733 "}"
10734 "offset = 298 * 300 * 4;"
10735 "for (var i = 0; i < 300; i++) {"
10736 " if (large_array[offset + 4 * i] != 127 ||"
10737 " large_array[offset + 4 * i + 1] != 0 ||"
10738 " large_array[offset + 4 * i + 2] != 0 ||"
10739 " large_array[offset + 4 * i + 3] != 127) {"
10740 " failed = true;"
10741 " }"
10742 "}"
10743 "!failed;");
10744 CHECK_EQ(true, result->BooleanValue());
10745 free(large_array_data);
10746 }
10747
ager@chromium.org3811b432009-10-28 14:53:37 +000010748 free(array_data);
10749}
10750
10751
10752THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010753 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010754 v8::kExternalByteArray,
10755 -128,
10756 127);
10757}
10758
10759
10760THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010761 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010762 v8::kExternalUnsignedByteArray,
10763 0,
10764 255);
10765}
10766
10767
10768THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010769 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010770 v8::kExternalShortArray,
10771 -32768,
10772 32767);
10773}
10774
10775
10776THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010777 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010778 v8::kExternalUnsignedShortArray,
10779 0,
10780 65535);
10781}
10782
10783
10784THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010785 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010786 v8::kExternalIntArray,
10787 INT_MIN, // -2147483648
10788 INT_MAX); // 2147483647
10789}
10790
10791
10792THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010793 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010794 v8::kExternalUnsignedIntArray,
10795 0,
10796 UINT_MAX); // 4294967295
10797}
10798
10799
10800THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010801 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010802 v8::kExternalFloatArray,
10803 -500,
10804 500);
10805}
10806
10807
10808THREADED_TEST(ExternalArrays) {
10809 TestExternalByteArray();
10810 TestExternalUnsignedByteArray();
10811 TestExternalShortArray();
10812 TestExternalUnsignedShortArray();
10813 TestExternalIntArray();
10814 TestExternalUnsignedIntArray();
10815 TestExternalFloatArray();
10816}
10817
10818
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010819void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10820 v8::HandleScope scope;
10821 LocalContext context;
10822 for (int size = 0; size < 100; size += 10) {
10823 int element_size = ExternalArrayElementSize(array_type);
10824 void* external_data = malloc(size * element_size);
10825 v8::Handle<v8::Object> obj = v8::Object::New();
10826 obj->SetIndexedPropertiesToExternalArrayData(
10827 external_data, array_type, size);
10828 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10829 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10830 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10831 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10832 free(external_data);
10833 }
10834}
10835
10836
10837THREADED_TEST(ExternalArrayInfo) {
10838 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10839 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10840 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10841 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10842 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10843 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10844 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10845}
10846
10847
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010848THREADED_TEST(ScriptContextDependence) {
10849 v8::HandleScope scope;
10850 LocalContext c1;
10851 const char *source = "foo";
10852 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10853 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10854 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10855 CHECK_EQ(dep->Run()->Int32Value(), 100);
10856 CHECK_EQ(indep->Run()->Int32Value(), 100);
10857 LocalContext c2;
10858 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10859 CHECK_EQ(dep->Run()->Int32Value(), 100);
10860 CHECK_EQ(indep->Run()->Int32Value(), 101);
10861}
10862
ager@chromium.org96c75b52009-08-26 09:13:16 +000010863
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010864THREADED_TEST(StackTrace) {
10865 v8::HandleScope scope;
10866 LocalContext context;
10867 v8::TryCatch try_catch;
10868 const char *source = "function foo() { FAIL.FAIL; }; foo();";
10869 v8::Handle<v8::String> src = v8::String::New(source);
10870 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10871 v8::Script::New(src, origin)->Run();
10872 CHECK(try_catch.HasCaught());
10873 v8::String::Utf8Value stack(try_catch.StackTrace());
10874 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10875}
ager@chromium.org96c75b52009-08-26 09:13:16 +000010876
10877
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010878// Checks that a StackFrame has certain expected values.
10879void checkStackFrame(const char* expected_script_name,
10880 const char* expected_func_name, int expected_line_number,
10881 int expected_column, bool is_eval, bool is_constructor,
10882 v8::Handle<v8::StackFrame> frame) {
10883 v8::HandleScope scope;
10884 v8::String::Utf8Value func_name(frame->GetFunctionName());
10885 v8::String::Utf8Value script_name(frame->GetScriptName());
10886 if (*script_name == NULL) {
10887 // The situation where there is no associated script, like for evals.
10888 CHECK(expected_script_name == NULL);
10889 } else {
10890 CHECK(strstr(*script_name, expected_script_name) != NULL);
10891 }
10892 CHECK(strstr(*func_name, expected_func_name) != NULL);
10893 CHECK_EQ(expected_line_number, frame->GetLineNumber());
10894 CHECK_EQ(expected_column, frame->GetColumn());
10895 CHECK_EQ(is_eval, frame->IsEval());
10896 CHECK_EQ(is_constructor, frame->IsConstructor());
10897}
10898
10899
10900v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10901 v8::HandleScope scope;
10902 const char* origin = "capture-stack-trace-test";
10903 const int kOverviewTest = 1;
10904 const int kDetailedTest = 2;
10905
10906 ASSERT(args.Length() == 1);
10907
10908 int testGroup = args[0]->Int32Value();
10909 if (testGroup == kOverviewTest) {
10910 v8::Handle<v8::StackTrace> stackTrace =
10911 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10912 CHECK_EQ(4, stackTrace->GetFrameCount());
10913 checkStackFrame(origin, "bar", 2, 10, false, false,
10914 stackTrace->GetFrame(0));
10915 checkStackFrame(origin, "foo", 6, 3, false, false,
10916 stackTrace->GetFrame(1));
10917 checkStackFrame(NULL, "", 1, 1, false, false,
10918 stackTrace->GetFrame(2));
10919 // The last frame is an anonymous function that has the initial call.
10920 checkStackFrame(origin, "", 8, 7, false, false,
10921 stackTrace->GetFrame(3));
10922
10923 CHECK(stackTrace->AsArray()->IsArray());
10924 } else if (testGroup == kDetailedTest) {
10925 v8::Handle<v8::StackTrace> stackTrace =
10926 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10927 CHECK_EQ(4, stackTrace->GetFrameCount());
10928 checkStackFrame(origin, "bat", 4, 22, false, false,
10929 stackTrace->GetFrame(0));
10930 checkStackFrame(origin, "baz", 8, 3, false, true,
10931 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010932#ifdef ENABLE_DEBUGGER_SUPPORT
10933 bool is_eval = true;
10934#else // ENABLE_DEBUGGER_SUPPORT
10935 bool is_eval = false;
10936#endif // ENABLE_DEBUGGER_SUPPORT
10937
10938 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010939 stackTrace->GetFrame(2));
10940 // The last frame is an anonymous function that has the initial call to foo.
10941 checkStackFrame(origin, "", 10, 1, false, false,
10942 stackTrace->GetFrame(3));
10943
10944 CHECK(stackTrace->AsArray()->IsArray());
10945 }
10946 return v8::Undefined();
10947}
10948
10949
10950// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010951// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10952// THREADED_TEST(CaptureStackTrace) {
10953TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010954 v8::HandleScope scope;
10955 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10956 Local<ObjectTemplate> templ = ObjectTemplate::New();
10957 templ->Set(v8_str("AnalyzeStackInNativeCode"),
10958 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10959 LocalContext context(0, templ);
10960
10961 // Test getting OVERVIEW information. Should ignore information that is not
10962 // script name, function name, line number, and column offset.
10963 const char *overview_source =
10964 "function bar() {\n"
10965 " var y; AnalyzeStackInNativeCode(1);\n"
10966 "}\n"
10967 "function foo() {\n"
10968 "\n"
10969 " bar();\n"
10970 "}\n"
10971 "var x;eval('new foo();');";
10972 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10973 v8::Handle<Value> overview_result =
10974 v8::Script::New(overview_src, origin)->Run();
10975 ASSERT(!overview_result.IsEmpty());
10976 ASSERT(overview_result->IsObject());
10977
10978 // Test getting DETAILED information.
10979 const char *detailed_source =
10980 "function bat() {AnalyzeStackInNativeCode(2);\n"
10981 "}\n"
10982 "\n"
10983 "function baz() {\n"
10984 " bat();\n"
10985 "}\n"
10986 "eval('new baz();');";
10987 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10988 // Make the script using a non-zero line and column offset.
10989 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10990 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10991 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10992 v8::Handle<v8::Script> detailed_script(
10993 v8::Script::New(detailed_src, &detailed_origin));
10994 v8::Handle<Value> detailed_result = detailed_script->Run();
10995 ASSERT(!detailed_result.IsEmpty());
10996 ASSERT(detailed_result->IsObject());
10997}
10998
10999
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011000static void StackTraceForUncaughtExceptionListener(
11001 v8::Handle<v8::Message> message,
11002 v8::Handle<Value>) {
11003 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
11004 CHECK_EQ(2, stack_trace->GetFrameCount());
11005 checkStackFrame("origin", "foo", 2, 3, false, false,
11006 stack_trace->GetFrame(0));
11007 checkStackFrame("origin", "bar", 5, 3, false, false,
11008 stack_trace->GetFrame(1));
11009}
11010
11011TEST(CaptureStackTraceForUncaughtException) {
11012 report_count = 0;
11013 v8::HandleScope scope;
11014 LocalContext env;
11015 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
11016 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
11017
11018 Script::Compile(v8_str("function foo() {\n"
11019 " throw 1;\n"
11020 "};\n"
11021 "function bar() {\n"
11022 " foo();\n"
11023 "};"),
11024 v8_str("origin"))->Run();
11025 v8::Local<v8::Object> global = env->Global();
11026 Local<Value> trouble = global->Get(v8_str("bar"));
11027 CHECK(trouble->IsFunction());
11028 Function::Cast(*trouble)->Call(global, 0, NULL);
11029 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
11030 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
11031}
11032
11033
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000011034v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
11035 v8::HandleScope scope;
11036 v8::Handle<v8::StackTrace> stackTrace =
11037 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
11038 CHECK_EQ(5, stackTrace->GetFrameCount());
11039 v8::Handle<v8::String> url = v8_str("eval_url");
11040 for (int i = 0; i < 3; i++) {
11041 v8::Handle<v8::String> name =
11042 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
11043 CHECK(!name.IsEmpty());
11044 CHECK_EQ(url, name);
11045 }
11046 return v8::Undefined();
11047}
11048
11049
11050TEST(SourceURLInStackTrace) {
11051 v8::HandleScope scope;
11052 Local<ObjectTemplate> templ = ObjectTemplate::New();
11053 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11054 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11055 LocalContext context(0, templ);
11056
11057 const char *source =
11058 "function outer() {\n"
11059 "function bar() {\n"
11060 " AnalyzeStackOfEvalWithSourceURL();\n"
11061 "}\n"
11062 "function foo() {\n"
11063 "\n"
11064 " bar();\n"
11065 "}\n"
11066 "foo();\n"
11067 "}\n"
11068 "eval('(' + outer +')()//@ sourceURL=eval_url');";
11069 CHECK(CompileRun(source)->IsUndefined());
11070}
11071
11072
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011073// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000011074THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011075 bool rv = false;
11076 for (int i = 0; i < 100; i++) {
11077 rv = v8::V8::IdleNotification();
11078 if (rv)
11079 break;
11080 }
11081 CHECK(rv == true);
11082}
11083
11084
11085static uint32_t* stack_limit;
11086
11087static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000011088 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011089 return v8::Undefined();
11090}
11091
11092
11093// Uses the address of a local variable to determine the stack top now.
11094// Given a size, returns an address that is that far from the current
11095// top of stack.
11096static uint32_t* ComputeStackLimit(uint32_t size) {
11097 uint32_t* answer = &size - (size / sizeof(size));
11098 // If the size is very large and the stack is very near the bottom of
11099 // memory then the calculation above may wrap around and give an address
11100 // that is above the (downwards-growing) stack. In that case we return
11101 // a very low address.
11102 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11103 return answer;
11104}
11105
11106
11107TEST(SetResourceConstraints) {
11108 static const int K = 1024;
11109 uint32_t* set_limit = ComputeStackLimit(128 * K);
11110
11111 // Set stack limit.
11112 v8::ResourceConstraints constraints;
11113 constraints.set_stack_limit(set_limit);
11114 CHECK(v8::SetResourceConstraints(&constraints));
11115
11116 // Execute a script.
11117 v8::HandleScope scope;
11118 LocalContext env;
11119 Local<v8::FunctionTemplate> fun_templ =
11120 v8::FunctionTemplate::New(GetStackLimitCallback);
11121 Local<Function> fun = fun_templ->GetFunction();
11122 env->Global()->Set(v8_str("get_stack_limit"), fun);
11123 CompileRun("get_stack_limit();");
11124
11125 CHECK(stack_limit == set_limit);
11126}
11127
11128
11129TEST(SetResourceConstraintsInThread) {
11130 uint32_t* set_limit;
11131 {
11132 v8::Locker locker;
11133 static const int K = 1024;
11134 set_limit = ComputeStackLimit(128 * K);
11135
11136 // Set stack limit.
11137 v8::ResourceConstraints constraints;
11138 constraints.set_stack_limit(set_limit);
11139 CHECK(v8::SetResourceConstraints(&constraints));
11140
11141 // Execute a script.
11142 v8::HandleScope scope;
11143 LocalContext env;
11144 Local<v8::FunctionTemplate> fun_templ =
11145 v8::FunctionTemplate::New(GetStackLimitCallback);
11146 Local<Function> fun = fun_templ->GetFunction();
11147 env->Global()->Set(v8_str("get_stack_limit"), fun);
11148 CompileRun("get_stack_limit();");
11149
11150 CHECK(stack_limit == set_limit);
11151 }
11152 {
11153 v8::Locker locker;
11154 CHECK(stack_limit == set_limit);
11155 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000011156}
ager@chromium.org3811b432009-10-28 14:53:37 +000011157
11158
11159THREADED_TEST(GetHeapStatistics) {
11160 v8::HandleScope scope;
11161 LocalContext c1;
11162 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011163 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11164 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011165 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011166 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11167 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011168}
11169
11170
11171static double DoubleFromBits(uint64_t value) {
11172 double target;
11173#ifdef BIG_ENDIAN_FLOATING_POINT
11174 const int kIntSize = 4;
11175 // Somebody swapped the lower and higher half of doubles.
11176 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11177 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11178#else
11179 memcpy(&target, &value, sizeof(target));
11180#endif
11181 return target;
11182}
11183
11184
11185static uint64_t DoubleToBits(double value) {
11186 uint64_t target;
11187#ifdef BIG_ENDIAN_FLOATING_POINT
11188 const int kIntSize = 4;
11189 // Somebody swapped the lower and higher half of doubles.
11190 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11191 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11192#else
11193 memcpy(&target, &value, sizeof(target));
11194#endif
11195 return target;
11196}
11197
11198
11199static double DoubleToDateTime(double input) {
11200 double date_limit = 864e13;
11201 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11202 return i::OS::nan_value();
11203 }
11204 return (input < 0) ? -(floor(-input)) : floor(input);
11205}
11206
11207// We don't have a consistent way to write 64-bit constants syntactically, so we
11208// split them into two 32-bit constants and combine them programmatically.
11209static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11210 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11211}
11212
11213
11214THREADED_TEST(QuietSignalingNaNs) {
11215 v8::HandleScope scope;
11216 LocalContext context;
11217 v8::TryCatch try_catch;
11218
11219 // Special double values.
11220 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11221 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11222 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11223 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11224 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11225 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11226 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11227
11228 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11229 // on either side of the epoch.
11230 double date_limit = 864e13;
11231
11232 double test_values[] = {
11233 snan,
11234 qnan,
11235 infinity,
11236 max_normal,
11237 date_limit + 1,
11238 date_limit,
11239 min_normal,
11240 max_denormal,
11241 min_denormal,
11242 0,
11243 -0,
11244 -min_denormal,
11245 -max_denormal,
11246 -min_normal,
11247 -date_limit,
11248 -date_limit - 1,
11249 -max_normal,
11250 -infinity,
11251 -qnan,
11252 -snan
11253 };
11254 int num_test_values = 20;
11255
11256 for (int i = 0; i < num_test_values; i++) {
11257 double test_value = test_values[i];
11258
11259 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11260 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11261 double stored_number = number->NumberValue();
11262 if (!IsNaN(test_value)) {
11263 CHECK_EQ(test_value, stored_number);
11264 } else {
11265 uint64_t stored_bits = DoubleToBits(stored_number);
11266 // Check if quiet nan (bits 51..62 all set).
11267 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11268 }
11269
11270 // Check that Date::New preserves non-NaNs in the date range and
11271 // quiets SNaNs.
11272 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11273 double expected_stored_date = DoubleToDateTime(test_value);
11274 double stored_date = date->NumberValue();
11275 if (!IsNaN(expected_stored_date)) {
11276 CHECK_EQ(expected_stored_date, stored_date);
11277 } else {
11278 uint64_t stored_bits = DoubleToBits(stored_date);
11279 // Check if quiet nan (bits 51..62 all set).
11280 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11281 }
11282 }
11283}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000011284
11285
11286static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11287 v8::HandleScope scope;
11288 v8::TryCatch tc;
11289 v8::Handle<v8::String> str = args[0]->ToString();
11290 if (tc.HasCaught())
11291 return tc.ReThrow();
11292 return v8::Undefined();
11293}
11294
11295
11296// Test that an exception can be propagated down through a spaghetti
11297// stack using ReThrow.
11298THREADED_TEST(SpaghettiStackReThrow) {
11299 v8::HandleScope scope;
11300 LocalContext context;
11301 context->Global()->Set(
11302 v8::String::New("s"),
11303 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11304 v8::TryCatch try_catch;
11305 CompileRun(
11306 "var i = 0;"
11307 "var o = {"
11308 " toString: function () {"
11309 " if (i == 10) {"
11310 " throw 'Hey!';"
11311 " } else {"
11312 " i++;"
11313 " return s(o);"
11314 " }"
11315 " }"
11316 "};"
11317 "s(o);");
11318 CHECK(try_catch.HasCaught());
11319 v8::String::Utf8Value value(try_catch.Exception());
11320 CHECK_EQ(0, strcmp(*value, "Hey!"));
11321}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011322
11323
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011324TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011325 v8::V8::Initialize();
11326
11327 v8::HandleScope scope;
11328 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000011329 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011330 int gc_count;
11331
ager@chromium.org60121232009-12-03 11:25:37 +000011332 // Create a context used to keep the code from aging in the compilation
11333 // cache.
11334 other_context = Context::New();
11335
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011336 // Context-dependent context data creates reference from the compilation
11337 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011338 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011339 context = Context::New();
11340 {
11341 v8::HandleScope scope;
11342
11343 context->Enter();
11344 Local<v8::String> obj = v8::String::New("");
11345 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000011346 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011347 context->Exit();
11348 }
11349 context.Dispose();
11350 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011351 other_context->Enter();
11352 CompileRun(source_simple);
11353 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011354 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011355 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011356 }
ager@chromium.org60121232009-12-03 11:25:37 +000011357 CHECK_GE(2, gc_count);
11358 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011359
11360 // Eval in a function creates reference from the compilation cache to the
11361 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011362 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011363 context = Context::New();
11364 {
11365 v8::HandleScope scope;
11366
11367 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000011368 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011369 context->Exit();
11370 }
11371 context.Dispose();
11372 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011373 other_context->Enter();
11374 CompileRun(source_eval);
11375 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011376 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011377 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011378 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011379 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011380 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011381
11382 // Looking up the line number for an exception creates reference from the
11383 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011384 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011385 context = Context::New();
11386 {
11387 v8::HandleScope scope;
11388
11389 context->Enter();
11390 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000011391 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011392 CHECK(try_catch.HasCaught());
11393 v8::Handle<v8::Message> message = try_catch.Message();
11394 CHECK(!message.IsEmpty());
11395 CHECK_EQ(1, message->GetLineNumber());
11396 context->Exit();
11397 }
11398 context.Dispose();
11399 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011400 other_context->Enter();
11401 CompileRun(source_exception);
11402 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011403 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011404 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011405 }
ager@chromium.org60121232009-12-03 11:25:37 +000011406 CHECK_GE(2, gc_count);
11407 CHECK_EQ(1, GetGlobalObjectsCount());
11408
11409 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011410}
ager@chromium.org5c838252010-02-19 08:53:10 +000011411
11412
11413THREADED_TEST(ScriptOrigin) {
11414 v8::HandleScope scope;
11415 LocalContext env;
11416 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11417 v8::Handle<v8::String> script = v8::String::New(
11418 "function f() {}\n\nfunction g() {}");
11419 v8::Script::Compile(script, &origin)->Run();
11420 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11421 env->Global()->Get(v8::String::New("f")));
11422 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11423 env->Global()->Get(v8::String::New("g")));
11424
11425 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11426 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11427 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11428
11429 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11430 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11431 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11432}
11433
11434
11435THREADED_TEST(ScriptLineNumber) {
11436 v8::HandleScope scope;
11437 LocalContext env;
11438 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11439 v8::Handle<v8::String> script = v8::String::New(
11440 "function f() {}\n\nfunction g() {}");
11441 v8::Script::Compile(script, &origin)->Run();
11442 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11443 env->Global()->Get(v8::String::New("f")));
11444 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11445 env->Global()->Get(v8::String::New("g")));
11446 CHECK_EQ(0, f->GetScriptLineNumber());
11447 CHECK_EQ(2, g->GetScriptLineNumber());
11448}
11449
11450
11451static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11452 const AccessorInfo& info) {
11453 return v8_num(42);
11454}
11455
11456
11457static void SetterWhichSetsYOnThisTo23(Local<String> name,
11458 Local<Value> value,
11459 const AccessorInfo& info) {
11460 info.This()->Set(v8_str("y"), v8_num(23));
11461}
11462
11463
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011464TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000011465 v8::HandleScope scope;
11466 Local<ObjectTemplate> templ = ObjectTemplate::New();
11467 templ->SetAccessor(v8_str("x"),
11468 GetterWhichReturns42,
11469 SetterWhichSetsYOnThisTo23);
11470 LocalContext context;
11471 context->Global()->Set(v8_str("P"), templ->NewInstance());
11472 CompileRun("function C1() {"
11473 " this.x = 23;"
11474 "};"
11475 "C1.prototype = P;"
11476 "function C2() {"
11477 " this.x = 23"
11478 "};"
11479 "C2.prototype = { };"
11480 "C2.prototype.__proto__ = P;");
11481
11482 v8::Local<v8::Script> script;
11483 script = v8::Script::Compile(v8_str("new C1();"));
11484 for (int i = 0; i < 10; i++) {
11485 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11486 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11487 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11488 }
11489
11490 script = v8::Script::Compile(v8_str("new C2();"));
11491 for (int i = 0; i < 10; i++) {
11492 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11493 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11494 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11495 }
11496}
11497
11498
11499static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11500 Local<String> name, const AccessorInfo& info) {
11501 return v8_num(42);
11502}
11503
11504
11505static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11506 Local<String> name, Local<Value> value, const AccessorInfo& info) {
11507 if (name->Equals(v8_str("x"))) {
11508 info.This()->Set(v8_str("y"), v8_num(23));
11509 }
11510 return v8::Handle<Value>();
11511}
11512
11513
11514THREADED_TEST(InterceptorOnConstructorPrototype) {
11515 v8::HandleScope scope;
11516 Local<ObjectTemplate> templ = ObjectTemplate::New();
11517 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11518 NamedPropertySetterWhichSetsYOnThisTo23);
11519 LocalContext context;
11520 context->Global()->Set(v8_str("P"), templ->NewInstance());
11521 CompileRun("function C1() {"
11522 " this.x = 23;"
11523 "};"
11524 "C1.prototype = P;"
11525 "function C2() {"
11526 " this.x = 23"
11527 "};"
11528 "C2.prototype = { };"
11529 "C2.prototype.__proto__ = P;");
11530
11531 v8::Local<v8::Script> script;
11532 script = v8::Script::Compile(v8_str("new C1();"));
11533 for (int i = 0; i < 10; i++) {
11534 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11535 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11536 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11537 }
11538
11539 script = v8::Script::Compile(v8_str("new C2();"));
11540 for (int i = 0; i < 10; i++) {
11541 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11542 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11543 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11544 }
11545}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011546
11547
11548TEST(Bug618) {
11549 const char* source = "function C1() {"
11550 " this.x = 23;"
11551 "};"
11552 "C1.prototype = P;";
11553
11554 v8::HandleScope scope;
11555 LocalContext context;
11556 v8::Local<v8::Script> script;
11557
11558 // Use a simple object as prototype.
11559 v8::Local<v8::Object> prototype = v8::Object::New();
11560 prototype->Set(v8_str("y"), v8_num(42));
11561 context->Global()->Set(v8_str("P"), prototype);
11562
11563 // This compile will add the code to the compilation cache.
11564 CompileRun(source);
11565
11566 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011567 // Allow enough iterations for the inobject slack tracking logic
11568 // to finalize instance size and install the fast construct stub.
11569 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011570 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11571 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11572 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11573 }
11574
11575 // Use an API object with accessors as prototype.
11576 Local<ObjectTemplate> templ = ObjectTemplate::New();
11577 templ->SetAccessor(v8_str("x"),
11578 GetterWhichReturns42,
11579 SetterWhichSetsYOnThisTo23);
11580 context->Global()->Set(v8_str("P"), templ->NewInstance());
11581
11582 // This compile will get the code from the compilation cache.
11583 CompileRun(source);
11584
11585 script = v8::Script::Compile(v8_str("new C1();"));
11586 for (int i = 0; i < 10; i++) {
11587 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11588 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11589 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11590 }
11591}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011592
11593int prologue_call_count = 0;
11594int epilogue_call_count = 0;
11595int prologue_call_count_second = 0;
11596int epilogue_call_count_second = 0;
11597
11598void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11599 ++prologue_call_count;
11600}
11601
11602void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11603 ++epilogue_call_count;
11604}
11605
11606void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11607 ++prologue_call_count_second;
11608}
11609
11610void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11611 ++epilogue_call_count_second;
11612}
11613
11614TEST(GCCallbacks) {
11615 LocalContext context;
11616
11617 v8::V8::AddGCPrologueCallback(PrologueCallback);
11618 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11619 CHECK_EQ(0, prologue_call_count);
11620 CHECK_EQ(0, epilogue_call_count);
11621 i::Heap::CollectAllGarbage(false);
11622 CHECK_EQ(1, prologue_call_count);
11623 CHECK_EQ(1, epilogue_call_count);
11624 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11625 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11626 i::Heap::CollectAllGarbage(false);
11627 CHECK_EQ(2, prologue_call_count);
11628 CHECK_EQ(2, epilogue_call_count);
11629 CHECK_EQ(1, prologue_call_count_second);
11630 CHECK_EQ(1, epilogue_call_count_second);
11631 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11632 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11633 i::Heap::CollectAllGarbage(false);
11634 CHECK_EQ(2, prologue_call_count);
11635 CHECK_EQ(2, epilogue_call_count);
11636 CHECK_EQ(2, prologue_call_count_second);
11637 CHECK_EQ(2, epilogue_call_count_second);
11638 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11639 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11640 i::Heap::CollectAllGarbage(false);
11641 CHECK_EQ(2, prologue_call_count);
11642 CHECK_EQ(2, epilogue_call_count);
11643 CHECK_EQ(2, prologue_call_count_second);
11644 CHECK_EQ(2, epilogue_call_count_second);
11645}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011646
11647
11648THREADED_TEST(AddToJSFunctionResultCache) {
11649 i::FLAG_allow_natives_syntax = true;
11650 v8::HandleScope scope;
11651
11652 LocalContext context;
11653
11654 const char* code =
11655 "(function() {"
11656 " var key0 = 'a';"
11657 " var key1 = 'b';"
11658 " var r0 = %_GetFromCache(0, key0);"
11659 " var r1 = %_GetFromCache(0, key1);"
11660 " var r0_ = %_GetFromCache(0, key0);"
11661 " if (r0 !== r0_)"
11662 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11663 " var r1_ = %_GetFromCache(0, key1);"
11664 " if (r1 !== r1_)"
11665 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11666 " return 'PASSED';"
11667 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011668 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011669 ExpectString(code, "PASSED");
11670}
11671
11672
11673static const int k0CacheSize = 16;
11674
11675THREADED_TEST(FillJSFunctionResultCache) {
11676 i::FLAG_allow_natives_syntax = true;
11677 v8::HandleScope scope;
11678
11679 LocalContext context;
11680
11681 const char* code =
11682 "(function() {"
11683 " var k = 'a';"
11684 " var r = %_GetFromCache(0, k);"
11685 " for (var i = 0; i < 16; i++) {"
11686 " %_GetFromCache(0, 'a' + i);"
11687 " };"
11688 " if (r === %_GetFromCache(0, k))"
11689 " return 'FAILED: k0CacheSize is too small';"
11690 " return 'PASSED';"
11691 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011692 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011693 ExpectString(code, "PASSED");
11694}
11695
11696
11697THREADED_TEST(RoundRobinGetFromCache) {
11698 i::FLAG_allow_natives_syntax = true;
11699 v8::HandleScope scope;
11700
11701 LocalContext context;
11702
11703 const char* code =
11704 "(function() {"
11705 " var keys = [];"
11706 " for (var i = 0; i < 16; i++) keys.push(i);"
11707 " var values = [];"
11708 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11709 " for (var i = 0; i < 16; i++) {"
11710 " var v = %_GetFromCache(0, keys[i]);"
11711 " if (v !== values[i])"
11712 " return 'Wrong value for ' + "
11713 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11714 " };"
11715 " return 'PASSED';"
11716 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011717 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011718 ExpectString(code, "PASSED");
11719}
11720
11721
11722THREADED_TEST(ReverseGetFromCache) {
11723 i::FLAG_allow_natives_syntax = true;
11724 v8::HandleScope scope;
11725
11726 LocalContext context;
11727
11728 const char* code =
11729 "(function() {"
11730 " var keys = [];"
11731 " for (var i = 0; i < 16; i++) keys.push(i);"
11732 " var values = [];"
11733 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11734 " for (var i = 15; i >= 16; i--) {"
11735 " var v = %_GetFromCache(0, keys[i]);"
11736 " if (v !== values[i])"
11737 " return 'Wrong value for ' + "
11738 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11739 " };"
11740 " return 'PASSED';"
11741 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011742 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011743 ExpectString(code, "PASSED");
11744}
11745
11746
11747THREADED_TEST(TestEviction) {
11748 i::FLAG_allow_natives_syntax = true;
11749 v8::HandleScope scope;
11750
11751 LocalContext context;
11752
11753 const char* code =
11754 "(function() {"
11755 " for (var i = 0; i < 2*16; i++) {"
11756 " %_GetFromCache(0, 'a' + i);"
11757 " };"
11758 " return 'PASSED';"
11759 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011760 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011761 ExpectString(code, "PASSED");
11762}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011763
11764
11765THREADED_TEST(TwoByteStringInAsciiCons) {
11766 // See Chromium issue 47824.
11767 v8::HandleScope scope;
11768
11769 LocalContext context;
11770 const char* init_code =
11771 "var str1 = 'abelspendabel';"
11772 "var str2 = str1 + str1 + str1;"
11773 "str2;";
11774 Local<Value> result = CompileRun(init_code);
11775
11776 CHECK(result->IsString());
11777 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11778 int length = string->length();
11779 CHECK(string->IsAsciiRepresentation());
11780
11781 FlattenString(string);
11782 i::Handle<i::String> flat_string = FlattenGetString(string);
11783
11784 CHECK(string->IsAsciiRepresentation());
11785 CHECK(flat_string->IsAsciiRepresentation());
11786
11787 // Create external resource.
11788 uint16_t* uc16_buffer = new uint16_t[length + 1];
11789
11790 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11791 uc16_buffer[length] = 0;
11792
11793 TestResource resource(uc16_buffer);
11794
11795 flat_string->MakeExternal(&resource);
11796
11797 CHECK(flat_string->IsTwoByteRepresentation());
11798
11799 // At this point, we should have a Cons string which is flat and ASCII,
11800 // with a first half that is a two-byte string (although it only contains
11801 // ASCII characters). This is a valid sequence of steps, and it can happen
11802 // in real pages.
11803
11804 CHECK(string->IsAsciiRepresentation());
11805 i::ConsString* cons = i::ConsString::cast(*string);
11806 CHECK_EQ(0, cons->second()->length());
11807 CHECK(cons->first()->IsTwoByteRepresentation());
11808
11809 // Check that some string operations work.
11810
11811 // Atom RegExp.
11812 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11813 CHECK_EQ(6, reresult->Int32Value());
11814
11815 // Nonatom RegExp.
11816 reresult = CompileRun("str2.match(/abe./g).length;");
11817 CHECK_EQ(6, reresult->Int32Value());
11818
11819 reresult = CompileRun("str2.search(/bel/g);");
11820 CHECK_EQ(1, reresult->Int32Value());
11821
11822 reresult = CompileRun("str2.search(/be./g);");
11823 CHECK_EQ(1, reresult->Int32Value());
11824
11825 ExpectTrue("/bel/g.test(str2);");
11826
11827 ExpectTrue("/be./g.test(str2);");
11828
11829 reresult = CompileRun("/bel/g.exec(str2);");
11830 CHECK(!reresult->IsNull());
11831
11832 reresult = CompileRun("/be./g.exec(str2);");
11833 CHECK(!reresult->IsNull());
11834
11835 ExpectString("str2.substring(2, 10);", "elspenda");
11836
11837 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11838
11839 ExpectString("str2.charAt(2);", "e");
11840
11841 reresult = CompileRun("str2.charCodeAt(2);");
11842 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11843}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000011844
11845
11846// Failed access check callback that performs a GC on each invocation.
11847void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11848 v8::AccessType type,
11849 Local<v8::Value> data) {
11850 i::Heap::CollectAllGarbage(true);
11851}
11852
11853
11854TEST(GCInFailedAccessCheckCallback) {
11855 // Install a failed access check callback that performs a GC on each
11856 // invocation. Then force the callback to be called from va
11857
11858 v8::V8::Initialize();
11859 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11860
11861 v8::HandleScope scope;
11862
11863 // Create an ObjectTemplate for global objects and install access
11864 // check callbacks that will block access.
11865 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11866 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11867 IndexedGetAccessBlocker,
11868 v8::Handle<v8::Value>(),
11869 false);
11870
11871 // Create a context and set an x property on it's global object.
11872 LocalContext context0(NULL, global_template);
11873 context0->Global()->Set(v8_str("x"), v8_num(42));
11874 v8::Handle<v8::Object> global0 = context0->Global();
11875
11876 // Create a context with a different security token so that the
11877 // failed access check callback will be called on each access.
11878 LocalContext context1(NULL, global_template);
11879 context1->Global()->Set(v8_str("other"), global0);
11880
11881 // Get property with failed access check.
11882 ExpectUndefined("other.x");
11883
11884 // Get element with failed access check.
11885 ExpectUndefined("other[0]");
11886
11887 // Set property with failed access check.
11888 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11889 CHECK(result->IsObject());
11890
11891 // Set element with failed access check.
11892 result = CompileRun("other[0] = new Object()");
11893 CHECK(result->IsObject());
11894
11895 // Get property attribute with failed access check.
11896 ExpectFalse("\'x\' in other");
11897
11898 // Get property attribute for element with failed access check.
11899 ExpectFalse("0 in other");
11900
11901 // Delete property.
11902 ExpectFalse("delete other.x");
11903
11904 // Delete element.
11905 CHECK_EQ(false, global0->Delete(0));
11906
11907 // DefineAccessor.
11908 CHECK_EQ(false,
11909 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11910
11911 // Define JavaScript accessor.
11912 ExpectUndefined("Object.prototype.__defineGetter__.call("
11913 " other, \'x\', function() { return 42; })");
11914
11915 // LookupAccessor.
11916 ExpectUndefined("Object.prototype.__lookupGetter__.call("
11917 " other, \'x\')");
11918
11919 // HasLocalElement.
11920 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11921
11922 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11923 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11924 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11925
11926 // Reset the failed access check callback so it does not influence
11927 // the other tests.
11928 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11929}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011930
11931
11932TEST(StringCheckMultipleContexts) {
11933 const char* code =
11934 "(function() { return \"a\".charAt(0); })()";
11935
11936 {
11937 // Run the code twice in the first context to initialize the call IC.
11938 v8::HandleScope scope;
11939 LocalContext context1;
11940 ExpectString(code, "a");
11941 ExpectString(code, "a");
11942 }
11943
11944 {
11945 // Change the String.prototype in the second context and check
11946 // that the right function gets called.
11947 v8::HandleScope scope;
11948 LocalContext context2;
11949 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11950 ExpectString(code, "not a");
11951 }
11952}
11953
11954
11955TEST(NumberCheckMultipleContexts) {
11956 const char* code =
11957 "(function() { return (42).toString(); })()";
11958
11959 {
11960 // Run the code twice in the first context to initialize the call IC.
11961 v8::HandleScope scope;
11962 LocalContext context1;
11963 ExpectString(code, "42");
11964 ExpectString(code, "42");
11965 }
11966
11967 {
11968 // Change the Number.prototype in the second context and check
11969 // that the right function gets called.
11970 v8::HandleScope scope;
11971 LocalContext context2;
11972 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11973 ExpectString(code, "not 42");
11974 }
11975}
11976
11977
11978TEST(BooleanCheckMultipleContexts) {
11979 const char* code =
11980 "(function() { return true.toString(); })()";
11981
11982 {
11983 // Run the code twice in the first context to initialize the call IC.
11984 v8::HandleScope scope;
11985 LocalContext context1;
11986 ExpectString(code, "true");
11987 ExpectString(code, "true");
11988 }
11989
11990 {
11991 // Change the Boolean.prototype in the second context and check
11992 // that the right function gets called.
11993 v8::HandleScope scope;
11994 LocalContext context2;
11995 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11996 ExpectString(code, "");
11997 }
11998}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011999
12000
12001TEST(DontDeleteCellLoadIC) {
12002 const char* function_code =
12003 "function readCell() { while (true) { return cell; } }";
12004
12005 {
12006 // Run the code twice in the first context to initialize the load
12007 // IC for a don't delete cell.
12008 v8::HandleScope scope;
12009 LocalContext context1;
12010 CompileRun("var cell = \"first\";");
12011 ExpectBoolean("delete cell", false);
12012 CompileRun(function_code);
12013 ExpectString("readCell()", "first");
12014 ExpectString("readCell()", "first");
12015 }
12016
12017 {
12018 // Use a deletable cell in the second context.
12019 v8::HandleScope scope;
12020 LocalContext context2;
12021 CompileRun("cell = \"second\";");
12022 CompileRun(function_code);
12023 ExpectString("readCell()", "second");
12024 ExpectBoolean("delete cell", true);
12025 ExpectString("(function() {"
12026 " try {"
12027 " return readCell();"
12028 " } catch(e) {"
12029 " return e.toString();"
12030 " }"
12031 "})()",
12032 "ReferenceError: cell is not defined");
12033 CompileRun("cell = \"new_second\";");
12034 i::Heap::CollectAllGarbage(true);
12035 ExpectString("readCell()", "new_second");
12036 ExpectString("readCell()", "new_second");
12037 }
12038}
12039
12040
12041TEST(DontDeleteCellLoadICForceDelete) {
12042 const char* function_code =
12043 "function readCell() { while (true) { return cell; } }";
12044
12045 // Run the code twice to initialize the load IC for a don't delete
12046 // cell.
12047 v8::HandleScope scope;
12048 LocalContext context;
12049 CompileRun("var cell = \"value\";");
12050 ExpectBoolean("delete cell", false);
12051 CompileRun(function_code);
12052 ExpectString("readCell()", "value");
12053 ExpectString("readCell()", "value");
12054
12055 // Delete the cell using the API and check the inlined code works
12056 // correctly.
12057 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12058 ExpectString("(function() {"
12059 " try {"
12060 " return readCell();"
12061 " } catch(e) {"
12062 " return e.toString();"
12063 " }"
12064 "})()",
12065 "ReferenceError: cell is not defined");
12066}
12067
12068
12069TEST(DontDeleteCellLoadICAPI) {
12070 const char* function_code =
12071 "function readCell() { while (true) { return cell; } }";
12072
12073 // Run the code twice to initialize the load IC for a don't delete
12074 // cell created using the API.
12075 v8::HandleScope scope;
12076 LocalContext context;
12077 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12078 ExpectBoolean("delete cell", false);
12079 CompileRun(function_code);
12080 ExpectString("readCell()", "value");
12081 ExpectString("readCell()", "value");
12082
12083 // Delete the cell using the API and check the inlined code works
12084 // correctly.
12085 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12086 ExpectString("(function() {"
12087 " try {"
12088 " return readCell();"
12089 " } catch(e) {"
12090 " return e.toString();"
12091 " }"
12092 "})()",
12093 "ReferenceError: cell is not defined");
12094}
12095
12096
12097TEST(GlobalLoadICGC) {
12098 const char* function_code =
12099 "function readCell() { while (true) { return cell; } }";
12100
12101 // Check inline load code for a don't delete cell is cleared during
12102 // GC.
12103 {
12104 v8::HandleScope scope;
12105 LocalContext context;
12106 CompileRun("var cell = \"value\";");
12107 ExpectBoolean("delete cell", false);
12108 CompileRun(function_code);
12109 ExpectString("readCell()", "value");
12110 ExpectString("readCell()", "value");
12111 }
12112 {
12113 v8::HandleScope scope;
12114 LocalContext context2;
12115 // Hold the code object in the second context.
12116 CompileRun(function_code);
12117 CheckSurvivingGlobalObjectsCount(1);
12118 }
12119
12120 // Check inline load code for a deletable cell is cleared during GC.
12121 {
12122 v8::HandleScope scope;
12123 LocalContext context;
12124 CompileRun("cell = \"value\";");
12125 CompileRun(function_code);
12126 ExpectString("readCell()", "value");
12127 ExpectString("readCell()", "value");
12128 }
12129 {
12130 v8::HandleScope scope;
12131 LocalContext context2;
12132 // Hold the code object in the second context.
12133 CompileRun(function_code);
12134 CheckSurvivingGlobalObjectsCount(1);
12135 }
12136}
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012137
12138
12139TEST(RegExp) {
12140 v8::HandleScope scope;
12141 LocalContext context;
12142
12143 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12144 CHECK(re->IsRegExp());
12145 CHECK(re->GetSource()->Equals(v8_str("foo")));
12146 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12147
12148 re = v8::RegExp::New(v8_str("bar"),
12149 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12150 v8::RegExp::kGlobal));
12151 CHECK(re->IsRegExp());
12152 CHECK(re->GetSource()->Equals(v8_str("bar")));
12153 CHECK_EQ(static_cast<int>(re->GetFlags()),
12154 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12155
12156 re = v8::RegExp::New(v8_str("baz"),
12157 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12158 v8::RegExp::kMultiline));
12159 CHECK(re->IsRegExp());
12160 CHECK(re->GetSource()->Equals(v8_str("baz")));
12161 CHECK_EQ(static_cast<int>(re->GetFlags()),
12162 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12163
12164 re = CompileRun("/quux/").As<v8::RegExp>();
12165 CHECK(re->IsRegExp());
12166 CHECK(re->GetSource()->Equals(v8_str("quux")));
12167 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12168
12169 re = CompileRun("/quux/gm").As<v8::RegExp>();
12170 CHECK(re->IsRegExp());
12171 CHECK(re->GetSource()->Equals(v8_str("quux")));
12172 CHECK_EQ(static_cast<int>(re->GetFlags()),
12173 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12174
12175 // Override the RegExp constructor and check the API constructor
12176 // still works.
12177 CompileRun("RegExp = function() {}");
12178
12179 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12180 CHECK(re->IsRegExp());
12181 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12182 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12183
12184 re = v8::RegExp::New(v8_str("foobarbaz"),
12185 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12186 v8::RegExp::kMultiline));
12187 CHECK(re->IsRegExp());
12188 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12189 CHECK_EQ(static_cast<int>(re->GetFlags()),
12190 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12191
12192 context->Global()->Set(v8_str("re"), re);
12193 ExpectTrue("re.test('FoobarbaZ')");
12194
12195 v8::TryCatch try_catch;
12196 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12197 CHECK(re.IsEmpty());
12198 CHECK(try_catch.HasCaught());
12199 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12200 ExpectTrue("ex instanceof SyntaxError");
12201}
12202
12203
12204static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12205 const v8::AccessorInfo& info ) {
12206 return v8_str("42!");
12207}
12208
12209
12210static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12211 v8::Handle<v8::Array> result = v8::Array::New();
12212 result->Set(0, v8_str("universalAnswer"));
12213 return result;
12214}
12215
12216
12217TEST(NamedEnumeratorAndForIn) {
12218 v8::HandleScope handle_scope;
12219 LocalContext context;
12220 v8::Context::Scope context_scope(context.local());
12221
12222 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12223 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12224 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12225 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12226 "var result = []; for (var k in o) result.push(k); result"));
12227 CHECK_EQ(1, result->Length());
12228 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12229}