blob: e06062b2ed4c46d4a6f8e23b64a09be49f6eccd2 [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
5376 value = v8_compile("other.blocked_prop = 1")->Run();
5377 value = v8_compile("other.blocked_prop")->Run();
5378 CHECK(value->IsUndefined());
5379
ager@chromium.org870a0b62008-11-04 11:43:05 +00005380 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5381 CHECK(value->IsFalse());
5382
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005383 // Access accessible property
5384 value = v8_compile("other.accessible_prop = 3")->Run();
5385 CHECK(value->IsNumber());
5386 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005387 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005388
5389 value = v8_compile("other.accessible_prop")->Run();
5390 CHECK(value->IsNumber());
5391 CHECK_EQ(3, value->Int32Value());
5392
ager@chromium.org870a0b62008-11-04 11:43:05 +00005393 value =
5394 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
5395 CHECK(value->IsTrue());
5396
5397 // Enumeration doesn't enumerate accessors from inaccessible objects in
5398 // the prototype chain even if the accessors are in themselves accessible.
5399 Local<Value> result =
5400 CompileRun("(function(){var obj = {'__proto__':other};"
5401 "for (var p in obj)"
5402 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5403 " return false;"
5404 " }"
5405 "return true;})()");
5406 CHECK(result->IsTrue());
5407
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005408 context1->Exit();
5409 context0->Exit();
5410 context1.Dispose();
5411 context0.Dispose();
5412}
5413
5414
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005415static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5416 Local<Value> name,
5417 v8::AccessType type,
5418 Local<Value> data) {
5419 return false;
5420}
5421
5422
5423static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5424 uint32_t key,
5425 v8::AccessType type,
5426 Local<Value> data) {
5427 return false;
5428}
5429
5430
5431THREADED_TEST(AccessControlGetOwnPropertyNames) {
5432 v8::HandleScope handle_scope;
5433 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5434
5435 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5436 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5437 GetOwnPropertyNamesIndexedBlocker);
5438
5439 // Create an environment
5440 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5441 context0->Enter();
5442
5443 v8::Handle<v8::Object> global0 = context0->Global();
5444
5445 v8::HandleScope scope1;
5446
5447 v8::Persistent<Context> context1 = Context::New();
5448 context1->Enter();
5449
5450 v8::Handle<v8::Object> global1 = context1->Global();
5451 global1->Set(v8_str("other"), global0);
5452 global1->Set(v8_str("object"), obj_template->NewInstance());
5453
5454 v8::Handle<Value> value;
5455
5456 // Attempt to get the property names of the other global object and
5457 // of an object that requires access checks. Accessing the other
5458 // global object should be blocked by access checks on the global
5459 // proxy object. Accessing the object that requires access checks
5460 // is blocked by the access checks on the object itself.
5461 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5462 CHECK(value->IsTrue());
5463
5464 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5465 CHECK(value->IsTrue());
5466
5467 context1->Exit();
5468 context0->Exit();
5469 context1.Dispose();
5470 context0.Dispose();
5471}
5472
5473
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00005474static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5475 v8::Handle<v8::Array> result = v8::Array::New(1);
5476 result->Set(0, v8_str("x"));
5477 return result;
5478}
5479
5480
5481THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5482 v8::HandleScope handle_scope;
5483 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5484
5485 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5486 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5487 NamedPropertyEnumerator);
5488
5489 LocalContext context;
5490 v8::Handle<v8::Object> global = context->Global();
5491 global->Set(v8_str("object"), obj_template->NewInstance());
5492
5493 v8::Handle<Value> value =
5494 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5495 CHECK_EQ(v8_str("x"), value);
5496}
5497
5498
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005499static v8::Handle<Value> ConstTenGetter(Local<String> name,
5500 const AccessorInfo& info) {
5501 return v8_num(10);
5502}
5503
5504
5505THREADED_TEST(CrossDomainAccessors) {
5506 v8::HandleScope handle_scope;
5507
5508 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5509
5510 v8::Handle<v8::ObjectTemplate> global_template =
5511 func_template->InstanceTemplate();
5512
5513 v8::Handle<v8::ObjectTemplate> proto_template =
5514 func_template->PrototypeTemplate();
5515
5516 // Add an accessor to proto that's accessible by cross-domain JS code.
5517 proto_template->SetAccessor(v8_str("accessible"),
5518 ConstTenGetter, 0,
5519 v8::Handle<Value>(),
5520 v8::ALL_CAN_READ);
5521
5522 // Add an accessor that is not accessible by cross-domain JS code.
5523 global_template->SetAccessor(v8_str("unreachable"),
5524 UnreachableGetter, 0,
5525 v8::Handle<Value>(),
5526 v8::DEFAULT);
5527
5528 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5529 context0->Enter();
5530
5531 Local<v8::Object> global = context0->Global();
5532 // Add a normal property that shadows 'accessible'
5533 global->Set(v8_str("accessible"), v8_num(11));
5534
5535 // Enter a new context.
5536 v8::HandleScope scope1;
5537 v8::Persistent<Context> context1 = Context::New();
5538 context1->Enter();
5539
5540 v8::Handle<v8::Object> global1 = context1->Global();
5541 global1->Set(v8_str("other"), global);
5542
5543 // Should return 10, instead of 11
5544 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5545 CHECK(value->IsNumber());
5546 CHECK_EQ(10, value->Int32Value());
5547
5548 value = v8_compile("other.unreachable")->Run();
5549 CHECK(value->IsUndefined());
5550
5551 context1->Exit();
5552 context0->Exit();
5553 context1.Dispose();
5554 context0.Dispose();
5555}
5556
5557
5558static int named_access_count = 0;
5559static int indexed_access_count = 0;
5560
5561static bool NamedAccessCounter(Local<v8::Object> global,
5562 Local<Value> name,
5563 v8::AccessType type,
5564 Local<Value> data) {
5565 named_access_count++;
5566 return true;
5567}
5568
5569
5570static bool IndexedAccessCounter(Local<v8::Object> global,
5571 uint32_t key,
5572 v8::AccessType type,
5573 Local<Value> data) {
5574 indexed_access_count++;
5575 return true;
5576}
5577
5578
5579// This one is too easily disturbed by other tests.
5580TEST(AccessControlIC) {
5581 named_access_count = 0;
5582 indexed_access_count = 0;
5583
5584 v8::HandleScope handle_scope;
5585
5586 // Create an environment.
5587 v8::Persistent<Context> context0 = Context::New();
5588 context0->Enter();
5589
5590 // Create an object that requires access-check functions to be
5591 // called for cross-domain access.
5592 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5593 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5594 IndexedAccessCounter);
5595 Local<v8::Object> object = object_template->NewInstance();
5596
5597 v8::HandleScope scope1;
5598
5599 // Create another environment.
5600 v8::Persistent<Context> context1 = Context::New();
5601 context1->Enter();
5602
5603 // Make easy access to the object from the other environment.
5604 v8::Handle<v8::Object> global1 = context1->Global();
5605 global1->Set(v8_str("obj"), object);
5606
5607 v8::Handle<Value> value;
5608
5609 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005610 CompileRun("function testProp(obj) {"
5611 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5612 " for (var j = 0; j < 10; j++) obj.prop;"
5613 " return obj.prop"
5614 "}");
5615 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005616 CHECK(value->IsNumber());
5617 CHECK_EQ(1, value->Int32Value());
5618 CHECK_EQ(21, named_access_count);
5619
5620 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005621 CompileRun("var p = 'prop';"
5622 "function testKeyed(obj) {"
5623 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5624 " for (var j = 0; j < 10; j++) obj[p];"
5625 " return obj[p];"
5626 "}");
5627 // Use obj which requires access checks. No inline caching is used
5628 // in that case.
5629 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005630 CHECK(value->IsNumber());
5631 CHECK_EQ(1, value->Int32Value());
5632 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005633 // Force the inline caches into generic state and try again.
5634 CompileRun("testKeyed({ a: 0 })");
5635 CompileRun("testKeyed({ b: 0 })");
5636 value = CompileRun("testKeyed(obj)");
5637 CHECK(value->IsNumber());
5638 CHECK_EQ(1, value->Int32Value());
5639 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005640
5641 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00005642 CompileRun("function testIndexed(obj) {"
5643 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5644 " for (var j = 0; j < 10; j++) obj[0];"
5645 " return obj[0]"
5646 "}");
5647 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648 CHECK(value->IsNumber());
5649 CHECK_EQ(1, value->Int32Value());
5650 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005651 // Force the inline caches into generic state.
5652 CompileRun("testIndexed(new Array(1))");
5653 // Test that the indexed access check is called.
5654 value = CompileRun("testIndexed(obj)");
5655 CHECK(value->IsNumber());
5656 CHECK_EQ(1, value->Int32Value());
5657 CHECK_EQ(42, indexed_access_count);
5658
5659 // Check that the named access check is called when invoking
5660 // functions on an object that requires access checks.
5661 CompileRun("obj.f = function() {}");
5662 CompileRun("function testCallNormal(obj) {"
5663 " for (var i = 0; i < 10; i++) obj.f();"
5664 "}");
5665 CompileRun("testCallNormal(obj)");
5666 CHECK_EQ(74, named_access_count);
5667
5668 // Force obj into slow case.
5669 value = CompileRun("delete obj.prop");
5670 CHECK(value->BooleanValue());
5671 // Force inline caches into dictionary probing mode.
5672 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5673 // Test that the named access check is called.
5674 value = CompileRun("testProp(obj);");
5675 CHECK(value->IsNumber());
5676 CHECK_EQ(1, value->Int32Value());
5677 CHECK_EQ(96, named_access_count);
5678
5679 // Force the call inline cache into dictionary probing mode.
5680 CompileRun("o.f = function() {}; testCallNormal(o)");
5681 // Test that the named access check is still called for each
5682 // invocation of the function.
5683 value = CompileRun("testCallNormal(obj)");
5684 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005685
5686 context1->Exit();
5687 context0->Exit();
5688 context1.Dispose();
5689 context0.Dispose();
5690}
5691
5692
5693static bool NamedAccessFlatten(Local<v8::Object> global,
5694 Local<Value> name,
5695 v8::AccessType type,
5696 Local<Value> data) {
5697 char buf[100];
5698 int len;
5699
5700 CHECK(name->IsString());
5701
5702 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005703 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005704 CHECK_EQ(4, len);
5705
5706 uint16_t buf2[100];
5707
5708 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005709 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005710 CHECK_EQ(4, len);
5711
5712 return true;
5713}
5714
5715
5716static bool IndexedAccessFlatten(Local<v8::Object> global,
5717 uint32_t key,
5718 v8::AccessType type,
5719 Local<Value> data) {
5720 return true;
5721}
5722
5723
5724// Regression test. In access checks, operations that may cause
5725// garbage collection are not allowed. It used to be the case that
5726// using the Write operation on a string could cause a garbage
5727// collection due to flattening of the string. This is no longer the
5728// case.
5729THREADED_TEST(AccessControlFlatten) {
5730 named_access_count = 0;
5731 indexed_access_count = 0;
5732
5733 v8::HandleScope handle_scope;
5734
5735 // Create an environment.
5736 v8::Persistent<Context> context0 = Context::New();
5737 context0->Enter();
5738
5739 // Create an object that requires access-check functions to be
5740 // called for cross-domain access.
5741 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5742 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5743 IndexedAccessFlatten);
5744 Local<v8::Object> object = object_template->NewInstance();
5745
5746 v8::HandleScope scope1;
5747
5748 // Create another environment.
5749 v8::Persistent<Context> context1 = Context::New();
5750 context1->Enter();
5751
5752 // Make easy access to the object from the other environment.
5753 v8::Handle<v8::Object> global1 = context1->Global();
5754 global1->Set(v8_str("obj"), object);
5755
5756 v8::Handle<Value> value;
5757
5758 value = v8_compile("var p = 'as' + 'df';")->Run();
5759 value = v8_compile("obj[p];")->Run();
5760
5761 context1->Exit();
5762 context0->Exit();
5763 context1.Dispose();
5764 context0.Dispose();
5765}
5766
5767
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005768static v8::Handle<Value> AccessControlNamedGetter(
5769 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005770 return v8::Integer::New(42);
5771}
5772
5773
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005774static v8::Handle<Value> AccessControlNamedSetter(
5775 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005776 return value;
5777}
5778
5779
5780static v8::Handle<Value> AccessControlIndexedGetter(
5781 uint32_t index,
5782 const AccessorInfo& info) {
5783 return v8_num(42);
5784}
5785
5786
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005787static v8::Handle<Value> AccessControlIndexedSetter(
5788 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005789 return value;
5790}
5791
5792
5793THREADED_TEST(AccessControlInterceptorIC) {
5794 named_access_count = 0;
5795 indexed_access_count = 0;
5796
5797 v8::HandleScope handle_scope;
5798
5799 // Create an environment.
5800 v8::Persistent<Context> context0 = Context::New();
5801 context0->Enter();
5802
5803 // Create an object that requires access-check functions to be
5804 // called for cross-domain access. The object also has interceptors
5805 // interceptor.
5806 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5807 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5808 IndexedAccessCounter);
5809 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5810 AccessControlNamedSetter);
5811 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5812 AccessControlIndexedSetter);
5813 Local<v8::Object> object = object_template->NewInstance();
5814
5815 v8::HandleScope scope1;
5816
5817 // Create another environment.
5818 v8::Persistent<Context> context1 = Context::New();
5819 context1->Enter();
5820
5821 // Make easy access to the object from the other environment.
5822 v8::Handle<v8::Object> global1 = context1->Global();
5823 global1->Set(v8_str("obj"), object);
5824
5825 v8::Handle<Value> value;
5826
5827 // Check that the named access-control function is called every time
5828 // eventhough there is an interceptor on the object.
5829 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5830 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5831 "obj.x")->Run();
5832 CHECK(value->IsNumber());
5833 CHECK_EQ(42, value->Int32Value());
5834 CHECK_EQ(21, named_access_count);
5835
5836 value = v8_compile("var p = 'x';")->Run();
5837 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5838 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5839 "obj[p]")->Run();
5840 CHECK(value->IsNumber());
5841 CHECK_EQ(42, value->Int32Value());
5842 CHECK_EQ(42, named_access_count);
5843
5844 // Check that the indexed access-control function is called every
5845 // time eventhough there is an interceptor on the object.
5846 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5847 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5848 "obj[0]")->Run();
5849 CHECK(value->IsNumber());
5850 CHECK_EQ(42, value->Int32Value());
5851 CHECK_EQ(21, indexed_access_count);
5852
5853 context1->Exit();
5854 context0->Exit();
5855 context1.Dispose();
5856 context0.Dispose();
5857}
5858
5859
5860THREADED_TEST(Version) {
5861 v8::V8::GetVersion();
5862}
5863
5864
5865static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5866 ApiTestFuzzer::Fuzz();
5867 return v8_num(12);
5868}
5869
5870
5871THREADED_TEST(InstanceProperties) {
5872 v8::HandleScope handle_scope;
5873 LocalContext context;
5874
5875 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5876 Local<ObjectTemplate> instance = t->InstanceTemplate();
5877
5878 instance->Set(v8_str("x"), v8_num(42));
5879 instance->Set(v8_str("f"),
5880 v8::FunctionTemplate::New(InstanceFunctionCallback));
5881
5882 Local<Value> o = t->GetFunction()->NewInstance();
5883
5884 context->Global()->Set(v8_str("i"), o);
5885 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5886 CHECK_EQ(42, value->Int32Value());
5887
5888 value = Script::Compile(v8_str("i.f()"))->Run();
5889 CHECK_EQ(12, value->Int32Value());
5890}
5891
5892
5893static v8::Handle<Value>
5894GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5895 ApiTestFuzzer::Fuzz();
5896 return v8::Handle<Value>();
5897}
5898
5899
5900THREADED_TEST(GlobalObjectInstanceProperties) {
5901 v8::HandleScope handle_scope;
5902
5903 Local<Value> global_object;
5904
5905 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5906 t->InstanceTemplate()->SetNamedPropertyHandler(
5907 GlobalObjectInstancePropertiesGet);
5908 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5909 instance_template->Set(v8_str("x"), v8_num(42));
5910 instance_template->Set(v8_str("f"),
5911 v8::FunctionTemplate::New(InstanceFunctionCallback));
5912
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005913 // The script to check how Crankshaft compiles missing global function
5914 // invocations. function g is not defined and should throw on call.
5915 const char* script =
5916 "function wrapper(call) {"
5917 " var x = 0, y = 1;"
5918 " for (var i = 0; i < 1000; i++) {"
5919 " x += i * 100;"
5920 " y += i * 100;"
5921 " }"
5922 " if (call) g();"
5923 "}"
5924 "for (var i = 0; i < 17; i++) wrapper(false);"
5925 "var thrown = 0;"
5926 "try { wrapper(true); } catch (e) { thrown = 1; };"
5927 "thrown";
5928
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005929 {
5930 LocalContext env(NULL, instance_template);
5931 // Hold on to the global object so it can be used again in another
5932 // environment initialization.
5933 global_object = env->Global();
5934
5935 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5936 CHECK_EQ(42, value->Int32Value());
5937 value = Script::Compile(v8_str("f()"))->Run();
5938 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005939 value = Script::Compile(v8_str(script))->Run();
5940 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005941 }
5942
5943 {
5944 // Create new environment reusing the global object.
5945 LocalContext env(NULL, instance_template, global_object);
5946 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5947 CHECK_EQ(42, value->Int32Value());
5948 value = Script::Compile(v8_str("f()"))->Run();
5949 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005950 value = Script::Compile(v8_str(script))->Run();
5951 CHECK_EQ(1, value->Int32Value());
5952 }
5953}
5954
5955
5956THREADED_TEST(CallKnownGlobalReceiver) {
5957 v8::HandleScope handle_scope;
5958
5959 Local<Value> global_object;
5960
5961 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5962 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5963
5964 // The script to check that we leave global object not
5965 // global object proxy on stack when we deoptimize from inside
5966 // arguments evaluation.
5967 // To provoke error we need to both force deoptimization
5968 // from arguments evaluation and to force CallIC to take
5969 // CallIC_Miss code path that can't cope with global proxy.
5970 const char* script =
5971 "function bar(x, y) { try { } finally { } }"
5972 "function baz(x) { try { } finally { } }"
5973 "function bom(x) { try { } finally { } }"
5974 "function foo(x) { bar([x], bom(2)); }"
5975 "for (var i = 0; i < 10000; i++) foo(1);"
5976 "foo";
5977
5978 Local<Value> foo;
5979 {
5980 LocalContext env(NULL, instance_template);
5981 // Hold on to the global object so it can be used again in another
5982 // environment initialization.
5983 global_object = env->Global();
5984 foo = Script::Compile(v8_str(script))->Run();
5985 }
5986
5987 {
5988 // Create new environment reusing the global object.
5989 LocalContext env(NULL, instance_template, global_object);
5990 env->Global()->Set(v8_str("foo"), foo);
5991 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005992 }
5993}
5994
5995
5996static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5997 ApiTestFuzzer::Fuzz();
5998 return v8_num(42);
5999}
6000
6001
6002static int shadow_y;
6003static int shadow_y_setter_call_count;
6004static int shadow_y_getter_call_count;
6005
6006
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006007static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006008 shadow_y_setter_call_count++;
6009 shadow_y = 42;
6010}
6011
6012
6013static v8::Handle<Value> ShadowYGetter(Local<String> name,
6014 const AccessorInfo& info) {
6015 ApiTestFuzzer::Fuzz();
6016 shadow_y_getter_call_count++;
6017 return v8_num(shadow_y);
6018}
6019
6020
6021static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6022 const AccessorInfo& info) {
6023 return v8::Handle<Value>();
6024}
6025
6026
6027static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6028 const AccessorInfo&) {
6029 return v8::Handle<Value>();
6030}
6031
6032
6033THREADED_TEST(ShadowObject) {
6034 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6035 v8::HandleScope handle_scope;
6036
6037 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6038 LocalContext context(NULL, global_template);
6039
6040 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6041 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6042 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6043 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6044 Local<ObjectTemplate> instance = t->InstanceTemplate();
6045
6046 // Only allow calls of f on instances of t.
6047 Local<v8::Signature> signature = v8::Signature::New(t);
6048 proto->Set(v8_str("f"),
6049 v8::FunctionTemplate::New(ShadowFunctionCallback,
6050 Local<Value>(),
6051 signature));
6052 proto->Set(v8_str("x"), v8_num(12));
6053
6054 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6055
6056 Local<Value> o = t->GetFunction()->NewInstance();
6057 context->Global()->Set(v8_str("__proto__"), o);
6058
6059 Local<Value> value =
6060 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6061 CHECK(value->IsBoolean());
6062 CHECK(!value->BooleanValue());
6063
6064 value = Script::Compile(v8_str("x"))->Run();
6065 CHECK_EQ(12, value->Int32Value());
6066
6067 value = Script::Compile(v8_str("f()"))->Run();
6068 CHECK_EQ(42, value->Int32Value());
6069
6070 Script::Compile(v8_str("y = 42"))->Run();
6071 CHECK_EQ(1, shadow_y_setter_call_count);
6072 value = Script::Compile(v8_str("y"))->Run();
6073 CHECK_EQ(1, shadow_y_getter_call_count);
6074 CHECK_EQ(42, value->Int32Value());
6075}
6076
6077
6078THREADED_TEST(HiddenPrototype) {
6079 v8::HandleScope handle_scope;
6080 LocalContext context;
6081
6082 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6083 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6084 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6085 t1->SetHiddenPrototype(true);
6086 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6087 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6088 t2->SetHiddenPrototype(true);
6089 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6090 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6091 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6092
6093 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6094 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6095 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6096 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6097
6098 // Setting the prototype on an object skips hidden prototypes.
6099 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6100 o0->Set(v8_str("__proto__"), o1);
6101 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6102 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6103 o0->Set(v8_str("__proto__"), o2);
6104 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6105 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6106 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6107 o0->Set(v8_str("__proto__"), o3);
6108 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6109 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6110 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6111 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6112
6113 // Getting the prototype of o0 should get the first visible one
6114 // which is o3. Therefore, z should not be defined on the prototype
6115 // object.
6116 Local<Value> proto = o0->Get(v8_str("__proto__"));
6117 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006118 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006119}
6120
6121
ager@chromium.org5c838252010-02-19 08:53:10 +00006122THREADED_TEST(SetPrototype) {
6123 v8::HandleScope handle_scope;
6124 LocalContext context;
6125
6126 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6127 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6128 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6129 t1->SetHiddenPrototype(true);
6130 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6131 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6132 t2->SetHiddenPrototype(true);
6133 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6134 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6135 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6136
6137 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6138 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6139 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6140 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6141
6142 // Setting the prototype on an object does not skip hidden prototypes.
6143 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6144 CHECK(o0->SetPrototype(o1));
6145 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6146 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6147 CHECK(o1->SetPrototype(o2));
6148 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6149 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6150 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6151 CHECK(o2->SetPrototype(o3));
6152 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6153 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6154 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6155 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6156
6157 // Getting the prototype of o0 should get the first visible one
6158 // which is o3. Therefore, z should not be defined on the prototype
6159 // object.
6160 Local<Value> proto = o0->Get(v8_str("__proto__"));
6161 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006162 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006163
6164 // However, Object::GetPrototype ignores hidden prototype.
6165 Local<Value> proto0 = o0->GetPrototype();
6166 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006168
6169 Local<Value> proto1 = o1->GetPrototype();
6170 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006172
6173 Local<Value> proto2 = o2->GetPrototype();
6174 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006176}
6177
6178
6179THREADED_TEST(SetPrototypeThrows) {
6180 v8::HandleScope handle_scope;
6181 LocalContext context;
6182
6183 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6184
6185 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6186 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6187
6188 CHECK(o0->SetPrototype(o1));
6189 // If setting the prototype leads to the cycle, SetPrototype should
6190 // return false and keep VM in sane state.
6191 v8::TryCatch try_catch;
6192 CHECK(!o1->SetPrototype(o0));
6193 CHECK(!try_catch.HasCaught());
6194 ASSERT(!i::Top::has_pending_exception());
6195
6196 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6197}
6198
6199
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006200THREADED_TEST(GetterSetterExceptions) {
6201 v8::HandleScope handle_scope;
6202 LocalContext context;
6203 CompileRun(
6204 "function Foo() { };"
6205 "function Throw() { throw 5; };"
6206 "var x = { };"
6207 "x.__defineSetter__('set', Throw);"
6208 "x.__defineGetter__('get', Throw);");
6209 Local<v8::Object> x =
6210 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6211 v8::TryCatch try_catch;
6212 x->Set(v8_str("set"), v8::Integer::New(8));
6213 x->Get(v8_str("get"));
6214 x->Set(v8_str("set"), v8::Integer::New(8));
6215 x->Get(v8_str("get"));
6216 x->Set(v8_str("set"), v8::Integer::New(8));
6217 x->Get(v8_str("get"));
6218 x->Set(v8_str("set"), v8::Integer::New(8));
6219 x->Get(v8_str("get"));
6220}
6221
6222
6223THREADED_TEST(Constructor) {
6224 v8::HandleScope handle_scope;
6225 LocalContext context;
6226 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6227 templ->SetClassName(v8_str("Fun"));
6228 Local<Function> cons = templ->GetFunction();
6229 context->Global()->Set(v8_str("Fun"), cons);
6230 Local<v8::Object> inst = cons->NewInstance();
6231 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6232 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6233 CHECK(value->BooleanValue());
6234}
6235
6236THREADED_TEST(FunctionDescriptorException) {
6237 v8::HandleScope handle_scope;
6238 LocalContext context;
6239 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6240 templ->SetClassName(v8_str("Fun"));
6241 Local<Function> cons = templ->GetFunction();
6242 context->Global()->Set(v8_str("Fun"), cons);
6243 Local<Value> value = CompileRun(
6244 "function test() {"
6245 " try {"
6246 " (new Fun()).blah()"
6247 " } catch (e) {"
6248 " var str = String(e);"
6249 " if (str.indexOf('TypeError') == -1) return 1;"
6250 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00006251 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006252 " return 0;"
6253 " }"
6254 " return 4;"
6255 "}"
6256 "test();");
6257 CHECK_EQ(0, value->Int32Value());
6258}
6259
6260
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006261THREADED_TEST(EvalAliasedDynamic) {
6262 v8::HandleScope scope;
6263 LocalContext current;
6264
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006265 // Tests where aliased eval can only be resolved dynamically.
6266 Local<Script> script =
6267 Script::Compile(v8_str("function f(x) { "
6268 " var foo = 2;"
6269 " with (x) { return eval('foo'); }"
6270 "}"
6271 "foo = 0;"
6272 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006273 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006274 "var x = new Object();"
6275 "x.eval = function(x) { return 1; };"
6276 "result3 = f(x);"));
6277 script->Run();
6278 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6279 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6280 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6281
6282 v8::TryCatch try_catch;
6283 script =
6284 Script::Compile(v8_str("function f(x) { "
6285 " var bar = 2;"
6286 " with (x) { return eval('bar'); }"
6287 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006288 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006289 script->Run();
6290 CHECK(try_catch.HasCaught());
6291 try_catch.Reset();
6292}
6293
6294
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006295THREADED_TEST(CrossEval) {
6296 v8::HandleScope scope;
6297 LocalContext other;
6298 LocalContext current;
6299
6300 Local<String> token = v8_str("<security token>");
6301 other->SetSecurityToken(token);
6302 current->SetSecurityToken(token);
6303
6304 // Setup reference from current to other.
6305 current->Global()->Set(v8_str("other"), other->Global());
6306
6307 // Check that new variables are introduced in other context.
6308 Local<Script> script =
6309 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6310 script->Run();
6311 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6312 CHECK_EQ(1234, foo->Int32Value());
6313 CHECK(!current->Global()->Has(v8_str("foo")));
6314
6315 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006316 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006317 script =
6318 Script::Compile(v8_str("other.eval('na = 1234')"));
6319 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006320 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6321 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006322
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006323 // Check that global variables in current context are not visible in other
6324 // context.
6325 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006326 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006327 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006328 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006329 CHECK(try_catch.HasCaught());
6330 try_catch.Reset();
6331
6332 // Check that local variables in current context are not visible in other
6333 // context.
6334 script =
6335 Script::Compile(v8_str("(function() { "
6336 " var baz = 87;"
6337 " return other.eval('baz');"
6338 "})();"));
6339 result = script->Run();
6340 CHECK(try_catch.HasCaught());
6341 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006342
6343 // Check that global variables in the other environment are visible
6344 // when evaluting code.
6345 other->Global()->Set(v8_str("bis"), v8_num(1234));
6346 script = Script::Compile(v8_str("other.eval('bis')"));
6347 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006348 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006349
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006350 // Check that the 'this' pointer points to the global object evaluating
6351 // code.
6352 other->Global()->Set(v8_str("t"), other->Global());
6353 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006354 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006355 CHECK(result->IsTrue());
6356 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 variables introduced in with-statement are not visible in
6359 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006360 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006361 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006362 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006363 CHECK(try_catch.HasCaught());
6364 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006365
6366 // Check that you cannot use 'eval.call' with another object than the
6367 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006368 script =
6369 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6370 result = script->Run();
6371 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006372}
6373
6374
ager@chromium.orge2902be2009-06-08 12:21:35 +00006375// Test that calling eval in a context which has been detached from
6376// its global throws an exception. This behavior is consistent with
6377// other JavaScript implementations.
6378THREADED_TEST(EvalInDetachedGlobal) {
6379 v8::HandleScope scope;
6380
6381 v8::Persistent<Context> context0 = Context::New();
6382 v8::Persistent<Context> context1 = Context::New();
6383
6384 // Setup function in context0 that uses eval from context0.
6385 context0->Enter();
6386 v8::Handle<v8::Value> fun =
6387 CompileRun("var x = 42;"
6388 "(function() {"
6389 " var e = eval;"
6390 " return function(s) { return e(s); }"
6391 "})()");
6392 context0->Exit();
6393
6394 // Put the function into context1 and call it before and after
6395 // detaching the global. Before detaching, the call succeeds and
6396 // after detaching and exception is thrown.
6397 context1->Enter();
6398 context1->Global()->Set(v8_str("fun"), fun);
6399 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6400 CHECK_EQ(42, x_value->Int32Value());
6401 context0->DetachGlobal();
6402 v8::TryCatch catcher;
6403 x_value = CompileRun("fun('x')");
6404 CHECK(x_value.IsEmpty());
6405 CHECK(catcher.HasCaught());
6406 context1->Exit();
6407
6408 context1.Dispose();
6409 context0.Dispose();
6410}
6411
6412
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006413THREADED_TEST(CrossLazyLoad) {
6414 v8::HandleScope scope;
6415 LocalContext other;
6416 LocalContext current;
6417
6418 Local<String> token = v8_str("<security token>");
6419 other->SetSecurityToken(token);
6420 current->SetSecurityToken(token);
6421
6422 // Setup reference from current to other.
6423 current->Global()->Set(v8_str("other"), other->Global());
6424
6425 // Trigger lazy loading in other context.
6426 Local<Script> script =
6427 Script::Compile(v8_str("other.eval('new Date(42)')"));
6428 Local<Value> value = script->Run();
6429 CHECK_EQ(42.0, value->NumberValue());
6430}
6431
6432
6433static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6434 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006435 if (args.IsConstructCall()) {
6436 if (args[0]->IsInt32()) {
6437 return v8_num(-args[0]->Int32Value());
6438 }
6439 }
6440
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006441 return args[0];
6442}
6443
6444
6445// Test that a call handler can be set for objects which will allow
6446// non-function objects created through the API to be called as
6447// functions.
6448THREADED_TEST(CallAsFunction) {
6449 v8::HandleScope scope;
6450 LocalContext context;
6451
6452 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6453 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6454 instance_template->SetCallAsFunctionHandler(call_as_function);
6455 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6456 context->Global()->Set(v8_str("obj"), instance);
6457 v8::TryCatch try_catch;
6458 Local<Value> value;
6459 CHECK(!try_catch.HasCaught());
6460
ager@chromium.org9085a012009-05-11 19:22:57 +00006461 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006462 CHECK(!try_catch.HasCaught());
6463 CHECK_EQ(42, value->Int32Value());
6464
ager@chromium.org9085a012009-05-11 19:22:57 +00006465 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006466 CHECK(!try_catch.HasCaught());
6467 CHECK_EQ(49, value->Int32Value());
6468
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006469 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00006470 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006471 CHECK(!try_catch.HasCaught());
6472 CHECK_EQ(45, value->Int32Value());
6473
ager@chromium.org9085a012009-05-11 19:22:57 +00006474 value = CompileRun("obj.call = Function.prototype.call;"
6475 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006476 CHECK(!try_catch.HasCaught());
6477 CHECK_EQ(87, value->Int32Value());
6478
6479 // Regression tests for bug #1116356: Calling call through call/apply
6480 // must work for non-function receivers.
6481 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00006482 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006483 CHECK(!try_catch.HasCaught());
6484 CHECK_EQ(99, value->Int32Value());
6485
6486 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00006487 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006488 CHECK(!try_catch.HasCaught());
6489 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00006490
6491 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006492 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006493 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00006494 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006495 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006496}
6497
6498
6499static int CountHandles() {
6500 return v8::HandleScope::NumberOfHandles();
6501}
6502
6503
6504static int Recurse(int depth, int iterations) {
6505 v8::HandleScope scope;
6506 if (depth == 0) return CountHandles();
6507 for (int i = 0; i < iterations; i++) {
6508 Local<v8::Number> n = v8::Integer::New(42);
6509 }
6510 return Recurse(depth - 1, iterations);
6511}
6512
6513
6514THREADED_TEST(HandleIteration) {
6515 static const int kIterations = 500;
6516 static const int kNesting = 200;
6517 CHECK_EQ(0, CountHandles());
6518 {
6519 v8::HandleScope scope1;
6520 CHECK_EQ(0, CountHandles());
6521 for (int i = 0; i < kIterations; i++) {
6522 Local<v8::Number> n = v8::Integer::New(42);
6523 CHECK_EQ(i + 1, CountHandles());
6524 }
6525
6526 CHECK_EQ(kIterations, CountHandles());
6527 {
6528 v8::HandleScope scope2;
6529 for (int j = 0; j < kIterations; j++) {
6530 Local<v8::Number> n = v8::Integer::New(42);
6531 CHECK_EQ(j + 1 + kIterations, CountHandles());
6532 }
6533 }
6534 CHECK_EQ(kIterations, CountHandles());
6535 }
6536 CHECK_EQ(0, CountHandles());
6537 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6538}
6539
6540
6541static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6542 Local<String> name,
6543 const AccessorInfo& info) {
6544 ApiTestFuzzer::Fuzz();
6545 return v8::Handle<Value>();
6546}
6547
6548
6549THREADED_TEST(InterceptorHasOwnProperty) {
6550 v8::HandleScope scope;
6551 LocalContext context;
6552 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6553 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6554 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6555 Local<Function> function = fun_templ->GetFunction();
6556 context->Global()->Set(v8_str("constructor"), function);
6557 v8::Handle<Value> value = CompileRun(
6558 "var o = new constructor();"
6559 "o.hasOwnProperty('ostehaps');");
6560 CHECK_EQ(false, value->BooleanValue());
6561 value = CompileRun(
6562 "o.ostehaps = 42;"
6563 "o.hasOwnProperty('ostehaps');");
6564 CHECK_EQ(true, value->BooleanValue());
6565 value = CompileRun(
6566 "var p = new constructor();"
6567 "p.hasOwnProperty('ostehaps');");
6568 CHECK_EQ(false, value->BooleanValue());
6569}
6570
6571
ager@chromium.org9085a012009-05-11 19:22:57 +00006572static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6573 Local<String> name,
6574 const AccessorInfo& info) {
6575 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006576 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00006577 return v8::Handle<Value>();
6578}
6579
6580
6581THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6582 v8::HandleScope scope;
6583 LocalContext context;
6584 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6585 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6586 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6587 Local<Function> function = fun_templ->GetFunction();
6588 context->Global()->Set(v8_str("constructor"), function);
6589 // Let's first make some stuff so we can be sure to get a good GC.
6590 CompileRun(
6591 "function makestr(size) {"
6592 " switch (size) {"
6593 " case 1: return 'f';"
6594 " case 2: return 'fo';"
6595 " case 3: return 'foo';"
6596 " }"
6597 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6598 "}"
6599 "var x = makestr(12345);"
6600 "x = makestr(31415);"
6601 "x = makestr(23456);");
6602 v8::Handle<Value> value = CompileRun(
6603 "var o = new constructor();"
6604 "o.__proto__ = new String(x);"
6605 "o.hasOwnProperty('ostehaps');");
6606 CHECK_EQ(false, value->BooleanValue());
6607}
6608
6609
ager@chromium.orge2902be2009-06-08 12:21:35 +00006610typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6611 const AccessorInfo& info);
6612
6613
6614static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6615 const char* source,
6616 int expected) {
6617 v8::HandleScope scope;
6618 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006619 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00006620 LocalContext context;
6621 context->Global()->Set(v8_str("o"), templ->NewInstance());
6622 v8::Handle<Value> value = CompileRun(source);
6623 CHECK_EQ(expected, value->Int32Value());
6624}
6625
6626
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006627static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6628 const AccessorInfo& info) {
6629 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006630 CHECK_EQ(v8_str("data"), info.Data());
6631 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006632 return v8::Integer::New(42);
6633}
6634
6635
6636// This test should hit the load IC for the interceptor case.
6637THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00006638 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006639 "var result = 0;"
6640 "for (var i = 0; i < 1000; i++) {"
6641 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006642 "}",
6643 42);
6644}
6645
6646
6647// Below go several tests which verify that JITing for various
6648// configurations of interceptor and explicit fields works fine
6649// (those cases are special cased to get better performance).
6650
6651static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6652 const AccessorInfo& info) {
6653 ApiTestFuzzer::Fuzz();
6654 return v8_str("x")->Equals(name)
6655 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6656}
6657
6658
6659THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6660 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6661 "var result = 0;"
6662 "o.y = 239;"
6663 "for (var i = 0; i < 1000; i++) {"
6664 " result = o.y;"
6665 "}",
6666 239);
6667}
6668
6669
6670THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6671 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6672 "var result = 0;"
6673 "o.__proto__ = { 'y': 239 };"
6674 "for (var i = 0; i < 1000; i++) {"
6675 " result = o.y + o.x;"
6676 "}",
6677 239 + 42);
6678}
6679
6680
6681THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6682 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6683 "var result = 0;"
6684 "o.__proto__.y = 239;"
6685 "for (var i = 0; i < 1000; i++) {"
6686 " result = o.y + o.x;"
6687 "}",
6688 239 + 42);
6689}
6690
6691
6692THREADED_TEST(InterceptorLoadICUndefined) {
6693 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6694 "var result = 0;"
6695 "for (var i = 0; i < 1000; i++) {"
6696 " result = (o.y == undefined) ? 239 : 42;"
6697 "}",
6698 239);
6699}
6700
6701
6702THREADED_TEST(InterceptorLoadICWithOverride) {
6703 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6704 "fst = new Object(); fst.__proto__ = o;"
6705 "snd = new Object(); snd.__proto__ = fst;"
6706 "var result1 = 0;"
6707 "for (var i = 0; i < 1000; i++) {"
6708 " result1 = snd.x;"
6709 "}"
6710 "fst.x = 239;"
6711 "var result = 0;"
6712 "for (var i = 0; i < 1000; i++) {"
6713 " result = snd.x;"
6714 "}"
6715 "result + result1",
6716 239 + 42);
6717}
6718
6719
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006720// Test the case when we stored field into
6721// a stub, but interceptor produced value on its own.
6722THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6723 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6724 "proto = new Object();"
6725 "o.__proto__ = proto;"
6726 "proto.x = 239;"
6727 "for (var i = 0; i < 1000; i++) {"
6728 " o.x;"
6729 // Now it should be ICed and keep a reference to x defined on proto
6730 "}"
6731 "var result = 0;"
6732 "for (var i = 0; i < 1000; i++) {"
6733 " result += o.x;"
6734 "}"
6735 "result;",
6736 42 * 1000);
6737}
6738
6739
6740// Test the case when we stored field into
6741// a stub, but it got invalidated later on.
6742THREADED_TEST(InterceptorLoadICInvalidatedField) {
6743 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6744 "proto1 = new Object();"
6745 "proto2 = new Object();"
6746 "o.__proto__ = proto1;"
6747 "proto1.__proto__ = proto2;"
6748 "proto2.y = 239;"
6749 "for (var i = 0; i < 1000; i++) {"
6750 " o.y;"
6751 // Now it should be ICed and keep a reference to y defined on proto2
6752 "}"
6753 "proto1.y = 42;"
6754 "var result = 0;"
6755 "for (var i = 0; i < 1000; i++) {"
6756 " result += o.y;"
6757 "}"
6758 "result;",
6759 42 * 1000);
6760}
6761
6762
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00006763static int interceptor_load_not_handled_calls = 0;
6764static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6765 const AccessorInfo& info) {
6766 ++interceptor_load_not_handled_calls;
6767 return v8::Handle<v8::Value>();
6768}
6769
6770
6771// Test how post-interceptor lookups are done in the non-cacheable
6772// case: the interceptor should not be invoked during this lookup.
6773THREADED_TEST(InterceptorLoadICPostInterceptor) {
6774 interceptor_load_not_handled_calls = 0;
6775 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6776 "receiver = new Object();"
6777 "receiver.__proto__ = o;"
6778 "proto = new Object();"
6779 "/* Make proto a slow-case object. */"
6780 "for (var i = 0; i < 1000; i++) {"
6781 " proto[\"xxxxxxxx\" + i] = [];"
6782 "}"
6783 "proto.x = 17;"
6784 "o.__proto__ = proto;"
6785 "var result = 0;"
6786 "for (var i = 0; i < 1000; i++) {"
6787 " result += receiver.x;"
6788 "}"
6789 "result;",
6790 17 * 1000);
6791 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6792}
6793
6794
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006795// Test the case when we stored field into
6796// a stub, but it got invalidated later on due to override on
6797// global object which is between interceptor and fields' holders.
6798THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6799 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6800 "o.__proto__ = this;" // set a global to be a proto of o.
6801 "this.__proto__.y = 239;"
6802 "for (var i = 0; i < 10; i++) {"
6803 " if (o.y != 239) throw 'oops: ' + o.y;"
6804 // Now it should be ICed and keep a reference to y defined on field_holder.
6805 "}"
6806 "this.y = 42;" // Assign on a global.
6807 "var result = 0;"
6808 "for (var i = 0; i < 10; i++) {"
6809 " result += o.y;"
6810 "}"
6811 "result;",
6812 42 * 10);
6813}
6814
6815
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006816static void SetOnThis(Local<String> name,
6817 Local<Value> value,
6818 const AccessorInfo& info) {
6819 info.This()->ForceSet(name, value);
6820}
6821
6822
6823THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6824 v8::HandleScope scope;
6825 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6826 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6827 templ->SetAccessor(v8_str("y"), Return239);
6828 LocalContext context;
6829 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006830
6831 // Check the case when receiver and interceptor's holder
6832 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006833 v8::Handle<Value> value = CompileRun(
6834 "var result = 0;"
6835 "for (var i = 0; i < 7; i++) {"
6836 " result = o.y;"
6837 "}");
6838 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006839
6840 // Check the case when interceptor's holder is in proto chain
6841 // of receiver.
6842 value = CompileRun(
6843 "r = { __proto__: o };"
6844 "var result = 0;"
6845 "for (var i = 0; i < 7; i++) {"
6846 " result = r.y;"
6847 "}");
6848 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006849}
6850
6851
6852THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6853 v8::HandleScope scope;
6854 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6855 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6856 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6857 templ_p->SetAccessor(v8_str("y"), Return239);
6858
6859 LocalContext context;
6860 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6861 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6862
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006863 // Check the case when receiver and interceptor's holder
6864 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006865 v8::Handle<Value> value = CompileRun(
6866 "o.__proto__ = p;"
6867 "var result = 0;"
6868 "for (var i = 0; i < 7; i++) {"
6869 " result = o.x + o.y;"
6870 "}");
6871 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006872
6873 // Check the case when interceptor's holder is in proto chain
6874 // of receiver.
6875 value = CompileRun(
6876 "r = { __proto__: o };"
6877 "var result = 0;"
6878 "for (var i = 0; i < 7; i++) {"
6879 " result = r.x + r.y;"
6880 "}");
6881 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006882}
6883
6884
6885THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6886 v8::HandleScope scope;
6887 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6888 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6889 templ->SetAccessor(v8_str("y"), Return239);
6890
6891 LocalContext context;
6892 context->Global()->Set(v8_str("o"), templ->NewInstance());
6893
6894 v8::Handle<Value> value = CompileRun(
6895 "fst = new Object(); fst.__proto__ = o;"
6896 "snd = new Object(); snd.__proto__ = fst;"
6897 "var result1 = 0;"
6898 "for (var i = 0; i < 7; i++) {"
6899 " result1 = snd.x;"
6900 "}"
6901 "fst.x = 239;"
6902 "var result = 0;"
6903 "for (var i = 0; i < 7; i++) {"
6904 " result = snd.x;"
6905 "}"
6906 "result + result1");
6907 CHECK_EQ(239 + 42, value->Int32Value());
6908}
6909
6910
6911// Test the case when we stored callback into
6912// a stub, but interceptor produced value on its own.
6913THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6914 v8::HandleScope scope;
6915 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6916 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6917 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6918 templ_p->SetAccessor(v8_str("y"), Return239);
6919
6920 LocalContext context;
6921 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6922 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6923
6924 v8::Handle<Value> value = CompileRun(
6925 "o.__proto__ = p;"
6926 "for (var i = 0; i < 7; i++) {"
6927 " o.x;"
6928 // Now it should be ICed and keep a reference to x defined on p
6929 "}"
6930 "var result = 0;"
6931 "for (var i = 0; i < 7; i++) {"
6932 " result += o.x;"
6933 "}"
6934 "result");
6935 CHECK_EQ(42 * 7, value->Int32Value());
6936}
6937
6938
6939// Test the case when we stored callback into
6940// a stub, but it got invalidated later on.
6941THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6942 v8::HandleScope scope;
6943 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6944 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6945 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6946 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6947
6948 LocalContext context;
6949 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6950 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6951
6952 v8::Handle<Value> value = CompileRun(
6953 "inbetween = new Object();"
6954 "o.__proto__ = inbetween;"
6955 "inbetween.__proto__ = p;"
6956 "for (var i = 0; i < 10; i++) {"
6957 " o.y;"
6958 // Now it should be ICed and keep a reference to y defined on p
6959 "}"
6960 "inbetween.y = 42;"
6961 "var result = 0;"
6962 "for (var i = 0; i < 10; i++) {"
6963 " result += o.y;"
6964 "}"
6965 "result");
6966 CHECK_EQ(42 * 10, value->Int32Value());
6967}
6968
6969
6970// Test the case when we stored callback into
6971// a stub, but it got invalidated later on due to override on
6972// global object which is between interceptor and callbacks' holders.
6973THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6974 v8::HandleScope scope;
6975 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6976 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6977 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6978 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6979
6980 LocalContext context;
6981 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6982 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6983
6984 v8::Handle<Value> value = CompileRun(
6985 "o.__proto__ = this;"
6986 "this.__proto__ = p;"
6987 "for (var i = 0; i < 10; i++) {"
6988 " if (o.y != 239) throw 'oops: ' + o.y;"
6989 // Now it should be ICed and keep a reference to y defined on p
6990 "}"
6991 "this.y = 42;"
6992 "var result = 0;"
6993 "for (var i = 0; i < 10; i++) {"
6994 " result += o.y;"
6995 "}"
6996 "result");
6997 CHECK_EQ(42 * 10, value->Int32Value());
6998}
6999
7000
ager@chromium.orge2902be2009-06-08 12:21:35 +00007001static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7002 const AccessorInfo& info) {
7003 ApiTestFuzzer::Fuzz();
7004 CHECK(v8_str("x")->Equals(name));
7005 return v8::Integer::New(0);
7006}
7007
7008
7009THREADED_TEST(InterceptorReturningZero) {
7010 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7011 "o.x == undefined ? 1 : 0",
7012 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007013}
7014
7015
7016static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007017 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007018 CHECK(v8_str("x")->Equals(key));
7019 CHECK_EQ(42, value->Int32Value());
7020 return value;
7021}
7022
7023
7024// This test should hit the store IC for the interceptor case.
7025THREADED_TEST(InterceptorStoreIC) {
7026 v8::HandleScope scope;
7027 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7028 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007029 InterceptorStoreICSetter,
7030 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007031 LocalContext context;
7032 context->Global()->Set(v8_str("o"), templ->NewInstance());
7033 v8::Handle<Value> value = CompileRun(
7034 "for (var i = 0; i < 1000; i++) {"
7035 " o.x = 42;"
7036 "}");
7037}
7038
7039
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007040THREADED_TEST(InterceptorStoreICWithNoSetter) {
7041 v8::HandleScope scope;
7042 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7043 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7044 LocalContext context;
7045 context->Global()->Set(v8_str("o"), templ->NewInstance());
7046 v8::Handle<Value> value = CompileRun(
7047 "for (var i = 0; i < 1000; i++) {"
7048 " o.y = 239;"
7049 "}"
7050 "42 + o.y");
7051 CHECK_EQ(239 + 42, value->Int32Value());
7052}
7053
7054
7055
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007056
7057v8::Handle<Value> call_ic_function;
7058v8::Handle<Value> call_ic_function2;
7059v8::Handle<Value> call_ic_function3;
7060
7061static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7062 const AccessorInfo& info) {
7063 ApiTestFuzzer::Fuzz();
7064 CHECK(v8_str("x")->Equals(name));
7065 return call_ic_function;
7066}
7067
7068
7069// This test should hit the call IC for the interceptor case.
7070THREADED_TEST(InterceptorCallIC) {
7071 v8::HandleScope scope;
7072 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7073 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7074 LocalContext context;
7075 context->Global()->Set(v8_str("o"), templ->NewInstance());
7076 call_ic_function =
7077 v8_compile("function f(x) { return x + 1; }; f")->Run();
7078 v8::Handle<Value> value = CompileRun(
7079 "var result = 0;"
7080 "for (var i = 0; i < 1000; i++) {"
7081 " result = o.x(41);"
7082 "}");
7083 CHECK_EQ(42, value->Int32Value());
7084}
7085
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007086
7087// This test checks that if interceptor doesn't provide
7088// a value, we can fetch regular value.
7089THREADED_TEST(InterceptorCallICSeesOthers) {
7090 v8::HandleScope scope;
7091 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7092 templ->SetNamedPropertyHandler(NoBlockGetterX);
7093 LocalContext context;
7094 context->Global()->Set(v8_str("o"), templ->NewInstance());
7095 v8::Handle<Value> value = CompileRun(
7096 "o.x = function f(x) { return x + 1; };"
7097 "var result = 0;"
7098 "for (var i = 0; i < 7; i++) {"
7099 " result = o.x(41);"
7100 "}");
7101 CHECK_EQ(42, value->Int32Value());
7102}
7103
7104
7105static v8::Handle<Value> call_ic_function4;
7106static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7107 const AccessorInfo& info) {
7108 ApiTestFuzzer::Fuzz();
7109 CHECK(v8_str("x")->Equals(name));
7110 return call_ic_function4;
7111}
7112
7113
7114// This test checks that if interceptor provides a function,
7115// even if we cached shadowed variant, interceptor's function
7116// is invoked
7117THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7118 v8::HandleScope scope;
7119 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7120 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7121 LocalContext context;
7122 context->Global()->Set(v8_str("o"), templ->NewInstance());
7123 call_ic_function4 =
7124 v8_compile("function f(x) { return x - 1; }; f")->Run();
7125 v8::Handle<Value> value = CompileRun(
7126 "o.__proto__.x = function(x) { return x + 1; };"
7127 "var result = 0;"
7128 "for (var i = 0; i < 1000; i++) {"
7129 " result = o.x(42);"
7130 "}");
7131 CHECK_EQ(41, value->Int32Value());
7132}
7133
7134
7135// Test the case when we stored cacheable lookup into
7136// a stub, but it got invalidated later on
7137THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7138 v8::HandleScope scope;
7139 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7140 templ->SetNamedPropertyHandler(NoBlockGetterX);
7141 LocalContext context;
7142 context->Global()->Set(v8_str("o"), templ->NewInstance());
7143 v8::Handle<Value> value = CompileRun(
7144 "proto1 = new Object();"
7145 "proto2 = new Object();"
7146 "o.__proto__ = proto1;"
7147 "proto1.__proto__ = proto2;"
7148 "proto2.y = function(x) { return x + 1; };"
7149 // Invoke it many times to compile a stub
7150 "for (var i = 0; i < 7; i++) {"
7151 " o.y(42);"
7152 "}"
7153 "proto1.y = function(x) { return x - 1; };"
7154 "var result = 0;"
7155 "for (var i = 0; i < 7; i++) {"
7156 " result += o.y(42);"
7157 "}");
7158 CHECK_EQ(41 * 7, value->Int32Value());
7159}
7160
7161
7162static v8::Handle<Value> call_ic_function5;
7163static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7164 const AccessorInfo& info) {
7165 ApiTestFuzzer::Fuzz();
7166 if (v8_str("x")->Equals(name))
7167 return call_ic_function5;
7168 else
7169 return Local<Value>();
7170}
7171
7172
7173// This test checks that if interceptor doesn't provide a function,
7174// cached constant function is used
7175THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7176 v8::HandleScope scope;
7177 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7178 templ->SetNamedPropertyHandler(NoBlockGetterX);
7179 LocalContext context;
7180 context->Global()->Set(v8_str("o"), templ->NewInstance());
7181 v8::Handle<Value> value = CompileRun(
7182 "function inc(x) { return x + 1; };"
7183 "inc(1);"
7184 "o.x = inc;"
7185 "var result = 0;"
7186 "for (var i = 0; i < 1000; i++) {"
7187 " result = o.x(42);"
7188 "}");
7189 CHECK_EQ(43, value->Int32Value());
7190}
7191
7192
7193// This test checks that if interceptor provides a function,
7194// even if we cached constant function, interceptor's function
7195// is invoked
7196THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7197 v8::HandleScope scope;
7198 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7199 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7200 LocalContext context;
7201 context->Global()->Set(v8_str("o"), templ->NewInstance());
7202 call_ic_function5 =
7203 v8_compile("function f(x) { return x - 1; }; f")->Run();
7204 v8::Handle<Value> value = CompileRun(
7205 "function inc(x) { return x + 1; };"
7206 "inc(1);"
7207 "o.x = inc;"
7208 "var result = 0;"
7209 "for (var i = 0; i < 1000; i++) {"
7210 " result = o.x(42);"
7211 "}");
7212 CHECK_EQ(41, value->Int32Value());
7213}
7214
7215
7216// Test the case when we stored constant function into
7217// a stub, but it got invalidated later on
7218THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7219 v8::HandleScope scope;
7220 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7221 templ->SetNamedPropertyHandler(NoBlockGetterX);
7222 LocalContext context;
7223 context->Global()->Set(v8_str("o"), templ->NewInstance());
7224 v8::Handle<Value> value = CompileRun(
7225 "function inc(x) { return x + 1; };"
7226 "inc(1);"
7227 "proto1 = new Object();"
7228 "proto2 = new Object();"
7229 "o.__proto__ = proto1;"
7230 "proto1.__proto__ = proto2;"
7231 "proto2.y = inc;"
7232 // Invoke it many times to compile a stub
7233 "for (var i = 0; i < 7; i++) {"
7234 " o.y(42);"
7235 "}"
7236 "proto1.y = function(x) { return x - 1; };"
7237 "var result = 0;"
7238 "for (var i = 0; i < 7; i++) {"
7239 " result += o.y(42);"
7240 "}");
7241 CHECK_EQ(41 * 7, value->Int32Value());
7242}
7243
7244
7245// Test the case when we stored constant function into
7246// a stub, but it got invalidated later on due to override on
7247// global object which is between interceptor and constant function' holders.
7248THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7249 v8::HandleScope scope;
7250 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7251 templ->SetNamedPropertyHandler(NoBlockGetterX);
7252 LocalContext context;
7253 context->Global()->Set(v8_str("o"), templ->NewInstance());
7254 v8::Handle<Value> value = CompileRun(
7255 "function inc(x) { return x + 1; };"
7256 "inc(1);"
7257 "o.__proto__ = this;"
7258 "this.__proto__.y = inc;"
7259 // Invoke it many times to compile a stub
7260 "for (var i = 0; i < 7; i++) {"
7261 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7262 "}"
7263 "this.y = function(x) { return x - 1; };"
7264 "var result = 0;"
7265 "for (var i = 0; i < 7; i++) {"
7266 " result += o.y(42);"
7267 "}");
7268 CHECK_EQ(41 * 7, value->Int32Value());
7269}
7270
7271
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007272// Test the case when actual function to call sits on global object.
7273THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7274 v8::HandleScope scope;
7275 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7276 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7277
7278 LocalContext context;
7279 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7280
7281 v8::Handle<Value> value = CompileRun(
7282 "try {"
7283 " o.__proto__ = this;"
7284 " for (var i = 0; i < 10; i++) {"
7285 " var v = o.parseFloat('239');"
7286 " if (v != 239) throw v;"
7287 // Now it should be ICed and keep a reference to parseFloat.
7288 " }"
7289 " var result = 0;"
7290 " for (var i = 0; i < 10; i++) {"
7291 " result += o.parseFloat('239');"
7292 " }"
7293 " result"
7294 "} catch(e) {"
7295 " e"
7296 "};");
7297 CHECK_EQ(239 * 10, value->Int32Value());
7298}
7299
ager@chromium.org5c838252010-02-19 08:53:10 +00007300static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7301 const AccessorInfo& info) {
7302 ApiTestFuzzer::Fuzz();
7303 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7304 ++(*call_count);
7305 if ((*call_count) % 20 == 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00007306 i::Heap::CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00007307 }
7308 return v8::Handle<Value>();
7309}
7310
7311static v8::Handle<Value> FastApiCallback_TrivialSignature(
7312 const v8::Arguments& args) {
7313 ApiTestFuzzer::Fuzz();
7314 CHECK_EQ(args.This(), args.Holder());
7315 CHECK(args.Data()->Equals(v8_str("method_data")));
7316 return v8::Integer::New(args[0]->Int32Value() + 1);
7317}
7318
7319static v8::Handle<Value> FastApiCallback_SimpleSignature(
7320 const v8::Arguments& args) {
7321 ApiTestFuzzer::Fuzz();
7322 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7323 CHECK(args.Data()->Equals(v8_str("method_data")));
7324 // Note, we're using HasRealNamedProperty instead of Has to avoid
7325 // invoking the interceptor again.
7326 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7327 return v8::Integer::New(args[0]->Int32Value() + 1);
7328}
7329
7330// Helper to maximize the odds of object moving.
7331static void GenerateSomeGarbage() {
7332 CompileRun(
7333 "var garbage;"
7334 "for (var i = 0; i < 1000; i++) {"
7335 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7336 "}"
7337 "garbage = undefined;");
7338}
7339
7340THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7341 int interceptor_call_count = 0;
7342 v8::HandleScope scope;
7343 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7344 v8::Handle<v8::FunctionTemplate> method_templ =
7345 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7346 v8_str("method_data"),
7347 v8::Handle<v8::Signature>());
7348 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7349 proto_templ->Set(v8_str("method"), method_templ);
7350 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7351 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7352 NULL, NULL, NULL, NULL,
7353 v8::External::Wrap(&interceptor_call_count));
7354 LocalContext context;
7355 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7356 GenerateSomeGarbage();
7357 context->Global()->Set(v8_str("o"), fun->NewInstance());
7358 v8::Handle<Value> value = CompileRun(
7359 "var result = 0;"
7360 "for (var i = 0; i < 100; i++) {"
7361 " result = o.method(41);"
7362 "}");
7363 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7364 CHECK_EQ(100, interceptor_call_count);
7365}
7366
7367THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7368 int interceptor_call_count = 0;
7369 v8::HandleScope scope;
7370 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7371 v8::Handle<v8::FunctionTemplate> method_templ =
7372 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7373 v8_str("method_data"),
7374 v8::Signature::New(fun_templ));
7375 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7376 proto_templ->Set(v8_str("method"), method_templ);
7377 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7378 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7379 NULL, NULL, NULL, NULL,
7380 v8::External::Wrap(&interceptor_call_count));
7381 LocalContext context;
7382 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7383 GenerateSomeGarbage();
7384 context->Global()->Set(v8_str("o"), fun->NewInstance());
7385 v8::Handle<Value> value = CompileRun(
7386 "o.foo = 17;"
7387 "var receiver = {};"
7388 "receiver.__proto__ = o;"
7389 "var result = 0;"
7390 "for (var i = 0; i < 100; i++) {"
7391 " result = receiver.method(41);"
7392 "}");
7393 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7394 CHECK_EQ(100, interceptor_call_count);
7395}
7396
7397THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7398 int interceptor_call_count = 0;
7399 v8::HandleScope scope;
7400 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7401 v8::Handle<v8::FunctionTemplate> method_templ =
7402 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7403 v8_str("method_data"),
7404 v8::Signature::New(fun_templ));
7405 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7406 proto_templ->Set(v8_str("method"), method_templ);
7407 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7408 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7409 NULL, NULL, NULL, NULL,
7410 v8::External::Wrap(&interceptor_call_count));
7411 LocalContext context;
7412 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7413 GenerateSomeGarbage();
7414 context->Global()->Set(v8_str("o"), fun->NewInstance());
7415 v8::Handle<Value> value = CompileRun(
7416 "o.foo = 17;"
7417 "var receiver = {};"
7418 "receiver.__proto__ = o;"
7419 "var result = 0;"
7420 "var saved_result = 0;"
7421 "for (var i = 0; i < 100; i++) {"
7422 " result = receiver.method(41);"
7423 " if (i == 50) {"
7424 " saved_result = result;"
7425 " receiver = {method: function(x) { return x - 1 }};"
7426 " }"
7427 "}");
7428 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7429 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7430 CHECK_GE(interceptor_call_count, 50);
7431}
7432
7433THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7434 int interceptor_call_count = 0;
7435 v8::HandleScope scope;
7436 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7437 v8::Handle<v8::FunctionTemplate> method_templ =
7438 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7439 v8_str("method_data"),
7440 v8::Signature::New(fun_templ));
7441 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7442 proto_templ->Set(v8_str("method"), method_templ);
7443 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7444 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7445 NULL, NULL, NULL, NULL,
7446 v8::External::Wrap(&interceptor_call_count));
7447 LocalContext context;
7448 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7449 GenerateSomeGarbage();
7450 context->Global()->Set(v8_str("o"), fun->NewInstance());
7451 v8::Handle<Value> value = CompileRun(
7452 "o.foo = 17;"
7453 "var receiver = {};"
7454 "receiver.__proto__ = o;"
7455 "var result = 0;"
7456 "var saved_result = 0;"
7457 "for (var i = 0; i < 100; i++) {"
7458 " result = receiver.method(41);"
7459 " if (i == 50) {"
7460 " saved_result = result;"
7461 " o.method = function(x) { return x - 1 };"
7462 " }"
7463 "}");
7464 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7465 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7466 CHECK_GE(interceptor_call_count, 50);
7467}
7468
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007469THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7470 int interceptor_call_count = 0;
7471 v8::HandleScope scope;
7472 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7473 v8::Handle<v8::FunctionTemplate> method_templ =
7474 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7475 v8_str("method_data"),
7476 v8::Signature::New(fun_templ));
7477 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7478 proto_templ->Set(v8_str("method"), method_templ);
7479 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7480 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7481 NULL, NULL, NULL, NULL,
7482 v8::External::Wrap(&interceptor_call_count));
7483 LocalContext context;
7484 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7485 GenerateSomeGarbage();
7486 context->Global()->Set(v8_str("o"), fun->NewInstance());
7487 v8::TryCatch try_catch;
7488 v8::Handle<Value> value = CompileRun(
7489 "o.foo = 17;"
7490 "var receiver = {};"
7491 "receiver.__proto__ = o;"
7492 "var result = 0;"
7493 "var saved_result = 0;"
7494 "for (var i = 0; i < 100; i++) {"
7495 " result = receiver.method(41);"
7496 " if (i == 50) {"
7497 " saved_result = result;"
7498 " receiver = 333;"
7499 " }"
7500 "}");
7501 CHECK(try_catch.HasCaught());
7502 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7503 try_catch.Exception()->ToString());
7504 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7505 CHECK_GE(interceptor_call_count, 50);
7506}
7507
ager@chromium.org5c838252010-02-19 08:53:10 +00007508THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7509 int interceptor_call_count = 0;
7510 v8::HandleScope scope;
7511 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7512 v8::Handle<v8::FunctionTemplate> method_templ =
7513 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7514 v8_str("method_data"),
7515 v8::Signature::New(fun_templ));
7516 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7517 proto_templ->Set(v8_str("method"), method_templ);
7518 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7519 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7520 NULL, NULL, NULL, NULL,
7521 v8::External::Wrap(&interceptor_call_count));
7522 LocalContext context;
7523 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7524 GenerateSomeGarbage();
7525 context->Global()->Set(v8_str("o"), fun->NewInstance());
7526 v8::TryCatch try_catch;
7527 v8::Handle<Value> value = CompileRun(
7528 "o.foo = 17;"
7529 "var receiver = {};"
7530 "receiver.__proto__ = o;"
7531 "var result = 0;"
7532 "var saved_result = 0;"
7533 "for (var i = 0; i < 100; i++) {"
7534 " result = receiver.method(41);"
7535 " if (i == 50) {"
7536 " saved_result = result;"
7537 " receiver = {method: receiver.method};"
7538 " }"
7539 "}");
7540 CHECK(try_catch.HasCaught());
7541 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7542 try_catch.Exception()->ToString());
7543 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7544 CHECK_GE(interceptor_call_count, 50);
7545}
7546
7547THREADED_TEST(CallICFastApi_TrivialSignature) {
7548 v8::HandleScope scope;
7549 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7550 v8::Handle<v8::FunctionTemplate> method_templ =
7551 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7552 v8_str("method_data"),
7553 v8::Handle<v8::Signature>());
7554 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7555 proto_templ->Set(v8_str("method"), method_templ);
7556 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7557 LocalContext context;
7558 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7559 GenerateSomeGarbage();
7560 context->Global()->Set(v8_str("o"), fun->NewInstance());
7561 v8::Handle<Value> value = CompileRun(
7562 "var result = 0;"
7563 "for (var i = 0; i < 100; i++) {"
7564 " result = o.method(41);"
7565 "}");
7566
7567 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7568}
7569
7570THREADED_TEST(CallICFastApi_SimpleSignature) {
7571 v8::HandleScope scope;
7572 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7573 v8::Handle<v8::FunctionTemplate> method_templ =
7574 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7575 v8_str("method_data"),
7576 v8::Signature::New(fun_templ));
7577 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7578 proto_templ->Set(v8_str("method"), method_templ);
7579 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7580 LocalContext context;
7581 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7582 GenerateSomeGarbage();
7583 context->Global()->Set(v8_str("o"), fun->NewInstance());
7584 v8::Handle<Value> value = CompileRun(
7585 "o.foo = 17;"
7586 "var receiver = {};"
7587 "receiver.__proto__ = o;"
7588 "var result = 0;"
7589 "for (var i = 0; i < 100; i++) {"
7590 " result = receiver.method(41);"
7591 "}");
7592
7593 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7594}
7595
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007596THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007597 v8::HandleScope scope;
7598 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7599 v8::Handle<v8::FunctionTemplate> method_templ =
7600 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7601 v8_str("method_data"),
7602 v8::Signature::New(fun_templ));
7603 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7604 proto_templ->Set(v8_str("method"), method_templ);
7605 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7606 LocalContext context;
7607 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7608 GenerateSomeGarbage();
7609 context->Global()->Set(v8_str("o"), fun->NewInstance());
7610 v8::Handle<Value> value = CompileRun(
7611 "o.foo = 17;"
7612 "var receiver = {};"
7613 "receiver.__proto__ = o;"
7614 "var result = 0;"
7615 "var saved_result = 0;"
7616 "for (var i = 0; i < 100; i++) {"
7617 " result = receiver.method(41);"
7618 " if (i == 50) {"
7619 " saved_result = result;"
7620 " receiver = {method: function(x) { return x - 1 }};"
7621 " }"
7622 "}");
7623 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7624 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7625}
7626
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00007627THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7628 v8::HandleScope scope;
7629 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7630 v8::Handle<v8::FunctionTemplate> method_templ =
7631 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7632 v8_str("method_data"),
7633 v8::Signature::New(fun_templ));
7634 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7635 proto_templ->Set(v8_str("method"), method_templ);
7636 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7637 LocalContext context;
7638 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7639 GenerateSomeGarbage();
7640 context->Global()->Set(v8_str("o"), fun->NewInstance());
7641 v8::TryCatch try_catch;
7642 v8::Handle<Value> value = CompileRun(
7643 "o.foo = 17;"
7644 "var receiver = {};"
7645 "receiver.__proto__ = o;"
7646 "var result = 0;"
7647 "var saved_result = 0;"
7648 "for (var i = 0; i < 100; i++) {"
7649 " result = receiver.method(41);"
7650 " if (i == 50) {"
7651 " saved_result = result;"
7652 " receiver = 333;"
7653 " }"
7654 "}");
7655 CHECK(try_catch.HasCaught());
7656 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7657 try_catch.Exception()->ToString());
7658 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7659}
7660
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007661
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007662v8::Handle<Value> keyed_call_ic_function;
7663
7664static v8::Handle<Value> InterceptorKeyedCallICGetter(
7665 Local<String> name, const AccessorInfo& info) {
7666 ApiTestFuzzer::Fuzz();
7667 if (v8_str("x")->Equals(name)) {
7668 return keyed_call_ic_function;
7669 }
7670 return v8::Handle<Value>();
7671}
7672
7673
7674// Test the case when we stored cacheable lookup into
7675// a stub, but the function name changed (to another cacheable function).
7676THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7677 v8::HandleScope scope;
7678 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7679 templ->SetNamedPropertyHandler(NoBlockGetterX);
7680 LocalContext context;
7681 context->Global()->Set(v8_str("o"), templ->NewInstance());
7682 v8::Handle<Value> value = CompileRun(
7683 "proto = new Object();"
7684 "proto.y = function(x) { return x + 1; };"
7685 "proto.z = function(x) { return x - 1; };"
7686 "o.__proto__ = proto;"
7687 "var result = 0;"
7688 "var method = 'y';"
7689 "for (var i = 0; i < 10; i++) {"
7690 " if (i == 5) { method = 'z'; };"
7691 " result += o[method](41);"
7692 "}");
7693 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7694}
7695
7696
7697// Test the case when we stored cacheable lookup into
7698// a stub, but the function name changed (and the new function is present
7699// both before and after the interceptor in the prototype chain).
7700THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7701 v8::HandleScope scope;
7702 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7703 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7704 LocalContext context;
7705 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7706 keyed_call_ic_function =
7707 v8_compile("function f(x) { return x - 1; }; f")->Run();
7708 v8::Handle<Value> value = CompileRun(
7709 "o = new Object();"
7710 "proto2 = new Object();"
7711 "o.y = function(x) { return x + 1; };"
7712 "proto2.y = function(x) { return x + 2; };"
7713 "o.__proto__ = proto1;"
7714 "proto1.__proto__ = proto2;"
7715 "var result = 0;"
7716 "var method = 'x';"
7717 "for (var i = 0; i < 10; i++) {"
7718 " if (i == 5) { method = 'y'; };"
7719 " result += o[method](41);"
7720 "}");
7721 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7722}
7723
7724
7725// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7726// on the global object.
7727THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7728 v8::HandleScope scope;
7729 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7730 templ->SetNamedPropertyHandler(NoBlockGetterX);
7731 LocalContext context;
7732 context->Global()->Set(v8_str("o"), templ->NewInstance());
7733 v8::Handle<Value> value = CompileRun(
7734 "function inc(x) { return x + 1; };"
7735 "inc(1);"
7736 "function dec(x) { return x - 1; };"
7737 "dec(1);"
7738 "o.__proto__ = this;"
7739 "this.__proto__.x = inc;"
7740 "this.__proto__.y = dec;"
7741 "var result = 0;"
7742 "var method = 'x';"
7743 "for (var i = 0; i < 10; i++) {"
7744 " if (i == 5) { method = 'y'; };"
7745 " result += o[method](41);"
7746 "}");
7747 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7748}
7749
7750
7751// Test the case when actual function to call sits on global object.
7752THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7753 v8::HandleScope scope;
7754 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7755 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7756 LocalContext context;
7757 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7758
7759 v8::Handle<Value> value = CompileRun(
7760 "function len(x) { return x.length; };"
7761 "o.__proto__ = this;"
7762 "var m = 'parseFloat';"
7763 "var result = 0;"
7764 "for (var i = 0; i < 10; i++) {"
7765 " if (i == 5) {"
7766 " m = 'len';"
7767 " saved_result = result;"
7768 " };"
7769 " result = o[m]('239');"
7770 "}");
7771 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7772 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7773}
7774
7775// Test the map transition before the interceptor.
7776THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7777 v8::HandleScope scope;
7778 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7779 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7780 LocalContext context;
7781 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7782
7783 v8::Handle<Value> value = CompileRun(
7784 "var o = new Object();"
7785 "o.__proto__ = proto;"
7786 "o.method = function(x) { return x + 1; };"
7787 "var m = 'method';"
7788 "var result = 0;"
7789 "for (var i = 0; i < 10; i++) {"
7790 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
7791 " result += o[m](41);"
7792 "}");
7793 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7794}
7795
7796
7797// Test the map transition after the interceptor.
7798THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7799 v8::HandleScope scope;
7800 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7801 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7802 LocalContext context;
7803 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7804
7805 v8::Handle<Value> value = CompileRun(
7806 "var proto = new Object();"
7807 "o.__proto__ = proto;"
7808 "proto.method = function(x) { return x + 1; };"
7809 "var m = 'method';"
7810 "var result = 0;"
7811 "for (var i = 0; i < 10; i++) {"
7812 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7813 " result += o[m](41);"
7814 "}");
7815 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7816}
7817
7818
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007819static int interceptor_call_count = 0;
7820
7821static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7822 const AccessorInfo& info) {
7823 ApiTestFuzzer::Fuzz();
7824 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7825 return call_ic_function2;
7826 }
7827 return v8::Handle<Value>();
7828}
7829
7830
7831// This test should hit load and call ICs for the interceptor case.
7832// Once in a while, the interceptor will reply that a property was not
7833// found in which case we should get a reference error.
7834THREADED_TEST(InterceptorICReferenceErrors) {
7835 v8::HandleScope scope;
7836 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7837 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7838 LocalContext context(0, templ, v8::Handle<Value>());
7839 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7840 v8::Handle<Value> value = CompileRun(
7841 "function f() {"
7842 " for (var i = 0; i < 1000; i++) {"
7843 " try { x; } catch(e) { return true; }"
7844 " }"
7845 " return false;"
7846 "};"
7847 "f();");
7848 CHECK_EQ(true, value->BooleanValue());
7849 interceptor_call_count = 0;
7850 value = CompileRun(
7851 "function g() {"
7852 " for (var i = 0; i < 1000; i++) {"
7853 " try { x(42); } catch(e) { return true; }"
7854 " }"
7855 " return false;"
7856 "};"
7857 "g();");
7858 CHECK_EQ(true, value->BooleanValue());
7859}
7860
7861
7862static int interceptor_ic_exception_get_count = 0;
7863
7864static v8::Handle<Value> InterceptorICExceptionGetter(
7865 Local<String> name,
7866 const AccessorInfo& info) {
7867 ApiTestFuzzer::Fuzz();
7868 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7869 return call_ic_function3;
7870 }
7871 if (interceptor_ic_exception_get_count == 20) {
7872 return v8::ThrowException(v8_num(42));
7873 }
7874 // Do not handle get for properties other than x.
7875 return v8::Handle<Value>();
7876}
7877
7878// Test interceptor load/call IC where the interceptor throws an
7879// exception once in a while.
7880THREADED_TEST(InterceptorICGetterExceptions) {
7881 interceptor_ic_exception_get_count = 0;
7882 v8::HandleScope scope;
7883 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7884 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7885 LocalContext context(0, templ, v8::Handle<Value>());
7886 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7887 v8::Handle<Value> value = CompileRun(
7888 "function f() {"
7889 " for (var i = 0; i < 100; i++) {"
7890 " try { x; } catch(e) { return true; }"
7891 " }"
7892 " return false;"
7893 "};"
7894 "f();");
7895 CHECK_EQ(true, value->BooleanValue());
7896 interceptor_ic_exception_get_count = 0;
7897 value = CompileRun(
7898 "function f() {"
7899 " for (var i = 0; i < 100; i++) {"
7900 " try { x(42); } catch(e) { return true; }"
7901 " }"
7902 " return false;"
7903 "};"
7904 "f();");
7905 CHECK_EQ(true, value->BooleanValue());
7906}
7907
7908
7909static int interceptor_ic_exception_set_count = 0;
7910
7911static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007912 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007913 ApiTestFuzzer::Fuzz();
7914 if (++interceptor_ic_exception_set_count > 20) {
7915 return v8::ThrowException(v8_num(42));
7916 }
7917 // Do not actually handle setting.
7918 return v8::Handle<Value>();
7919}
7920
7921// Test interceptor store IC where the interceptor throws an exception
7922// once in a while.
7923THREADED_TEST(InterceptorICSetterExceptions) {
7924 interceptor_ic_exception_set_count = 0;
7925 v8::HandleScope scope;
7926 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7927 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7928 LocalContext context(0, templ, v8::Handle<Value>());
7929 v8::Handle<Value> value = CompileRun(
7930 "function f() {"
7931 " for (var i = 0; i < 100; i++) {"
7932 " try { x = 42; } catch(e) { return true; }"
7933 " }"
7934 " return false;"
7935 "};"
7936 "f();");
7937 CHECK_EQ(true, value->BooleanValue());
7938}
7939
7940
7941// Test that we ignore null interceptors.
7942THREADED_TEST(NullNamedInterceptor) {
7943 v8::HandleScope scope;
7944 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7945 templ->SetNamedPropertyHandler(0);
7946 LocalContext context;
7947 templ->Set("x", v8_num(42));
7948 v8::Handle<v8::Object> obj = templ->NewInstance();
7949 context->Global()->Set(v8_str("obj"), obj);
7950 v8::Handle<Value> value = CompileRun("obj.x");
7951 CHECK(value->IsInt32());
7952 CHECK_EQ(42, value->Int32Value());
7953}
7954
7955
7956// Test that we ignore null interceptors.
7957THREADED_TEST(NullIndexedInterceptor) {
7958 v8::HandleScope scope;
7959 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7960 templ->SetIndexedPropertyHandler(0);
7961 LocalContext context;
7962 templ->Set("42", v8_num(42));
7963 v8::Handle<v8::Object> obj = templ->NewInstance();
7964 context->Global()->Set(v8_str("obj"), obj);
7965 v8::Handle<Value> value = CompileRun("obj[42]");
7966 CHECK(value->IsInt32());
7967 CHECK_EQ(42, value->Int32Value());
7968}
7969
7970
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007971THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7972 v8::HandleScope scope;
7973 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7974 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7975 LocalContext env;
7976 env->Global()->Set(v8_str("obj"),
7977 templ->GetFunction()->NewInstance());
7978 ExpectTrue("obj.x === 42");
7979 ExpectTrue("!obj.propertyIsEnumerable('x')");
7980}
7981
7982
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007983static v8::Handle<Value> ParentGetter(Local<String> name,
7984 const AccessorInfo& info) {
7985 ApiTestFuzzer::Fuzz();
7986 return v8_num(1);
7987}
7988
7989
7990static v8::Handle<Value> ChildGetter(Local<String> name,
7991 const AccessorInfo& info) {
7992 ApiTestFuzzer::Fuzz();
7993 return v8_num(42);
7994}
7995
7996
7997THREADED_TEST(Overriding) {
7998 v8::HandleScope scope;
7999 LocalContext context;
8000
8001 // Parent template.
8002 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8003 Local<ObjectTemplate> parent_instance_templ =
8004 parent_templ->InstanceTemplate();
8005 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8006
8007 // Template that inherits from the parent template.
8008 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8009 Local<ObjectTemplate> child_instance_templ =
8010 child_templ->InstanceTemplate();
8011 child_templ->Inherit(parent_templ);
8012 // Override 'f'. The child version of 'f' should get called for child
8013 // instances.
8014 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8015 // Add 'g' twice. The 'g' added last should get called for instances.
8016 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8017 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8018
8019 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8020 // so 'h' can be shadowed on the instance object.
8021 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8022 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8023 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8024
8025 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8026 // but the attribute does not have effect because it is duplicated with
8027 // NULL setter.
8028 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8029 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8030
8031
8032
8033 // Instantiate the child template.
8034 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8035
8036 // Check that the child function overrides the parent one.
8037 context->Global()->Set(v8_str("o"), instance);
8038 Local<Value> value = v8_compile("o.f")->Run();
8039 // Check that the 'g' that was added last is hit.
8040 CHECK_EQ(42, value->Int32Value());
8041 value = v8_compile("o.g")->Run();
8042 CHECK_EQ(42, value->Int32Value());
8043
8044 // Check 'h' can be shadowed.
8045 value = v8_compile("o.h = 3; o.h")->Run();
8046 CHECK_EQ(3, value->Int32Value());
8047
8048 // Check 'i' is cannot be shadowed or changed.
8049 value = v8_compile("o.i = 3; o.i")->Run();
8050 CHECK_EQ(42, value->Int32Value());
8051}
8052
8053
8054static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8055 ApiTestFuzzer::Fuzz();
8056 if (args.IsConstructCall()) {
8057 return v8::Boolean::New(true);
8058 }
8059 return v8::Boolean::New(false);
8060}
8061
8062
8063THREADED_TEST(IsConstructCall) {
8064 v8::HandleScope scope;
8065
8066 // Function template with call handler.
8067 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8068 templ->SetCallHandler(IsConstructHandler);
8069
8070 LocalContext context;
8071
8072 context->Global()->Set(v8_str("f"), templ->GetFunction());
8073 Local<Value> value = v8_compile("f()")->Run();
8074 CHECK(!value->BooleanValue());
8075 value = v8_compile("new f()")->Run();
8076 CHECK(value->BooleanValue());
8077}
8078
8079
8080THREADED_TEST(ObjectProtoToString) {
8081 v8::HandleScope scope;
8082 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8083 templ->SetClassName(v8_str("MyClass"));
8084
8085 LocalContext context;
8086
8087 Local<String> customized_tostring = v8_str("customized toString");
8088
8089 // Replace Object.prototype.toString
8090 v8_compile("Object.prototype.toString = function() {"
8091 " return 'customized toString';"
8092 "}")->Run();
8093
8094 // Normal ToString call should call replaced Object.prototype.toString
8095 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8096 Local<String> value = instance->ToString();
8097 CHECK(value->IsString() && value->Equals(customized_tostring));
8098
8099 // ObjectProtoToString should not call replace toString function.
8100 value = instance->ObjectProtoToString();
8101 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8102
8103 // Check global
8104 value = context->Global()->ObjectProtoToString();
8105 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8106
8107 // Check ordinary object
8108 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008109 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008110 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8111}
8112
8113
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008114THREADED_TEST(ObjectGetConstructorName) {
8115 v8::HandleScope scope;
8116 LocalContext context;
8117 v8_compile("function Parent() {};"
8118 "function Child() {};"
8119 "Child.prototype = new Parent();"
8120 "var outer = { inner: function() { } };"
8121 "var p = new Parent();"
8122 "var c = new Child();"
8123 "var x = new outer.inner();")->Run();
8124
8125 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8126 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8127 v8_str("Parent")));
8128
8129 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8130 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8131 v8_str("Child")));
8132
8133 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8134 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8135 v8_str("outer.inner")));
8136}
8137
8138
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008139bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008140i::Semaphore* ApiTestFuzzer::all_tests_done_=
8141 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008142int ApiTestFuzzer::active_tests_;
8143int ApiTestFuzzer::tests_being_run_;
8144int ApiTestFuzzer::current_;
8145
8146
8147// We are in a callback and want to switch to another thread (if we
8148// are currently running the thread fuzzing test).
8149void ApiTestFuzzer::Fuzz() {
8150 if (!fuzzing_) return;
8151 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8152 test->ContextSwitch();
8153}
8154
8155
8156// Let the next thread go. Since it is also waiting on the V8 lock it may
8157// not start immediately.
8158bool ApiTestFuzzer::NextThread() {
8159 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008160 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008161 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008162 if (kLogThreading)
8163 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008164 return false;
8165 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008166 if (kLogThreading) {
8167 printf("Switch from %s to %s\n",
8168 test_name,
8169 RegisterThreadedTest::nth(test_position)->name());
8170 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008171 current_ = test_position;
8172 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8173 return true;
8174}
8175
8176
8177void ApiTestFuzzer::Run() {
8178 // When it is our turn...
8179 gate_->Wait();
8180 {
8181 // ... get the V8 lock and start running the test.
8182 v8::Locker locker;
8183 CallTest();
8184 }
8185 // This test finished.
8186 active_ = false;
8187 active_tests_--;
8188 // If it was the last then signal that fact.
8189 if (active_tests_ == 0) {
8190 all_tests_done_->Signal();
8191 } else {
8192 // Otherwise select a new test and start that.
8193 NextThread();
8194 }
8195}
8196
8197
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008198static unsigned linear_congruential_generator;
8199
8200
8201void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008202 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008203 fuzzing_ = true;
8204 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8205 int end = (part == FIRST_PART)
8206 ? (RegisterThreadedTest::count() >> 1)
8207 : RegisterThreadedTest::count();
8208 active_tests_ = tests_being_run_ = end - start;
8209 for (int i = 0; i < tests_being_run_; i++) {
8210 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8211 }
8212 for (int i = 0; i < active_tests_; i++) {
8213 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8214 }
8215}
8216
8217
8218static void CallTestNumber(int test_number) {
8219 (RegisterThreadedTest::nth(test_number)->callback())();
8220}
8221
8222
8223void ApiTestFuzzer::RunAllTests() {
8224 // Set off the first test.
8225 current_ = -1;
8226 NextThread();
8227 // Wait till they are all done.
8228 all_tests_done_->Wait();
8229}
8230
8231
8232int ApiTestFuzzer::GetNextTestNumber() {
8233 int next_test;
8234 do {
8235 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8236 linear_congruential_generator *= 1664525u;
8237 linear_congruential_generator += 1013904223u;
8238 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8239 return next_test;
8240}
8241
8242
8243void ApiTestFuzzer::ContextSwitch() {
8244 // If the new thread is the same as the current thread there is nothing to do.
8245 if (NextThread()) {
8246 // Now it can start.
8247 v8::Unlocker unlocker;
8248 // Wait till someone starts us again.
8249 gate_->Wait();
8250 // And we're off.
8251 }
8252}
8253
8254
8255void ApiTestFuzzer::TearDown() {
8256 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00008257 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8258 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8259 if (fuzzer != NULL) fuzzer->Join();
8260 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008261}
8262
8263
8264// Lets not be needlessly self-referential.
8265TEST(Threading) {
8266 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8267 ApiTestFuzzer::RunAllTests();
8268 ApiTestFuzzer::TearDown();
8269}
8270
8271TEST(Threading2) {
8272 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8273 ApiTestFuzzer::RunAllTests();
8274 ApiTestFuzzer::TearDown();
8275}
8276
8277
8278void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008279 if (kLogThreading)
8280 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008281 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008282 if (kLogThreading)
8283 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008284}
8285
8286
8287static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008288 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008289 ApiTestFuzzer::Fuzz();
8290 v8::Unlocker unlocker;
8291 const char* code = "throw 7;";
8292 {
8293 v8::Locker nested_locker;
8294 v8::HandleScope scope;
8295 v8::Handle<Value> exception;
8296 { v8::TryCatch try_catch;
8297 v8::Handle<Value> value = CompileRun(code);
8298 CHECK(value.IsEmpty());
8299 CHECK(try_catch.HasCaught());
8300 // Make sure to wrap the exception in a new handle because
8301 // the handle returned from the TryCatch is destroyed
8302 // when the TryCatch is destroyed.
8303 exception = Local<Value>::New(try_catch.Exception());
8304 }
8305 return v8::ThrowException(exception);
8306 }
8307}
8308
8309
8310static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008311 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008312 ApiTestFuzzer::Fuzz();
8313 v8::Unlocker unlocker;
8314 const char* code = "throw 7;";
8315 {
8316 v8::Locker nested_locker;
8317 v8::HandleScope scope;
8318 v8::Handle<Value> value = CompileRun(code);
8319 CHECK(value.IsEmpty());
8320 return v8_str("foo");
8321 }
8322}
8323
8324
8325// These are locking tests that don't need to be run again
8326// as part of the locking aggregation tests.
8327TEST(NestedLockers) {
8328 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008329 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008330 v8::HandleScope scope;
8331 LocalContext env;
8332 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8333 Local<Function> fun = fun_templ->GetFunction();
8334 env->Global()->Set(v8_str("throw_in_js"), fun);
8335 Local<Script> script = v8_compile("(function () {"
8336 " try {"
8337 " throw_in_js();"
8338 " return 42;"
8339 " } catch (e) {"
8340 " return e * 13;"
8341 " }"
8342 "})();");
8343 CHECK_EQ(91, script->Run()->Int32Value());
8344}
8345
8346
8347// These are locking tests that don't need to be run again
8348// as part of the locking aggregation tests.
8349TEST(NestedLockersNoTryCatch) {
8350 v8::Locker locker;
8351 v8::HandleScope scope;
8352 LocalContext env;
8353 Local<v8::FunctionTemplate> fun_templ =
8354 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8355 Local<Function> fun = fun_templ->GetFunction();
8356 env->Global()->Set(v8_str("throw_in_js"), fun);
8357 Local<Script> script = v8_compile("(function () {"
8358 " try {"
8359 " throw_in_js();"
8360 " return 42;"
8361 " } catch (e) {"
8362 " return e * 13;"
8363 " }"
8364 "})();");
8365 CHECK_EQ(91, script->Run()->Int32Value());
8366}
8367
8368
8369THREADED_TEST(RecursiveLocking) {
8370 v8::Locker locker;
8371 {
8372 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008373 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008374 }
8375}
8376
8377
8378static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8379 ApiTestFuzzer::Fuzz();
8380 v8::Unlocker unlocker;
8381 return v8::Undefined();
8382}
8383
8384
8385THREADED_TEST(LockUnlockLock) {
8386 {
8387 v8::Locker locker;
8388 v8::HandleScope scope;
8389 LocalContext env;
8390 Local<v8::FunctionTemplate> fun_templ =
8391 v8::FunctionTemplate::New(UnlockForAMoment);
8392 Local<Function> fun = fun_templ->GetFunction();
8393 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8394 Local<Script> script = v8_compile("(function () {"
8395 " unlock_for_a_moment();"
8396 " return 42;"
8397 "})();");
8398 CHECK_EQ(42, script->Run()->Int32Value());
8399 }
8400 {
8401 v8::Locker locker;
8402 v8::HandleScope scope;
8403 LocalContext env;
8404 Local<v8::FunctionTemplate> fun_templ =
8405 v8::FunctionTemplate::New(UnlockForAMoment);
8406 Local<Function> fun = fun_templ->GetFunction();
8407 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8408 Local<Script> script = v8_compile("(function () {"
8409 " unlock_for_a_moment();"
8410 " return 42;"
8411 "})();");
8412 CHECK_EQ(42, script->Run()->Int32Value());
8413 }
8414}
8415
8416
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008417static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008418 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008419 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008420 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8421 if (object->IsJSGlobalObject()) count++;
8422 return count;
8423}
8424
8425
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008426static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008427 // We need to collect all garbage twice to be sure that everything
8428 // has been collected. This is because inline caches are cleared in
8429 // the first garbage collection but some of the maps have already
8430 // been marked at that point. Therefore some of the maps are not
8431 // collected until the second garbage collection.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008432 i::Heap::CollectAllGarbage(false);
8433 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008434 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008435#ifdef DEBUG
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008436 if (count != expected) i::Heap::TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008437#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008438 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008439}
8440
8441
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008442TEST(DontLeakGlobalObjects) {
8443 // Regression test for issues 1139850 and 1174891.
8444
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008445 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008446
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008447 for (int i = 0; i < 5; i++) {
8448 { v8::HandleScope scope;
8449 LocalContext context;
8450 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008451 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008452
8453 { v8::HandleScope scope;
8454 LocalContext context;
8455 v8_compile("Date")->Run();
8456 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008457 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008458
8459 { v8::HandleScope scope;
8460 LocalContext context;
8461 v8_compile("/aaa/")->Run();
8462 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00008463 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008464
8465 { v8::HandleScope scope;
8466 const char* extension_list[] = { "v8/gc" };
8467 v8::ExtensionConfiguration extensions(1, extension_list);
8468 LocalContext context(&extensions);
8469 v8_compile("gc();")->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}
8474
8475
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008476v8::Persistent<v8::Object> some_object;
8477v8::Persistent<v8::Object> bad_handle;
8478
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008479void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008480 v8::HandleScope scope;
8481 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008482 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008483}
8484
8485
8486THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8487 LocalContext context;
8488
8489 v8::Persistent<v8::Object> handle1, handle2;
8490 {
8491 v8::HandleScope scope;
8492 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8493 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8494 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8495 }
8496 // Note: order is implementation dependent alas: currently
8497 // global handle nodes are processed by PostGarbageCollectionProcessing
8498 // in reverse allocation order, so if second allocated handle is deleted,
8499 // weak callback of the first handle would be able to 'reallocate' it.
8500 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8501 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008502 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008503}
8504
8505
8506v8::Persistent<v8::Object> to_be_disposed;
8507
8508void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8509 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008510 i::Heap::CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008511 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008512}
8513
8514
8515THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8516 LocalContext context;
8517
8518 v8::Persistent<v8::Object> handle1, handle2;
8519 {
8520 v8::HandleScope scope;
8521 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8522 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8523 }
8524 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8525 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00008526 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008527}
8528
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008529void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8530 handle.Dispose();
8531}
8532
8533void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8534 v8::HandleScope scope;
8535 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00008536 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008537}
8538
8539
8540THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8541 LocalContext context;
8542
8543 v8::Persistent<v8::Object> handle1, handle2, handle3;
8544 {
8545 v8::HandleScope scope;
8546 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8547 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8548 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8549 }
8550 handle2.MakeWeak(NULL, DisposingCallback);
8551 handle3.MakeWeak(NULL, HandleCreatingCallback);
8552 i::Heap::CollectAllGarbage(false);
8553}
8554
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00008555
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008556THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008557 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008558
8559 const int nof = 2;
8560 const char* sources[nof] = {
8561 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8562 "Object()"
8563 };
8564
8565 for (int i = 0; i < nof; i++) {
8566 const char* source = sources[i];
8567 { v8::HandleScope scope;
8568 LocalContext context;
8569 CompileRun(source);
8570 }
8571 { v8::HandleScope scope;
8572 LocalContext context;
8573 CompileRun(source);
8574 }
8575 }
8576}
8577
8578
8579static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8580 v8::HandleScope inner;
8581 env->Enter();
8582 v8::Handle<Value> three = v8_num(3);
8583 v8::Handle<Value> value = inner.Close(three);
8584 env->Exit();
8585 return value;
8586}
8587
8588
8589THREADED_TEST(NestedHandleScopeAndContexts) {
8590 v8::HandleScope outer;
8591 v8::Persistent<Context> env = Context::New();
8592 env->Enter();
8593 v8::Handle<Value> value = NestedScope(env);
8594 v8::Handle<String> str = value->ToString();
8595 env->Exit();
8596 env.Dispose();
8597}
8598
8599
8600THREADED_TEST(ExternalAllocatedMemory) {
8601 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008602 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008603 const int kSize = 1024*1024;
8604 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8605 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8606}
8607
8608
8609THREADED_TEST(DisposeEnteredContext) {
8610 v8::HandleScope scope;
8611 LocalContext outer;
8612 { v8::Persistent<v8::Context> inner = v8::Context::New();
8613 inner->Enter();
8614 inner.Dispose();
8615 inner.Clear();
8616 inner->Exit();
8617 }
8618}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008619
8620
8621// Regression test for issue 54, object templates with internal fields
8622// but no accessors or interceptors did not get their internal field
8623// count set on instances.
8624THREADED_TEST(Regress54) {
8625 v8::HandleScope outer;
8626 LocalContext context;
8627 static v8::Persistent<v8::ObjectTemplate> templ;
8628 if (templ.IsEmpty()) {
8629 v8::HandleScope inner;
8630 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8631 local->SetInternalFieldCount(1);
8632 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8633 }
8634 v8::Handle<v8::Object> result = templ->NewInstance();
8635 CHECK_EQ(1, result->InternalFieldCount());
8636}
8637
8638
8639// If part of the threaded tests, this test makes ThreadingTest fail
8640// on mac.
8641TEST(CatchStackOverflow) {
8642 v8::HandleScope scope;
8643 LocalContext context;
8644 v8::TryCatch try_catch;
8645 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8646 "function f() {"
8647 " return f();"
8648 "}"
8649 ""
8650 "f();"));
8651 v8::Handle<v8::Value> result = script->Run();
8652 CHECK(result.IsEmpty());
8653}
8654
8655
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008656static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8657 const char* resource_name,
8658 int line_offset) {
8659 v8::HandleScope scope;
8660 v8::TryCatch try_catch;
8661 v8::Handle<v8::Value> result = script->Run();
8662 CHECK(result.IsEmpty());
8663 CHECK(try_catch.HasCaught());
8664 v8::Handle<v8::Message> message = try_catch.Message();
8665 CHECK(!message.IsEmpty());
8666 CHECK_EQ(10 + line_offset, message->GetLineNumber());
8667 CHECK_EQ(91, message->GetStartPosition());
8668 CHECK_EQ(92, message->GetEndPosition());
8669 CHECK_EQ(2, message->GetStartColumn());
8670 CHECK_EQ(3, message->GetEndColumn());
8671 v8::String::AsciiValue line(message->GetSourceLine());
8672 CHECK_EQ(" throw 'nirk';", *line);
8673 v8::String::AsciiValue name(message->GetScriptResourceName());
8674 CHECK_EQ(resource_name, *name);
8675}
8676
8677
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008678THREADED_TEST(TryCatchSourceInfo) {
8679 v8::HandleScope scope;
8680 LocalContext context;
8681 v8::Handle<v8::String> source = v8::String::New(
8682 "function Foo() {\n"
8683 " return Bar();\n"
8684 "}\n"
8685 "\n"
8686 "function Bar() {\n"
8687 " return Baz();\n"
8688 "}\n"
8689 "\n"
8690 "function Baz() {\n"
8691 " throw 'nirk';\n"
8692 "}\n"
8693 "\n"
8694 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008695
8696 const char* resource_name;
8697 v8::Handle<v8::Script> script;
8698 resource_name = "test.js";
8699 script = v8::Script::Compile(source, v8::String::New(resource_name));
8700 CheckTryCatchSourceInfo(script, resource_name, 0);
8701
8702 resource_name = "test1.js";
8703 v8::ScriptOrigin origin1(v8::String::New(resource_name));
8704 script = v8::Script::Compile(source, &origin1);
8705 CheckTryCatchSourceInfo(script, resource_name, 0);
8706
8707 resource_name = "test2.js";
8708 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8709 script = v8::Script::Compile(source, &origin2);
8710 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008711}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008712
8713
8714THREADED_TEST(CompilationCache) {
8715 v8::HandleScope scope;
8716 LocalContext context;
8717 v8::Handle<v8::String> source0 = v8::String::New("1234");
8718 v8::Handle<v8::String> source1 = v8::String::New("1234");
8719 v8::Handle<v8::Script> script0 =
8720 v8::Script::Compile(source0, v8::String::New("test.js"));
8721 v8::Handle<v8::Script> script1 =
8722 v8::Script::Compile(source1, v8::String::New("test.js"));
8723 v8::Handle<v8::Script> script2 =
8724 v8::Script::Compile(source0); // different origin
8725 CHECK_EQ(1234, script0->Run()->Int32Value());
8726 CHECK_EQ(1234, script1->Run()->Int32Value());
8727 CHECK_EQ(1234, script2->Run()->Int32Value());
8728}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008729
8730
8731static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8732 ApiTestFuzzer::Fuzz();
8733 return v8_num(42);
8734}
8735
8736
8737THREADED_TEST(CallbackFunctionName) {
8738 v8::HandleScope scope;
8739 LocalContext context;
8740 Local<ObjectTemplate> t = ObjectTemplate::New();
8741 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8742 context->Global()->Set(v8_str("obj"), t->NewInstance());
8743 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8744 CHECK(value->IsString());
8745 v8::String::AsciiValue name(value);
8746 CHECK_EQ("asdf", *name);
8747}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008748
8749
8750THREADED_TEST(DateAccess) {
8751 v8::HandleScope scope;
8752 LocalContext context;
8753 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8754 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008755 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008756}
8757
8758
8759void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008760 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008761 v8::Handle<v8::Array> props = obj->GetPropertyNames();
8762 CHECK_EQ(elmc, props->Length());
8763 for (int i = 0; i < elmc; i++) {
8764 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8765 CHECK_EQ(elmv[i], *elm);
8766 }
8767}
8768
8769
8770THREADED_TEST(PropertyEnumeration) {
8771 v8::HandleScope scope;
8772 LocalContext context;
8773 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8774 "var result = [];"
8775 "result[0] = {};"
8776 "result[1] = {a: 1, b: 2};"
8777 "result[2] = [1, 2, 3];"
8778 "var proto = {x: 1, y: 2, z: 3};"
8779 "var x = { __proto__: proto, w: 0, z: 1 };"
8780 "result[3] = x;"
8781 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008782 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008783 CHECK_EQ(4, elms->Length());
8784 int elmc0 = 0;
8785 const char** elmv0 = NULL;
8786 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8787 int elmc1 = 2;
8788 const char* elmv1[] = {"a", "b"};
8789 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8790 int elmc2 = 3;
8791 const char* elmv2[] = {"0", "1", "2"};
8792 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8793 int elmc3 = 4;
8794 const char* elmv3[] = {"w", "z", "x", "y"};
8795 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8796}
ager@chromium.org870a0b62008-11-04 11:43:05 +00008797
8798
ager@chromium.org870a0b62008-11-04 11:43:05 +00008799static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8800 Local<Value> name,
8801 v8::AccessType type,
8802 Local<Value> data) {
8803 return type != v8::ACCESS_SET;
8804}
8805
8806
8807static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8808 uint32_t key,
8809 v8::AccessType type,
8810 Local<Value> data) {
8811 return type != v8::ACCESS_SET;
8812}
8813
8814
8815THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8816 v8::HandleScope scope;
8817 LocalContext context;
8818 Local<ObjectTemplate> templ = ObjectTemplate::New();
8819 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8820 IndexedSetAccessBlocker);
8821 templ->Set(v8_str("x"), v8::True());
8822 Local<v8::Object> instance = templ->NewInstance();
8823 context->Global()->Set(v8_str("obj"), instance);
8824 Local<Value> value = CompileRun("obj.x");
8825 CHECK(value->BooleanValue());
8826}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008827
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008828
ager@chromium.org32912102009-01-16 10:38:43 +00008829static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8830 Local<Value> name,
8831 v8::AccessType type,
8832 Local<Value> data) {
8833 return false;
8834}
8835
8836
8837static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8838 uint32_t key,
8839 v8::AccessType type,
8840 Local<Value> data) {
8841 return false;
8842}
8843
8844
8845
8846THREADED_TEST(AccessChecksReenabledCorrectly) {
8847 v8::HandleScope scope;
8848 LocalContext context;
8849 Local<ObjectTemplate> templ = ObjectTemplate::New();
8850 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8851 IndexedGetAccessBlocker);
8852 templ->Set(v8_str("a"), v8_str("a"));
8853 // Add more than 8 (see kMaxFastProperties) properties
8854 // so that the constructor will force copying map.
8855 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008856 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00008857 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008858 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00008859 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008860 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00008861 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008862 buf[2] = k;
8863 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00008864 templ->Set(v8_str(buf), v8::Number::New(k));
8865 }
8866 }
8867 }
8868
8869 Local<v8::Object> instance_1 = templ->NewInstance();
8870 context->Global()->Set(v8_str("obj_1"), instance_1);
8871
8872 Local<Value> value_1 = CompileRun("obj_1.a");
8873 CHECK(value_1->IsUndefined());
8874
8875 Local<v8::Object> instance_2 = templ->NewInstance();
8876 context->Global()->Set(v8_str("obj_2"), instance_2);
8877
8878 Local<Value> value_2 = CompileRun("obj_2.a");
8879 CHECK(value_2->IsUndefined());
8880}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008881
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008882
ager@chromium.org8bb60582008-12-11 12:02:20 +00008883// This tests that access check information remains on the global
8884// object template when creating contexts.
8885THREADED_TEST(AccessControlRepeatedContextCreation) {
8886 v8::HandleScope handle_scope;
8887 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8888 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8889 IndexedSetAccessBlocker);
8890 i::Handle<i::ObjectTemplateInfo> internal_template =
8891 v8::Utils::OpenHandle(*global_template);
8892 CHECK(!internal_template->constructor()->IsUndefined());
8893 i::Handle<i::FunctionTemplateInfo> constructor(
8894 i::FunctionTemplateInfo::cast(internal_template->constructor()));
8895 CHECK(!constructor->access_check_info()->IsUndefined());
8896 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8897 CHECK(!constructor->access_check_info()->IsUndefined());
8898}
8899
8900
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008901THREADED_TEST(TurnOnAccessCheck) {
8902 v8::HandleScope handle_scope;
8903
8904 // Create an environment with access check to the global object disabled by
8905 // default.
8906 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8907 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8908 IndexedGetAccessBlocker,
8909 v8::Handle<v8::Value>(),
8910 false);
8911 v8::Persistent<Context> context = Context::New(NULL, global_template);
8912 Context::Scope context_scope(context);
8913
8914 // Set up a property and a number of functions.
8915 context->Global()->Set(v8_str("a"), v8_num(1));
8916 CompileRun("function f1() {return a;}"
8917 "function f2() {return a;}"
8918 "function g1() {return h();}"
8919 "function g2() {return h();}"
8920 "function h() {return 1;}");
8921 Local<Function> f1 =
8922 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8923 Local<Function> f2 =
8924 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8925 Local<Function> g1 =
8926 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8927 Local<Function> g2 =
8928 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8929 Local<Function> h =
8930 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8931
8932 // Get the global object.
8933 v8::Handle<v8::Object> global = context->Global();
8934
8935 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8936 // uses the runtime system to retreive property a whereas f2 uses global load
8937 // inline cache.
8938 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8939 for (int i = 0; i < 4; i++) {
8940 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8941 }
8942
8943 // Same for g1 and g2.
8944 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8945 for (int i = 0; i < 4; i++) {
8946 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8947 }
8948
8949 // Detach the global and turn on access check.
8950 context->DetachGlobal();
8951 context->Global()->TurnOnAccessCheck();
8952
8953 // Failing access check to property get results in undefined.
8954 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8955 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8956
8957 // Failing access check to function call results in exception.
8958 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8959 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8960
8961 // No failing access check when just returning a constant.
8962 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8963}
8964
8965
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008966v8::Handle<v8::String> a;
8967v8::Handle<v8::String> h;
8968
8969static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8970 Local<Value> name,
8971 v8::AccessType type,
8972 Local<Value> data) {
8973 return !(name->Equals(a) || name->Equals(h));
8974}
8975
8976
8977THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8978 v8::HandleScope handle_scope;
8979
8980 // Create an environment with access check to the global object disabled by
8981 // default. When the registered access checker will block access to properties
8982 // a and h
8983 a = v8_str("a");
8984 h = v8_str("h");
8985 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8986 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8987 IndexedGetAccessBlocker,
8988 v8::Handle<v8::Value>(),
8989 false);
8990 v8::Persistent<Context> context = Context::New(NULL, global_template);
8991 Context::Scope context_scope(context);
8992
8993 // Set up a property and a number of functions.
8994 context->Global()->Set(v8_str("a"), v8_num(1));
8995 static const char* source = "function f1() {return a;}"
8996 "function f2() {return a;}"
8997 "function g1() {return h();}"
8998 "function g2() {return h();}"
8999 "function h() {return 1;}";
9000
9001 CompileRun(source);
9002 Local<Function> f1;
9003 Local<Function> f2;
9004 Local<Function> g1;
9005 Local<Function> g2;
9006 Local<Function> h;
9007 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9008 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9009 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9010 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9011 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9012
9013 // Get the global object.
9014 v8::Handle<v8::Object> global = context->Global();
9015
9016 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9017 // uses the runtime system to retreive property a whereas f2 uses global load
9018 // inline cache.
9019 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9020 for (int i = 0; i < 4; i++) {
9021 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9022 }
9023
9024 // Same for g1 and g2.
9025 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9026 for (int i = 0; i < 4; i++) {
9027 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9028 }
9029
9030 // Detach the global and turn on access check now blocking access to property
9031 // a and function h.
9032 context->DetachGlobal();
9033 context->Global()->TurnOnAccessCheck();
9034
9035 // Failing access check to property get results in undefined.
9036 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9037 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9038
9039 // Failing access check to function call results in exception.
9040 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9041 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9042
9043 // No failing access check when just returning a constant.
9044 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9045
9046 // Now compile the source again. And get the newly compiled functions, except
9047 // for h for which access is blocked.
9048 CompileRun(source);
9049 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9050 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9051 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9052 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9053 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9054
9055 // Failing access check to property get results in undefined.
9056 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9057 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9058
9059 // Failing access check to function call results in exception.
9060 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9061 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9062}
9063
9064
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009065// This test verifies that pre-compilation (aka preparsing) can be called
9066// without initializing the whole VM. Thus we cannot run this test in a
9067// multi-threaded setup.
9068TEST(PreCompile) {
9069 // TODO(155): This test would break without the initialization of V8. This is
9070 // a workaround for now to make this test not fail.
9071 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009072 const char* script = "function foo(a) { return a+1; }";
9073 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009074 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009075 CHECK_NE(sd->Length(), 0);
9076 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009077 CHECK(!sd->HasError());
9078 delete sd;
9079}
9080
9081
9082TEST(PreCompileWithError) {
9083 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009084 const char* script = "function foo(a) { return 1 * * 2; }";
9085 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009086 v8::ScriptData::PreCompile(script, i::StrLength(script));
9087 CHECK(sd->HasError());
9088 delete sd;
9089}
9090
9091
9092TEST(Regress31661) {
9093 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009094 const char* script = " The Definintive Guide";
9095 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009096 v8::ScriptData::PreCompile(script, i::StrLength(script));
9097 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009098 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009099}
9100
9101
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009102// Tests that ScriptData can be serialized and deserialized.
9103TEST(PreCompileSerialization) {
9104 v8::V8::Initialize();
9105 const char* script = "function foo(a) { return a+1; }";
9106 v8::ScriptData* sd =
9107 v8::ScriptData::PreCompile(script, i::StrLength(script));
9108
9109 // Serialize.
9110 int serialized_data_length = sd->Length();
9111 char* serialized_data = i::NewArray<char>(serialized_data_length);
9112 memcpy(serialized_data, sd->Data(), serialized_data_length);
9113
9114 // Deserialize.
9115 v8::ScriptData* deserialized_sd =
9116 v8::ScriptData::New(serialized_data, serialized_data_length);
9117
9118 // Verify that the original is the same as the deserialized.
9119 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9120 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9121 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9122
9123 delete sd;
9124 delete deserialized_sd;
9125}
9126
9127
9128// Attempts to deserialize bad data.
9129TEST(PreCompileDeserializationError) {
9130 v8::V8::Initialize();
9131 const char* data = "DONT CARE";
9132 int invalid_size = 3;
9133 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9134
9135 CHECK_EQ(0, sd->Length());
9136
9137 delete sd;
9138}
9139
9140
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009141// Attempts to deserialize bad data.
9142TEST(PreCompileInvalidPreparseDataError) {
9143 v8::V8::Initialize();
9144 v8::HandleScope scope;
9145 LocalContext context;
9146
9147 const char* script = "function foo(){ return 5;}\n"
9148 "function bar(){ return 6 + 7;} foo();";
9149 v8::ScriptData* sd =
9150 v8::ScriptData::PreCompile(script, i::StrLength(script));
9151 CHECK(!sd->HasError());
9152 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009153 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009154 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009155 const int kFunctionEntryStartOffset = 0;
9156 const int kFunctionEntryEndOffset = 1;
9157 unsigned* sd_data =
9158 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009159
9160 // Overwrite function bar's end position with 0.
9161 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9162 v8::TryCatch try_catch;
9163
9164 Local<String> source = String::New(script);
9165 Local<Script> compiled_script = Script::New(source, NULL, sd);
9166 CHECK(try_catch.HasCaught());
9167 String::AsciiValue exception_value(try_catch.Message()->Get());
9168 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9169 *exception_value);
9170
9171 try_catch.Reset();
9172 // Overwrite function bar's start position with 200. The function entry
9173 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009174 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9175 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009176 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9177 200;
9178 compiled_script = Script::New(source, NULL, sd);
9179 CHECK(try_catch.HasCaught());
9180 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9181 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9182 *second_exception_value);
9183
9184 delete sd;
9185}
9186
9187
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009188// Verifies that the Handle<String> and const char* versions of the API produce
9189// the same results (at least for one trivial case).
9190TEST(PreCompileAPIVariationsAreSame) {
9191 v8::V8::Initialize();
9192 v8::HandleScope scope;
9193
9194 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009195
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009196 v8::ScriptData* sd_from_cstring =
9197 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9198
9199 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009200 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009201 v8::String::NewExternal(resource));
9202
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009203 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9204 v8::String::New(cstring));
9205
9206 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009207 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009208 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009209 sd_from_cstring->Length()));
9210
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009211 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9212 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9213 sd_from_string->Data(),
9214 sd_from_cstring->Length()));
9215
9216
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009217 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009218 delete sd_from_external_string;
9219 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009220}
9221
9222
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009223// This tests that we do not allow dictionary load/call inline caches
9224// to use functions that have not yet been compiled. The potential
9225// problem of loading a function that has not yet been compiled can
9226// arise because we share code between contexts via the compilation
9227// cache.
9228THREADED_TEST(DictionaryICLoadedFunction) {
9229 v8::HandleScope scope;
9230 // Test LoadIC.
9231 for (int i = 0; i < 2; i++) {
9232 LocalContext context;
9233 context->Global()->Set(v8_str("tmp"), v8::True());
9234 context->Global()->Delete(v8_str("tmp"));
9235 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9236 }
9237 // Test CallIC.
9238 for (int i = 0; i < 2; i++) {
9239 LocalContext context;
9240 context->Global()->Set(v8_str("tmp"), v8::True());
9241 context->Global()->Delete(v8_str("tmp"));
9242 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9243 }
9244}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009245
9246
9247// Test that cross-context new calls use the context of the callee to
9248// create the new JavaScript object.
9249THREADED_TEST(CrossContextNew) {
9250 v8::HandleScope scope;
9251 v8::Persistent<Context> context0 = Context::New();
9252 v8::Persistent<Context> context1 = Context::New();
9253
9254 // Allow cross-domain access.
9255 Local<String> token = v8_str("<security token>");
9256 context0->SetSecurityToken(token);
9257 context1->SetSecurityToken(token);
9258
9259 // Set an 'x' property on the Object prototype and define a
9260 // constructor function in context0.
9261 context0->Enter();
9262 CompileRun("Object.prototype.x = 42; function C() {};");
9263 context0->Exit();
9264
9265 // Call the constructor function from context0 and check that the
9266 // result has the 'x' property.
9267 context1->Enter();
9268 context1->Global()->Set(v8_str("other"), context0->Global());
9269 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9270 CHECK(value->IsInt32());
9271 CHECK_EQ(42, value->Int32Value());
9272 context1->Exit();
9273
9274 // Dispose the contexts to allow them to be garbage collected.
9275 context0.Dispose();
9276 context1.Dispose();
9277}
ager@chromium.org381abbb2009-02-25 13:23:22 +00009278
9279
9280class RegExpInterruptTest {
9281 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009282 RegExpInterruptTest() : block_(NULL) {}
9283 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009284 void RunTest() {
9285 block_ = i::OS::CreateSemaphore(0);
9286 gc_count_ = 0;
9287 gc_during_regexp_ = 0;
9288 regexp_success_ = false;
9289 gc_success_ = false;
9290 GCThread gc_thread(this);
9291 gc_thread.Start();
9292 v8::Locker::StartPreemption(1);
9293
9294 LongRunningRegExp();
9295 {
9296 v8::Unlocker unlock;
9297 gc_thread.Join();
9298 }
9299 v8::Locker::StopPreemption();
9300 CHECK(regexp_success_);
9301 CHECK(gc_success_);
9302 }
9303 private:
9304 // Number of garbage collections required.
9305 static const int kRequiredGCs = 5;
9306
9307 class GCThread : public i::Thread {
9308 public:
9309 explicit GCThread(RegExpInterruptTest* test)
9310 : test_(test) {}
9311 virtual void Run() {
9312 test_->CollectGarbage();
9313 }
9314 private:
9315 RegExpInterruptTest* test_;
9316 };
9317
9318 void CollectGarbage() {
9319 block_->Wait();
9320 while (gc_during_regexp_ < kRequiredGCs) {
9321 {
9322 v8::Locker lock;
9323 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009324 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009325 gc_count_++;
9326 }
9327 i::OS::Sleep(1);
9328 }
9329 gc_success_ = true;
9330 }
9331
9332 void LongRunningRegExp() {
9333 block_->Signal(); // Enable garbage collection thread on next preemption.
9334 int rounds = 0;
9335 while (gc_during_regexp_ < kRequiredGCs) {
9336 int gc_before = gc_count_;
9337 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009338 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009339 const char* c_source =
9340 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9341 ".exec('aaaaaaaaaaaaaaab') === null";
9342 Local<String> source = String::New(c_source);
9343 Local<Script> script = Script::Compile(source);
9344 Local<Value> result = script->Run();
9345 if (!result->BooleanValue()) {
9346 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9347 return;
9348 }
9349 }
9350 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009351 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00009352 const char* c_source =
9353 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9354 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9355 Local<String> source = String::New(c_source);
9356 Local<Script> script = Script::Compile(source);
9357 Local<Value> result = script->Run();
9358 if (!result->BooleanValue()) {
9359 gc_during_regexp_ = kRequiredGCs;
9360 return;
9361 }
9362 }
9363 int gc_after = gc_count_;
9364 gc_during_regexp_ += gc_after - gc_before;
9365 rounds++;
9366 i::OS::Sleep(1);
9367 }
9368 regexp_success_ = true;
9369 }
9370
9371 i::Semaphore* block_;
9372 int gc_count_;
9373 int gc_during_regexp_;
9374 bool regexp_success_;
9375 bool gc_success_;
9376};
9377
9378
9379// Test that a regular expression execution can be interrupted and
9380// survive a garbage collection.
9381TEST(RegExpInterruption) {
9382 v8::Locker lock;
9383 v8::V8::Initialize();
9384 v8::HandleScope scope;
9385 Local<Context> local_env;
9386 {
9387 LocalContext env;
9388 local_env = env.local();
9389 }
9390
9391 // Local context should still be live.
9392 CHECK(!local_env.IsEmpty());
9393 local_env->Enter();
9394
9395 // Should complete without problems.
9396 RegExpInterruptTest().RunTest();
9397
9398 local_env->Exit();
9399}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009400
9401
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009402class ApplyInterruptTest {
9403 public:
9404 ApplyInterruptTest() : block_(NULL) {}
9405 ~ApplyInterruptTest() { delete block_; }
9406 void RunTest() {
9407 block_ = i::OS::CreateSemaphore(0);
9408 gc_count_ = 0;
9409 gc_during_apply_ = 0;
9410 apply_success_ = false;
9411 gc_success_ = false;
9412 GCThread gc_thread(this);
9413 gc_thread.Start();
9414 v8::Locker::StartPreemption(1);
9415
9416 LongRunningApply();
9417 {
9418 v8::Unlocker unlock;
9419 gc_thread.Join();
9420 }
9421 v8::Locker::StopPreemption();
9422 CHECK(apply_success_);
9423 CHECK(gc_success_);
9424 }
9425 private:
9426 // Number of garbage collections required.
9427 static const int kRequiredGCs = 2;
9428
9429 class GCThread : public i::Thread {
9430 public:
9431 explicit GCThread(ApplyInterruptTest* test)
9432 : test_(test) {}
9433 virtual void Run() {
9434 test_->CollectGarbage();
9435 }
9436 private:
9437 ApplyInterruptTest* test_;
9438 };
9439
9440 void CollectGarbage() {
9441 block_->Wait();
9442 while (gc_during_apply_ < kRequiredGCs) {
9443 {
9444 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009445 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009446 gc_count_++;
9447 }
9448 i::OS::Sleep(1);
9449 }
9450 gc_success_ = true;
9451 }
9452
9453 void LongRunningApply() {
9454 block_->Signal();
9455 int rounds = 0;
9456 while (gc_during_apply_ < kRequiredGCs) {
9457 int gc_before = gc_count_;
9458 {
9459 const char* c_source =
9460 "function do_very_little(bar) {"
9461 " this.foo = bar;"
9462 "}"
9463 "for (var i = 0; i < 100000; i++) {"
9464 " do_very_little.apply(this, ['bar']);"
9465 "}";
9466 Local<String> source = String::New(c_source);
9467 Local<Script> script = Script::Compile(source);
9468 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009469 // Check that no exception was thrown.
9470 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009471 }
9472 int gc_after = gc_count_;
9473 gc_during_apply_ += gc_after - gc_before;
9474 rounds++;
9475 }
9476 apply_success_ = true;
9477 }
9478
9479 i::Semaphore* block_;
9480 int gc_count_;
9481 int gc_during_apply_;
9482 bool apply_success_;
9483 bool gc_success_;
9484};
9485
9486
9487// Test that nothing bad happens if we get a preemption just when we were
9488// about to do an apply().
9489TEST(ApplyInterruption) {
9490 v8::Locker lock;
9491 v8::V8::Initialize();
9492 v8::HandleScope scope;
9493 Local<Context> local_env;
9494 {
9495 LocalContext env;
9496 local_env = env.local();
9497 }
9498
9499 // Local context should still be live.
9500 CHECK(!local_env.IsEmpty());
9501 local_env->Enter();
9502
9503 // Should complete without problems.
9504 ApplyInterruptTest().RunTest();
9505
9506 local_env->Exit();
9507}
9508
9509
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009510// Verify that we can clone an object
9511TEST(ObjectClone) {
9512 v8::HandleScope scope;
9513 LocalContext env;
9514
9515 const char* sample =
9516 "var rv = {};" \
9517 "rv.alpha = 'hello';" \
9518 "rv.beta = 123;" \
9519 "rv;";
9520
9521 // Create an object, verify basics.
9522 Local<Value> val = CompileRun(sample);
9523 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009524 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009525 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9526
9527 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9528 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9529 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9530
9531 // Clone it.
9532 Local<v8::Object> clone = obj->Clone();
9533 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9534 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9535 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9536
9537 // Set a property on the clone, verify each object.
9538 clone->Set(v8_str("beta"), v8::Integer::New(456));
9539 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9540 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9541}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009542
9543
ager@chromium.org5ec48922009-05-05 07:25:34 +00009544class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9545 public:
9546 explicit AsciiVectorResource(i::Vector<const char> vector)
9547 : data_(vector) {}
9548 virtual ~AsciiVectorResource() {}
9549 virtual size_t length() const { return data_.length(); }
9550 virtual const char* data() const { return data_.start(); }
9551 private:
9552 i::Vector<const char> data_;
9553};
9554
9555
9556class UC16VectorResource : public v8::String::ExternalStringResource {
9557 public:
9558 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9559 : data_(vector) {}
9560 virtual ~UC16VectorResource() {}
9561 virtual size_t length() const { return data_.length(); }
9562 virtual const i::uc16* data() const { return data_.start(); }
9563 private:
9564 i::Vector<const i::uc16> data_;
9565};
9566
9567
9568static void MorphAString(i::String* string,
9569 AsciiVectorResource* ascii_resource,
9570 UC16VectorResource* uc16_resource) {
9571 CHECK(i::StringShape(string).IsExternal());
9572 if (string->IsAsciiRepresentation()) {
9573 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009574 CHECK(string->map() == i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009575 // Morph external string to be TwoByte string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009576 string->set_map(i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009577 i::ExternalTwoByteString* morphed =
9578 i::ExternalTwoByteString::cast(string);
9579 morphed->set_resource(uc16_resource);
9580 } else {
9581 // Check old map is not symbol or long.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009582 CHECK(string->map() == i::Heap::external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009583 // Morph external string to be ASCII string.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009584 string->set_map(i::Heap::external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009585 i::ExternalAsciiString* morphed =
9586 i::ExternalAsciiString::cast(string);
9587 morphed->set_resource(ascii_resource);
9588 }
9589}
9590
9591
9592// Test that we can still flatten a string if the components it is built up
9593// from have been turned into 16 bit strings in the mean time.
9594THREADED_TEST(MorphCompositeStringTest) {
9595 const char* c_string = "Now is the time for all good men"
9596 " to come to the aid of the party";
9597 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9598 {
9599 v8::HandleScope scope;
9600 LocalContext env;
9601 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009602 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009603 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009604 i::Vector<const uint16_t>(two_byte_string,
9605 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00009606
9607 Local<String> lhs(v8::Utils::ToLocal(
9608 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9609 Local<String> rhs(v8::Utils::ToLocal(
9610 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9611
9612 env->Global()->Set(v8_str("lhs"), lhs);
9613 env->Global()->Set(v8_str("rhs"), rhs);
9614
9615 CompileRun(
9616 "var cons = lhs + rhs;"
9617 "var slice = lhs.substring(1, lhs.length - 1);"
9618 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9619
9620 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9621 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9622
9623 // Now do some stuff to make sure the strings are flattened, etc.
9624 CompileRun(
9625 "/[^a-z]/.test(cons);"
9626 "/[^a-z]/.test(slice);"
9627 "/[^a-z]/.test(slice_on_cons);");
9628 const char* expected_cons =
9629 "Now is the time for all good men to come to the aid of the party"
9630 "Now is the time for all good men to come to the aid of the party";
9631 const char* expected_slice =
9632 "ow is the time for all good men to come to the aid of the part";
9633 const char* expected_slice_on_cons =
9634 "ow is the time for all good men to come to the aid of the party"
9635 "Now is the time for all good men to come to the aid of the part";
9636 CHECK_EQ(String::New(expected_cons),
9637 env->Global()->Get(v8_str("cons")));
9638 CHECK_EQ(String::New(expected_slice),
9639 env->Global()->Get(v8_str("slice")));
9640 CHECK_EQ(String::New(expected_slice_on_cons),
9641 env->Global()->Get(v8_str("slice_on_cons")));
9642 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009643 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009644}
9645
9646
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009647TEST(CompileExternalTwoByteSource) {
9648 v8::HandleScope scope;
9649 LocalContext context;
9650
9651 // This is a very short list of sources, which currently is to check for a
9652 // regression caused by r2703.
9653 const char* ascii_sources[] = {
9654 "0.5",
9655 "-0.5", // This mainly testes PushBack in the Scanner.
9656 "--0.5", // This mainly testes PushBack in the Scanner.
9657 NULL
9658 };
9659
9660 // Compile the sources as external two byte strings.
9661 for (int i = 0; ascii_sources[i] != NULL; i++) {
9662 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9663 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009664 i::Vector<const uint16_t>(two_byte_string,
9665 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009666 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9667 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009668 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009669 }
9670}
9671
9672
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009673class RegExpStringModificationTest {
9674 public:
9675 RegExpStringModificationTest()
9676 : block_(i::OS::CreateSemaphore(0)),
9677 morphs_(0),
9678 morphs_during_regexp_(0),
9679 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9680 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9681 ~RegExpStringModificationTest() { delete block_; }
9682 void RunTest() {
9683 regexp_success_ = false;
9684 morph_success_ = false;
9685
9686 // Initialize the contents of two_byte_content_ to be a uc16 representation
9687 // of "aaaaaaaaaaaaaab".
9688 for (int i = 0; i < 14; i++) {
9689 two_byte_content_[i] = 'a';
9690 }
9691 two_byte_content_[14] = 'b';
9692
9693 // Create the input string for the regexp - the one we are going to change
9694 // properties of.
9695 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9696
9697 // Inject the input as a global variable.
9698 i::Handle<i::String> input_name =
9699 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009700 i::Top::global_context()->global()->SetProperty(*input_name,
9701 *input_,
9702 NONE)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009703
9704
9705 MorphThread morph_thread(this);
9706 morph_thread.Start();
9707 v8::Locker::StartPreemption(1);
9708 LongRunningRegExp();
9709 {
9710 v8::Unlocker unlock;
9711 morph_thread.Join();
9712 }
9713 v8::Locker::StopPreemption();
9714 CHECK(regexp_success_);
9715 CHECK(morph_success_);
9716 }
9717 private:
9718
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009719 // Number of string modifications required.
9720 static const int kRequiredModifications = 5;
9721 static const int kMaxModifications = 100;
9722
9723 class MorphThread : public i::Thread {
9724 public:
9725 explicit MorphThread(RegExpStringModificationTest* test)
9726 : test_(test) {}
9727 virtual void Run() {
9728 test_->MorphString();
9729 }
9730 private:
9731 RegExpStringModificationTest* test_;
9732 };
9733
9734 void MorphString() {
9735 block_->Wait();
9736 while (morphs_during_regexp_ < kRequiredModifications &&
9737 morphs_ < kMaxModifications) {
9738 {
9739 v8::Locker lock;
9740 // Swap string between ascii and two-byte representation.
9741 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +00009742 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009743 morphs_++;
9744 }
9745 i::OS::Sleep(1);
9746 }
9747 morph_success_ = true;
9748 }
9749
9750 void LongRunningRegExp() {
9751 block_->Signal(); // Enable morphing thread on next preemption.
9752 while (morphs_during_regexp_ < kRequiredModifications &&
9753 morphs_ < kMaxModifications) {
9754 int morphs_before = morphs_;
9755 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009756 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009757 // Match 15-30 "a"'s against 14 and a "b".
9758 const char* c_source =
9759 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9760 ".exec(input) === null";
9761 Local<String> source = String::New(c_source);
9762 Local<Script> script = Script::Compile(source);
9763 Local<Value> result = script->Run();
9764 CHECK(result->IsTrue());
9765 }
9766 int morphs_after = morphs_;
9767 morphs_during_regexp_ += morphs_after - morphs_before;
9768 }
9769 regexp_success_ = true;
9770 }
9771
9772 i::uc16 two_byte_content_[15];
9773 i::Semaphore* block_;
9774 int morphs_;
9775 int morphs_during_regexp_;
9776 bool regexp_success_;
9777 bool morph_success_;
9778 i::Handle<i::String> input_;
9779 AsciiVectorResource ascii_resource_;
9780 UC16VectorResource uc16_resource_;
9781};
9782
9783
9784// Test that a regular expression execution can be interrupted and
9785// the string changed without failing.
9786TEST(RegExpStringModification) {
9787 v8::Locker lock;
9788 v8::V8::Initialize();
9789 v8::HandleScope scope;
9790 Local<Context> local_env;
9791 {
9792 LocalContext env;
9793 local_env = env.local();
9794 }
9795
9796 // Local context should still be live.
9797 CHECK(!local_env.IsEmpty());
9798 local_env->Enter();
9799
9800 // Should complete without problems.
9801 RegExpStringModificationTest().RunTest();
9802
9803 local_env->Exit();
9804}
9805
9806
9807// Test that we can set a property on the global object even if there
9808// is a read-only property in the prototype chain.
9809TEST(ReadOnlyPropertyInGlobalProto) {
9810 v8::HandleScope scope;
9811 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9812 LocalContext context(0, templ);
9813 v8::Handle<v8::Object> global = context->Global();
9814 v8::Handle<v8::Object> global_proto =
9815 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9816 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9817 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9818 // Check without 'eval' or 'with'.
9819 v8::Handle<v8::Value> res =
9820 CompileRun("function f() { x = 42; return x; }; f()");
9821 // Check with 'eval'.
9822 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9823 CHECK_EQ(v8::Integer::New(42), res);
9824 // Check with 'with'.
9825 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9826 CHECK_EQ(v8::Integer::New(42), res);
9827}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009828
9829static int force_set_set_count = 0;
9830static int force_set_get_count = 0;
9831bool pass_on_get = false;
9832
9833static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9834 const v8::AccessorInfo& info) {
9835 force_set_get_count++;
9836 if (pass_on_get) {
9837 return v8::Handle<v8::Value>();
9838 } else {
9839 return v8::Int32::New(3);
9840 }
9841}
9842
9843static void ForceSetSetter(v8::Local<v8::String> name,
9844 v8::Local<v8::Value> value,
9845 const v8::AccessorInfo& info) {
9846 force_set_set_count++;
9847}
9848
9849static v8::Handle<v8::Value> ForceSetInterceptSetter(
9850 v8::Local<v8::String> name,
9851 v8::Local<v8::Value> value,
9852 const v8::AccessorInfo& info) {
9853 force_set_set_count++;
9854 return v8::Undefined();
9855}
9856
9857TEST(ForceSet) {
9858 force_set_get_count = 0;
9859 force_set_set_count = 0;
9860 pass_on_get = false;
9861
9862 v8::HandleScope scope;
9863 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9864 v8::Handle<v8::String> access_property = v8::String::New("a");
9865 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9866 LocalContext context(NULL, templ);
9867 v8::Handle<v8::Object> global = context->Global();
9868
9869 // Ordinary properties
9870 v8::Handle<v8::String> simple_property = v8::String::New("p");
9871 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9872 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9873 // This should fail because the property is read-only
9874 global->Set(simple_property, v8::Int32::New(5));
9875 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9876 // This should succeed even though the property is read-only
9877 global->ForceSet(simple_property, v8::Int32::New(6));
9878 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9879
9880 // Accessors
9881 CHECK_EQ(0, force_set_set_count);
9882 CHECK_EQ(0, force_set_get_count);
9883 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9884 // CHECK_EQ the property shouldn't override it, just call the setter
9885 // which in this case does nothing.
9886 global->Set(access_property, v8::Int32::New(7));
9887 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9888 CHECK_EQ(1, force_set_set_count);
9889 CHECK_EQ(2, force_set_get_count);
9890 // Forcing the property to be set should override the accessor without
9891 // calling it
9892 global->ForceSet(access_property, v8::Int32::New(8));
9893 CHECK_EQ(8, global->Get(access_property)->Int32Value());
9894 CHECK_EQ(1, force_set_set_count);
9895 CHECK_EQ(2, force_set_get_count);
9896}
9897
9898TEST(ForceSetWithInterceptor) {
9899 force_set_get_count = 0;
9900 force_set_set_count = 0;
9901 pass_on_get = false;
9902
9903 v8::HandleScope scope;
9904 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9905 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9906 LocalContext context(NULL, templ);
9907 v8::Handle<v8::Object> global = context->Global();
9908
9909 v8::Handle<v8::String> some_property = v8::String::New("a");
9910 CHECK_EQ(0, force_set_set_count);
9911 CHECK_EQ(0, force_set_get_count);
9912 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9913 // Setting the property shouldn't override it, just call the setter
9914 // which in this case does nothing.
9915 global->Set(some_property, v8::Int32::New(7));
9916 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9917 CHECK_EQ(1, force_set_set_count);
9918 CHECK_EQ(2, force_set_get_count);
9919 // Getting the property when the interceptor returns an empty handle
9920 // should yield undefined, since the property isn't present on the
9921 // object itself yet.
9922 pass_on_get = true;
9923 CHECK(global->Get(some_property)->IsUndefined());
9924 CHECK_EQ(1, force_set_set_count);
9925 CHECK_EQ(3, force_set_get_count);
9926 // Forcing the property to be set should cause the value to be
9927 // set locally without calling the interceptor.
9928 global->ForceSet(some_property, v8::Int32::New(8));
9929 CHECK_EQ(8, global->Get(some_property)->Int32Value());
9930 CHECK_EQ(1, force_set_set_count);
9931 CHECK_EQ(4, force_set_get_count);
9932 // Reenabling the interceptor should cause it to take precedence over
9933 // the property
9934 pass_on_get = false;
9935 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9936 CHECK_EQ(1, force_set_set_count);
9937 CHECK_EQ(5, force_set_get_count);
9938 // The interceptor should also work for other properties
9939 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9940 CHECK_EQ(1, force_set_set_count);
9941 CHECK_EQ(6, force_set_get_count);
9942}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00009943
9944
ager@chromium.orge2902be2009-06-08 12:21:35 +00009945THREADED_TEST(ForceDelete) {
9946 v8::HandleScope scope;
9947 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9948 LocalContext context(NULL, templ);
9949 v8::Handle<v8::Object> global = context->Global();
9950
9951 // Ordinary properties
9952 v8::Handle<v8::String> simple_property = v8::String::New("p");
9953 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9954 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9955 // This should fail because the property is dont-delete.
9956 CHECK(!global->Delete(simple_property));
9957 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9958 // This should succeed even though the property is dont-delete.
9959 CHECK(global->ForceDelete(simple_property));
9960 CHECK(global->Get(simple_property)->IsUndefined());
9961}
9962
9963
9964static int force_delete_interceptor_count = 0;
9965static bool pass_on_delete = false;
9966
9967
9968static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9969 v8::Local<v8::String> name,
9970 const v8::AccessorInfo& info) {
9971 force_delete_interceptor_count++;
9972 if (pass_on_delete) {
9973 return v8::Handle<v8::Boolean>();
9974 } else {
9975 return v8::True();
9976 }
9977}
9978
9979
9980THREADED_TEST(ForceDeleteWithInterceptor) {
9981 force_delete_interceptor_count = 0;
9982 pass_on_delete = false;
9983
9984 v8::HandleScope scope;
9985 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9986 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9987 LocalContext context(NULL, templ);
9988 v8::Handle<v8::Object> global = context->Global();
9989
9990 v8::Handle<v8::String> some_property = v8::String::New("a");
9991 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9992
9993 // Deleting a property should get intercepted and nothing should
9994 // happen.
9995 CHECK_EQ(0, force_delete_interceptor_count);
9996 CHECK(global->Delete(some_property));
9997 CHECK_EQ(1, force_delete_interceptor_count);
9998 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9999 // Deleting the property when the interceptor returns an empty
10000 // handle should not delete the property since it is DontDelete.
10001 pass_on_delete = true;
10002 CHECK(!global->Delete(some_property));
10003 CHECK_EQ(2, force_delete_interceptor_count);
10004 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10005 // Forcing the property to be deleted should delete the value
10006 // without calling the interceptor.
10007 CHECK(global->ForceDelete(some_property));
10008 CHECK(global->Get(some_property)->IsUndefined());
10009 CHECK_EQ(2, force_delete_interceptor_count);
10010}
10011
10012
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010013// Make sure that forcing a delete invalidates any IC stubs, so we
10014// don't read the hole value.
10015THREADED_TEST(ForceDeleteIC) {
10016 v8::HandleScope scope;
10017 LocalContext context;
10018 // Create a DontDelete variable on the global object.
10019 CompileRun("this.__proto__ = { foo: 'horse' };"
10020 "var foo = 'fish';"
10021 "function f() { return foo.length; }");
10022 // Initialize the IC for foo in f.
10023 CompileRun("for (var i = 0; i < 4; i++) f();");
10024 // Make sure the value of foo is correct before the deletion.
10025 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10026 // Force the deletion of foo.
10027 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10028 // Make sure the value for foo is read from the prototype, and that
10029 // we don't get in trouble with reading the deleted cell value
10030 // sentinel.
10031 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10032}
10033
10034
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010035v8::Persistent<Context> calling_context0;
10036v8::Persistent<Context> calling_context1;
10037v8::Persistent<Context> calling_context2;
10038
10039
10040// Check that the call to the callback is initiated in
10041// calling_context2, the directly calling context is calling_context1
10042// and the callback itself is in calling_context0.
10043static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10044 ApiTestFuzzer::Fuzz();
10045 CHECK(Context::GetCurrent() == calling_context0);
10046 CHECK(Context::GetCalling() == calling_context1);
10047 CHECK(Context::GetEntered() == calling_context2);
10048 return v8::Integer::New(42);
10049}
10050
10051
10052THREADED_TEST(GetCallingContext) {
10053 v8::HandleScope scope;
10054
10055 calling_context0 = Context::New();
10056 calling_context1 = Context::New();
10057 calling_context2 = Context::New();
10058
10059 // Allow cross-domain access.
10060 Local<String> token = v8_str("<security token>");
10061 calling_context0->SetSecurityToken(token);
10062 calling_context1->SetSecurityToken(token);
10063 calling_context2->SetSecurityToken(token);
10064
10065 // Create an object with a C++ callback in context0.
10066 calling_context0->Enter();
10067 Local<v8::FunctionTemplate> callback_templ =
10068 v8::FunctionTemplate::New(GetCallingContextCallback);
10069 calling_context0->Global()->Set(v8_str("callback"),
10070 callback_templ->GetFunction());
10071 calling_context0->Exit();
10072
10073 // Expose context0 in context1 and setup a function that calls the
10074 // callback function.
10075 calling_context1->Enter();
10076 calling_context1->Global()->Set(v8_str("context0"),
10077 calling_context0->Global());
10078 CompileRun("function f() { context0.callback() }");
10079 calling_context1->Exit();
10080
10081 // Expose context1 in context2 and call the callback function in
10082 // context0 indirectly through f in context1.
10083 calling_context2->Enter();
10084 calling_context2->Global()->Set(v8_str("context1"),
10085 calling_context1->Global());
10086 CompileRun("context1.f()");
10087 calling_context2->Exit();
10088
10089 // Dispose the contexts to allow them to be garbage collected.
10090 calling_context0.Dispose();
10091 calling_context1.Dispose();
10092 calling_context2.Dispose();
10093 calling_context0.Clear();
10094 calling_context1.Clear();
10095 calling_context2.Clear();
10096}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010097
10098
10099// Check that a variable declaration with no explicit initialization
10100// value does not shadow an existing property in the prototype chain.
10101//
10102// This is consistent with Firefox and Safari.
10103//
10104// See http://crbug.com/12548.
10105THREADED_TEST(InitGlobalVarInProtoChain) {
10106 v8::HandleScope scope;
10107 LocalContext context;
10108 // Introduce a variable in the prototype chain.
10109 CompileRun("__proto__.x = 42");
10110 v8::Handle<v8::Value> result = CompileRun("var x; x");
10111 CHECK(!result->IsUndefined());
10112 CHECK_EQ(42, result->Int32Value());
10113}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010114
10115
10116// Regression test for issue 398.
10117// If a function is added to an object, creating a constant function
10118// field, and the result is cloned, replacing the constant function on the
10119// original should not affect the clone.
10120// See http://code.google.com/p/v8/issues/detail?id=398
10121THREADED_TEST(ReplaceConstantFunction) {
10122 v8::HandleScope scope;
10123 LocalContext context;
10124 v8::Handle<v8::Object> obj = v8::Object::New();
10125 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10126 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10127 obj->Set(foo_string, func_templ->GetFunction());
10128 v8::Handle<v8::Object> obj_clone = obj->Clone();
10129 obj_clone->Set(foo_string, v8::String::New("Hello"));
10130 CHECK(!obj->Get(foo_string)->IsUndefined());
10131}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010132
10133
10134// Regression test for http://crbug.com/16276.
10135THREADED_TEST(Regress16276) {
10136 v8::HandleScope scope;
10137 LocalContext context;
10138 // Force the IC in f to be a dictionary load IC.
10139 CompileRun("function f(obj) { return obj.x; }\n"
10140 "var obj = { x: { foo: 42 }, y: 87 };\n"
10141 "var x = obj.x;\n"
10142 "delete obj.y;\n"
10143 "for (var i = 0; i < 5; i++) f(obj);");
10144 // Detach the global object to make 'this' refer directly to the
10145 // global object (not the proxy), and make sure that the dictionary
10146 // load IC doesn't mess up loading directly from the global object.
10147 context->DetachGlobal();
10148 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10149}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010150
10151
10152THREADED_TEST(PixelArray) {
10153 v8::HandleScope scope;
10154 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010155 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010156 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10157 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10158 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010159 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010160 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010161 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010162 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010163 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010164 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010165 CHECK_EQ(i % 256, pixels->get(i));
10166 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010167 }
10168
10169 v8::Handle<v8::Object> obj = v8::Object::New();
10170 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10171 // Set the elements to be the pixels.
10172 // jsobj->set_elements(*pixels);
10173 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010174 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010175 obj->Set(v8_str("field"), v8::Int32::New(1503));
10176 context->Global()->Set(v8_str("pixels"), obj);
10177 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10178 CHECK_EQ(1503, result->Int32Value());
10179 result = CompileRun("pixels[1]");
10180 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010181
10182 result = CompileRun("var sum = 0;"
10183 "for (var i = 0; i < 8; i++) {"
10184 " sum += pixels[i] = pixels[i] = -i;"
10185 "}"
10186 "sum;");
10187 CHECK_EQ(-28, result->Int32Value());
10188
10189 result = CompileRun("var sum = 0;"
10190 "for (var i = 0; i < 8; i++) {"
10191 " sum += pixels[i] = pixels[i] = 0;"
10192 "}"
10193 "sum;");
10194 CHECK_EQ(0, result->Int32Value());
10195
10196 result = CompileRun("var sum = 0;"
10197 "for (var i = 0; i < 8; i++) {"
10198 " sum += pixels[i] = pixels[i] = 255;"
10199 "}"
10200 "sum;");
10201 CHECK_EQ(8 * 255, result->Int32Value());
10202
10203 result = CompileRun("var sum = 0;"
10204 "for (var i = 0; i < 8; i++) {"
10205 " sum += pixels[i] = pixels[i] = 256 + i;"
10206 "}"
10207 "sum;");
10208 CHECK_EQ(2076, result->Int32Value());
10209
10210 result = CompileRun("var sum = 0;"
10211 "for (var i = 0; i < 8; i++) {"
10212 " sum += pixels[i] = pixels[i] = i;"
10213 "}"
10214 "sum;");
10215 CHECK_EQ(28, result->Int32Value());
10216
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010217 result = CompileRun("var sum = 0;"
10218 "for (var i = 0; i < 8; i++) {"
10219 " sum += pixels[i];"
10220 "}"
10221 "sum;");
10222 CHECK_EQ(28, result->Int32Value());
10223
10224 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10225 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010227 *value.location() = i::Smi::FromInt(256);
10228 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010229 CHECK_EQ(255,
10230 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010231 *value.location() = i::Smi::FromInt(-1);
10232 i::SetElement(jsobj, 1, value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010233 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010234
10235 result = CompileRun("for (var i = 0; i < 8; i++) {"
10236 " pixels[i] = (i * 65) - 109;"
10237 "}"
10238 "pixels[1] + pixels[6];");
10239 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010240 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10241 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10242 CHECK_EQ(21,
10243 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10244 CHECK_EQ(86,
10245 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10246 CHECK_EQ(151,
10247 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10248 CHECK_EQ(216,
10249 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10250 CHECK_EQ(255,
10251 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10252 CHECK_EQ(255,
10253 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010254 result = CompileRun("var sum = 0;"
10255 "for (var i = 0; i < 8; i++) {"
10256 " sum += pixels[i];"
10257 "}"
10258 "sum;");
10259 CHECK_EQ(984, result->Int32Value());
10260
10261 result = CompileRun("for (var i = 0; i < 8; i++) {"
10262 " pixels[i] = (i * 1.1);"
10263 "}"
10264 "pixels[1] + pixels[6];");
10265 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010266 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10267 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10268 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10269 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10270 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10271 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10272 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10273 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010274
10275 result = CompileRun("for (var i = 0; i < 8; i++) {"
10276 " pixels[7] = undefined;"
10277 "}"
10278 "pixels[7];");
10279 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010280 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010281
10282 result = CompileRun("for (var i = 0; i < 8; i++) {"
10283 " pixels[6] = '2.3';"
10284 "}"
10285 "pixels[6];");
10286 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010287 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010288
10289 result = CompileRun("for (var i = 0; i < 8; i++) {"
10290 " pixels[5] = NaN;"
10291 "}"
10292 "pixels[5];");
10293 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010294 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010295
10296 result = CompileRun("for (var i = 0; i < 8; i++) {"
10297 " pixels[8] = Infinity;"
10298 "}"
10299 "pixels[8];");
10300 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010301 CHECK_EQ(255,
10302 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010303
10304 result = CompileRun("for (var i = 0; i < 8; i++) {"
10305 " pixels[9] = -Infinity;"
10306 "}"
10307 "pixels[9];");
10308 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010309 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010310
10311 result = CompileRun("pixels[3] = 33;"
10312 "delete pixels[3];"
10313 "pixels[3];");
10314 CHECK_EQ(33, result->Int32Value());
10315
10316 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10317 "pixels[2] = 12; pixels[3] = 13;"
10318 "pixels.__defineGetter__('2',"
10319 "function() { return 120; });"
10320 "pixels[2];");
10321 CHECK_EQ(12, result->Int32Value());
10322
10323 result = CompileRun("var js_array = new Array(40);"
10324 "js_array[0] = 77;"
10325 "js_array;");
10326 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10327
10328 result = CompileRun("pixels[1] = 23;"
10329 "pixels.__proto__ = [];"
10330 "js_array.__proto__ = pixels;"
10331 "js_array.concat(pixels);");
10332 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10333 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10334
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010335 result = CompileRun("pixels[1] = 23;");
10336 CHECK_EQ(23, result->Int32Value());
10337
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010338 // Test for index greater than 255. Regression test for:
10339 // http://code.google.com/p/chromium/issues/detail?id=26337.
10340 result = CompileRun("pixels[256] = 255;");
10341 CHECK_EQ(255, result->Int32Value());
10342 result = CompileRun("var i = 0;"
10343 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10344 "i");
10345 CHECK_EQ(255, result->Int32Value());
10346
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010347 free(pixel_data);
10348}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010349
ager@chromium.org96c75b52009-08-26 09:13:16 +000010350
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010351THREADED_TEST(PixelArrayInfo) {
10352 v8::HandleScope scope;
10353 LocalContext context;
10354 for (int size = 0; size < 100; size += 10) {
10355 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10356 v8::Handle<v8::Object> obj = v8::Object::New();
10357 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10358 CHECK(obj->HasIndexedPropertiesInPixelData());
10359 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10360 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10361 free(pixel_data);
10362 }
10363}
10364
10365
10366static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10367 switch (array_type) {
10368 case v8::kExternalByteArray:
10369 case v8::kExternalUnsignedByteArray:
10370 return 1;
10371 break;
10372 case v8::kExternalShortArray:
10373 case v8::kExternalUnsignedShortArray:
10374 return 2;
10375 break;
10376 case v8::kExternalIntArray:
10377 case v8::kExternalUnsignedIntArray:
10378 case v8::kExternalFloatArray:
10379 return 4;
10380 break;
10381 default:
10382 UNREACHABLE();
10383 return -1;
10384 }
10385 UNREACHABLE();
10386 return -1;
10387}
10388
10389
ager@chromium.org3811b432009-10-28 14:53:37 +000010390template <class ExternalArrayClass, class ElementType>
10391static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10392 int64_t low,
10393 int64_t high) {
10394 v8::HandleScope scope;
10395 LocalContext context;
10396 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010397 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000010398 ElementType* array_data =
10399 static_cast<ElementType*>(malloc(kElementCount * element_size));
10400 i::Handle<ExternalArrayClass> array =
10401 i::Handle<ExternalArrayClass>::cast(
10402 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10403 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10404 for (int i = 0; i < kElementCount; i++) {
10405 array->set(i, static_cast<ElementType>(i));
10406 }
10407 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10408 for (int i = 0; i < kElementCount; i++) {
10409 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10410 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10411 }
10412
10413 v8::Handle<v8::Object> obj = v8::Object::New();
10414 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10415 // Set the elements to be the external array.
10416 obj->SetIndexedPropertiesToExternalArrayData(array_data,
10417 array_type,
10418 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010419 CHECK_EQ(
10420 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010421 obj->Set(v8_str("field"), v8::Int32::New(1503));
10422 context->Global()->Set(v8_str("ext_array"), obj);
10423 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10424 CHECK_EQ(1503, result->Int32Value());
10425 result = CompileRun("ext_array[1]");
10426 CHECK_EQ(1, result->Int32Value());
10427
10428 // Check pass through of assigned smis
10429 result = CompileRun("var sum = 0;"
10430 "for (var i = 0; i < 8; i++) {"
10431 " sum += ext_array[i] = ext_array[i] = -i;"
10432 "}"
10433 "sum;");
10434 CHECK_EQ(-28, result->Int32Value());
10435
10436 // Check assigned smis
10437 result = CompileRun("for (var i = 0; i < 8; i++) {"
10438 " ext_array[i] = i;"
10439 "}"
10440 "var sum = 0;"
10441 "for (var i = 0; i < 8; i++) {"
10442 " sum += ext_array[i];"
10443 "}"
10444 "sum;");
10445 CHECK_EQ(28, result->Int32Value());
10446
10447 // Check assigned smis in reverse order
10448 result = CompileRun("for (var i = 8; --i >= 0; ) {"
10449 " ext_array[i] = i;"
10450 "}"
10451 "var sum = 0;"
10452 "for (var i = 0; i < 8; i++) {"
10453 " sum += ext_array[i];"
10454 "}"
10455 "sum;");
10456 CHECK_EQ(28, result->Int32Value());
10457
10458 // Check pass through of assigned HeapNumbers
10459 result = CompileRun("var sum = 0;"
10460 "for (var i = 0; i < 16; i+=2) {"
10461 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10462 "}"
10463 "sum;");
10464 CHECK_EQ(-28, result->Int32Value());
10465
10466 // Check assigned HeapNumbers
10467 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10468 " ext_array[i] = (i * 0.5);"
10469 "}"
10470 "var sum = 0;"
10471 "for (var i = 0; i < 16; i+=2) {"
10472 " sum += ext_array[i];"
10473 "}"
10474 "sum;");
10475 CHECK_EQ(28, result->Int32Value());
10476
10477 // Check assigned HeapNumbers in reverse order
10478 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10479 " ext_array[i] = (i * 0.5);"
10480 "}"
10481 "var sum = 0;"
10482 "for (var i = 0; i < 16; i+=2) {"
10483 " sum += ext_array[i];"
10484 "}"
10485 "sum;");
10486 CHECK_EQ(28, result->Int32Value());
10487
10488 i::ScopedVector<char> test_buf(1024);
10489
10490 // Check legal boundary conditions.
10491 // The repeated loads and stores ensure the ICs are exercised.
10492 const char* boundary_program =
10493 "var res = 0;"
10494 "for (var i = 0; i < 16; i++) {"
10495 " ext_array[i] = %lld;"
10496 " if (i > 8) {"
10497 " res = ext_array[i];"
10498 " }"
10499 "}"
10500 "res;";
10501 i::OS::SNPrintF(test_buf,
10502 boundary_program,
10503 low);
10504 result = CompileRun(test_buf.start());
10505 CHECK_EQ(low, result->IntegerValue());
10506
10507 i::OS::SNPrintF(test_buf,
10508 boundary_program,
10509 high);
10510 result = CompileRun(test_buf.start());
10511 CHECK_EQ(high, result->IntegerValue());
10512
10513 // Check misprediction of type in IC.
10514 result = CompileRun("var tmp_array = ext_array;"
10515 "var sum = 0;"
10516 "for (var i = 0; i < 8; i++) {"
10517 " tmp_array[i] = i;"
10518 " sum += tmp_array[i];"
10519 " if (i == 4) {"
10520 " tmp_array = {};"
10521 " }"
10522 "}"
10523 "sum;");
10524 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10525 CHECK_EQ(28, result->Int32Value());
10526
10527 // Make sure out-of-range loads do not throw.
10528 i::OS::SNPrintF(test_buf,
10529 "var caught_exception = false;"
10530 "try {"
10531 " ext_array[%d];"
10532 "} catch (e) {"
10533 " caught_exception = true;"
10534 "}"
10535 "caught_exception;",
10536 kElementCount);
10537 result = CompileRun(test_buf.start());
10538 CHECK_EQ(false, result->BooleanValue());
10539
10540 // Make sure out-of-range stores do not throw.
10541 i::OS::SNPrintF(test_buf,
10542 "var caught_exception = false;"
10543 "try {"
10544 " ext_array[%d] = 1;"
10545 "} catch (e) {"
10546 " caught_exception = true;"
10547 "}"
10548 "caught_exception;",
10549 kElementCount);
10550 result = CompileRun(test_buf.start());
10551 CHECK_EQ(false, result->BooleanValue());
10552
10553 // Check other boundary conditions, values and operations.
10554 result = CompileRun("for (var i = 0; i < 8; i++) {"
10555 " ext_array[7] = undefined;"
10556 "}"
10557 "ext_array[7];");
10558 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010559 CHECK_EQ(
10560 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010561
10562 result = CompileRun("for (var i = 0; i < 8; i++) {"
10563 " ext_array[6] = '2.3';"
10564 "}"
10565 "ext_array[6];");
10566 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010567 CHECK_EQ(
10568 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000010569
10570 if (array_type != v8::kExternalFloatArray) {
10571 // Though the specification doesn't state it, be explicit about
10572 // converting NaNs and +/-Infinity to zero.
10573 result = CompileRun("for (var i = 0; i < 8; i++) {"
10574 " ext_array[i] = 5;"
10575 "}"
10576 "for (var i = 0; i < 8; i++) {"
10577 " ext_array[i] = NaN;"
10578 "}"
10579 "ext_array[5];");
10580 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010581 CHECK_EQ(0,
10582 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010583
10584 result = CompileRun("for (var i = 0; i < 8; i++) {"
10585 " ext_array[i] = 5;"
10586 "}"
10587 "for (var i = 0; i < 8; i++) {"
10588 " ext_array[i] = Infinity;"
10589 "}"
10590 "ext_array[5];");
10591 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010592 CHECK_EQ(0,
10593 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000010594
10595 result = CompileRun("for (var i = 0; i < 8; i++) {"
10596 " ext_array[i] = 5;"
10597 "}"
10598 "for (var i = 0; i < 8; i++) {"
10599 " ext_array[i] = -Infinity;"
10600 "}"
10601 "ext_array[5];");
10602 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010603 CHECK_EQ(0,
10604 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000010605
10606 // Check truncation behavior of integral arrays.
10607 const char* unsigned_data =
10608 "var source_data = [0.6, 10.6];"
10609 "var expected_results = [0, 10];";
10610 const char* signed_data =
10611 "var source_data = [0.6, 10.6, -0.6, -10.6];"
10612 "var expected_results = [0, 10, 0, -10];";
10613 bool is_unsigned =
10614 (array_type == v8::kExternalUnsignedByteArray ||
10615 array_type == v8::kExternalUnsignedShortArray ||
10616 array_type == v8::kExternalUnsignedIntArray);
10617
10618 i::OS::SNPrintF(test_buf,
10619 "%s"
10620 "var all_passed = true;"
10621 "for (var i = 0; i < source_data.length; i++) {"
10622 " for (var j = 0; j < 8; j++) {"
10623 " ext_array[j] = source_data[i];"
10624 " }"
10625 " all_passed = all_passed &&"
10626 " (ext_array[5] == expected_results[i]);"
10627 "}"
10628 "all_passed;",
10629 (is_unsigned ? unsigned_data : signed_data));
10630 result = CompileRun(test_buf.start());
10631 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000010632 }
10633
10634 result = CompileRun("ext_array[3] = 33;"
10635 "delete ext_array[3];"
10636 "ext_array[3];");
10637 CHECK_EQ(33, result->Int32Value());
10638
10639 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10640 "ext_array[2] = 12; ext_array[3] = 13;"
10641 "ext_array.__defineGetter__('2',"
10642 "function() { return 120; });"
10643 "ext_array[2];");
10644 CHECK_EQ(12, result->Int32Value());
10645
10646 result = CompileRun("var js_array = new Array(40);"
10647 "js_array[0] = 77;"
10648 "js_array;");
10649 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10650
10651 result = CompileRun("ext_array[1] = 23;"
10652 "ext_array.__proto__ = [];"
10653 "js_array.__proto__ = ext_array;"
10654 "js_array.concat(ext_array);");
10655 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10656 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10657
10658 result = CompileRun("ext_array[1] = 23;");
10659 CHECK_EQ(23, result->Int32Value());
10660
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010661 // Test more complex manipulations which cause eax to contain values
10662 // that won't be completely overwritten by loads from the arrays.
10663 // This catches bugs in the instructions used for the KeyedLoadIC
10664 // for byte and word types.
10665 {
10666 const int kXSize = 300;
10667 const int kYSize = 300;
10668 const int kLargeElementCount = kXSize * kYSize * 4;
10669 ElementType* large_array_data =
10670 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10671 i::Handle<ExternalArrayClass> large_array =
10672 i::Handle<ExternalArrayClass>::cast(
10673 i::Factory::NewExternalArray(kLargeElementCount,
10674 array_type,
10675 array_data));
10676 v8::Handle<v8::Object> large_obj = v8::Object::New();
10677 // Set the elements to be the external array.
10678 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10679 array_type,
10680 kLargeElementCount);
10681 context->Global()->Set(v8_str("large_array"), large_obj);
10682 // Initialize contents of a few rows.
10683 for (int x = 0; x < 300; x++) {
10684 int row = 0;
10685 int offset = row * 300 * 4;
10686 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10687 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10688 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10689 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10690 row = 150;
10691 offset = row * 300 * 4;
10692 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10693 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10694 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10695 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10696 row = 298;
10697 offset = row * 300 * 4;
10698 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10699 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10700 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10701 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10702 }
10703 // The goal of the code below is to make "offset" large enough
10704 // that the computation of the index (which goes into eax) has
10705 // high bits set which will not be overwritten by a byte or short
10706 // load.
10707 result = CompileRun("var failed = false;"
10708 "var offset = 0;"
10709 "for (var i = 0; i < 300; i++) {"
10710 " if (large_array[4 * i] != 127 ||"
10711 " large_array[4 * i + 1] != 0 ||"
10712 " large_array[4 * i + 2] != 0 ||"
10713 " large_array[4 * i + 3] != 127) {"
10714 " failed = true;"
10715 " }"
10716 "}"
10717 "offset = 150 * 300 * 4;"
10718 "for (var i = 0; i < 300; i++) {"
10719 " if (large_array[offset + 4 * i] != 127 ||"
10720 " large_array[offset + 4 * i + 1] != 0 ||"
10721 " large_array[offset + 4 * i + 2] != 0 ||"
10722 " large_array[offset + 4 * i + 3] != 127) {"
10723 " failed = true;"
10724 " }"
10725 "}"
10726 "offset = 298 * 300 * 4;"
10727 "for (var i = 0; i < 300; i++) {"
10728 " if (large_array[offset + 4 * i] != 127 ||"
10729 " large_array[offset + 4 * i + 1] != 0 ||"
10730 " large_array[offset + 4 * i + 2] != 0 ||"
10731 " large_array[offset + 4 * i + 3] != 127) {"
10732 " failed = true;"
10733 " }"
10734 "}"
10735 "!failed;");
10736 CHECK_EQ(true, result->BooleanValue());
10737 free(large_array_data);
10738 }
10739
ager@chromium.org3811b432009-10-28 14:53:37 +000010740 free(array_data);
10741}
10742
10743
10744THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010745 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010746 v8::kExternalByteArray,
10747 -128,
10748 127);
10749}
10750
10751
10752THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010753 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010754 v8::kExternalUnsignedByteArray,
10755 0,
10756 255);
10757}
10758
10759
10760THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010761 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010762 v8::kExternalShortArray,
10763 -32768,
10764 32767);
10765}
10766
10767
10768THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010769 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010770 v8::kExternalUnsignedShortArray,
10771 0,
10772 65535);
10773}
10774
10775
10776THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010777 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010778 v8::kExternalIntArray,
10779 INT_MIN, // -2147483648
10780 INT_MAX); // 2147483647
10781}
10782
10783
10784THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010785 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010786 v8::kExternalUnsignedIntArray,
10787 0,
10788 UINT_MAX); // 4294967295
10789}
10790
10791
10792THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010793 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000010794 v8::kExternalFloatArray,
10795 -500,
10796 500);
10797}
10798
10799
10800THREADED_TEST(ExternalArrays) {
10801 TestExternalByteArray();
10802 TestExternalUnsignedByteArray();
10803 TestExternalShortArray();
10804 TestExternalUnsignedShortArray();
10805 TestExternalIntArray();
10806 TestExternalUnsignedIntArray();
10807 TestExternalFloatArray();
10808}
10809
10810
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000010811void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10812 v8::HandleScope scope;
10813 LocalContext context;
10814 for (int size = 0; size < 100; size += 10) {
10815 int element_size = ExternalArrayElementSize(array_type);
10816 void* external_data = malloc(size * element_size);
10817 v8::Handle<v8::Object> obj = v8::Object::New();
10818 obj->SetIndexedPropertiesToExternalArrayData(
10819 external_data, array_type, size);
10820 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10821 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10822 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10823 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10824 free(external_data);
10825 }
10826}
10827
10828
10829THREADED_TEST(ExternalArrayInfo) {
10830 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10831 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10832 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10833 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10834 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10835 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10836 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10837}
10838
10839
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010840THREADED_TEST(ScriptContextDependence) {
10841 v8::HandleScope scope;
10842 LocalContext c1;
10843 const char *source = "foo";
10844 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10845 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10846 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10847 CHECK_EQ(dep->Run()->Int32Value(), 100);
10848 CHECK_EQ(indep->Run()->Int32Value(), 100);
10849 LocalContext c2;
10850 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10851 CHECK_EQ(dep->Run()->Int32Value(), 100);
10852 CHECK_EQ(indep->Run()->Int32Value(), 101);
10853}
10854
ager@chromium.org96c75b52009-08-26 09:13:16 +000010855
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010856THREADED_TEST(StackTrace) {
10857 v8::HandleScope scope;
10858 LocalContext context;
10859 v8::TryCatch try_catch;
10860 const char *source = "function foo() { FAIL.FAIL; }; foo();";
10861 v8::Handle<v8::String> src = v8::String::New(source);
10862 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10863 v8::Script::New(src, origin)->Run();
10864 CHECK(try_catch.HasCaught());
10865 v8::String::Utf8Value stack(try_catch.StackTrace());
10866 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10867}
ager@chromium.org96c75b52009-08-26 09:13:16 +000010868
10869
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010870// Checks that a StackFrame has certain expected values.
10871void checkStackFrame(const char* expected_script_name,
10872 const char* expected_func_name, int expected_line_number,
10873 int expected_column, bool is_eval, bool is_constructor,
10874 v8::Handle<v8::StackFrame> frame) {
10875 v8::HandleScope scope;
10876 v8::String::Utf8Value func_name(frame->GetFunctionName());
10877 v8::String::Utf8Value script_name(frame->GetScriptName());
10878 if (*script_name == NULL) {
10879 // The situation where there is no associated script, like for evals.
10880 CHECK(expected_script_name == NULL);
10881 } else {
10882 CHECK(strstr(*script_name, expected_script_name) != NULL);
10883 }
10884 CHECK(strstr(*func_name, expected_func_name) != NULL);
10885 CHECK_EQ(expected_line_number, frame->GetLineNumber());
10886 CHECK_EQ(expected_column, frame->GetColumn());
10887 CHECK_EQ(is_eval, frame->IsEval());
10888 CHECK_EQ(is_constructor, frame->IsConstructor());
10889}
10890
10891
10892v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10893 v8::HandleScope scope;
10894 const char* origin = "capture-stack-trace-test";
10895 const int kOverviewTest = 1;
10896 const int kDetailedTest = 2;
10897
10898 ASSERT(args.Length() == 1);
10899
10900 int testGroup = args[0]->Int32Value();
10901 if (testGroup == kOverviewTest) {
10902 v8::Handle<v8::StackTrace> stackTrace =
10903 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10904 CHECK_EQ(4, stackTrace->GetFrameCount());
10905 checkStackFrame(origin, "bar", 2, 10, false, false,
10906 stackTrace->GetFrame(0));
10907 checkStackFrame(origin, "foo", 6, 3, false, false,
10908 stackTrace->GetFrame(1));
10909 checkStackFrame(NULL, "", 1, 1, false, false,
10910 stackTrace->GetFrame(2));
10911 // The last frame is an anonymous function that has the initial call.
10912 checkStackFrame(origin, "", 8, 7, false, false,
10913 stackTrace->GetFrame(3));
10914
10915 CHECK(stackTrace->AsArray()->IsArray());
10916 } else if (testGroup == kDetailedTest) {
10917 v8::Handle<v8::StackTrace> stackTrace =
10918 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10919 CHECK_EQ(4, stackTrace->GetFrameCount());
10920 checkStackFrame(origin, "bat", 4, 22, false, false,
10921 stackTrace->GetFrame(0));
10922 checkStackFrame(origin, "baz", 8, 3, false, true,
10923 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010924#ifdef ENABLE_DEBUGGER_SUPPORT
10925 bool is_eval = true;
10926#else // ENABLE_DEBUGGER_SUPPORT
10927 bool is_eval = false;
10928#endif // ENABLE_DEBUGGER_SUPPORT
10929
10930 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010931 stackTrace->GetFrame(2));
10932 // The last frame is an anonymous function that has the initial call to foo.
10933 checkStackFrame(origin, "", 10, 1, false, false,
10934 stackTrace->GetFrame(3));
10935
10936 CHECK(stackTrace->AsArray()->IsArray());
10937 }
10938 return v8::Undefined();
10939}
10940
10941
10942// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010943// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10944// THREADED_TEST(CaptureStackTrace) {
10945TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000010946 v8::HandleScope scope;
10947 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10948 Local<ObjectTemplate> templ = ObjectTemplate::New();
10949 templ->Set(v8_str("AnalyzeStackInNativeCode"),
10950 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10951 LocalContext context(0, templ);
10952
10953 // Test getting OVERVIEW information. Should ignore information that is not
10954 // script name, function name, line number, and column offset.
10955 const char *overview_source =
10956 "function bar() {\n"
10957 " var y; AnalyzeStackInNativeCode(1);\n"
10958 "}\n"
10959 "function foo() {\n"
10960 "\n"
10961 " bar();\n"
10962 "}\n"
10963 "var x;eval('new foo();');";
10964 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10965 v8::Handle<Value> overview_result =
10966 v8::Script::New(overview_src, origin)->Run();
10967 ASSERT(!overview_result.IsEmpty());
10968 ASSERT(overview_result->IsObject());
10969
10970 // Test getting DETAILED information.
10971 const char *detailed_source =
10972 "function bat() {AnalyzeStackInNativeCode(2);\n"
10973 "}\n"
10974 "\n"
10975 "function baz() {\n"
10976 " bat();\n"
10977 "}\n"
10978 "eval('new baz();');";
10979 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10980 // Make the script using a non-zero line and column offset.
10981 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10982 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10983 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10984 v8::Handle<v8::Script> detailed_script(
10985 v8::Script::New(detailed_src, &detailed_origin));
10986 v8::Handle<Value> detailed_result = detailed_script->Run();
10987 ASSERT(!detailed_result.IsEmpty());
10988 ASSERT(detailed_result->IsObject());
10989}
10990
10991
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010992static void StackTraceForUncaughtExceptionListener(
10993 v8::Handle<v8::Message> message,
10994 v8::Handle<Value>) {
10995 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10996 CHECK_EQ(2, stack_trace->GetFrameCount());
10997 checkStackFrame("origin", "foo", 2, 3, false, false,
10998 stack_trace->GetFrame(0));
10999 checkStackFrame("origin", "bar", 5, 3, false, false,
11000 stack_trace->GetFrame(1));
11001}
11002
11003TEST(CaptureStackTraceForUncaughtException) {
11004 report_count = 0;
11005 v8::HandleScope scope;
11006 LocalContext env;
11007 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
11008 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
11009
11010 Script::Compile(v8_str("function foo() {\n"
11011 " throw 1;\n"
11012 "};\n"
11013 "function bar() {\n"
11014 " foo();\n"
11015 "};"),
11016 v8_str("origin"))->Run();
11017 v8::Local<v8::Object> global = env->Global();
11018 Local<Value> trouble = global->Get(v8_str("bar"));
11019 CHECK(trouble->IsFunction());
11020 Function::Cast(*trouble)->Call(global, 0, NULL);
11021 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
11022 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
11023}
11024
11025
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000011026v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
11027 v8::HandleScope scope;
11028 v8::Handle<v8::StackTrace> stackTrace =
11029 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
11030 CHECK_EQ(5, stackTrace->GetFrameCount());
11031 v8::Handle<v8::String> url = v8_str("eval_url");
11032 for (int i = 0; i < 3; i++) {
11033 v8::Handle<v8::String> name =
11034 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
11035 CHECK(!name.IsEmpty());
11036 CHECK_EQ(url, name);
11037 }
11038 return v8::Undefined();
11039}
11040
11041
11042TEST(SourceURLInStackTrace) {
11043 v8::HandleScope scope;
11044 Local<ObjectTemplate> templ = ObjectTemplate::New();
11045 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
11046 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
11047 LocalContext context(0, templ);
11048
11049 const char *source =
11050 "function outer() {\n"
11051 "function bar() {\n"
11052 " AnalyzeStackOfEvalWithSourceURL();\n"
11053 "}\n"
11054 "function foo() {\n"
11055 "\n"
11056 " bar();\n"
11057 "}\n"
11058 "foo();\n"
11059 "}\n"
11060 "eval('(' + outer +')()//@ sourceURL=eval_url');";
11061 CHECK(CompileRun(source)->IsUndefined());
11062}
11063
11064
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011065// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000011066THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011067 bool rv = false;
11068 for (int i = 0; i < 100; i++) {
11069 rv = v8::V8::IdleNotification();
11070 if (rv)
11071 break;
11072 }
11073 CHECK(rv == true);
11074}
11075
11076
11077static uint32_t* stack_limit;
11078
11079static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000011080 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011081 return v8::Undefined();
11082}
11083
11084
11085// Uses the address of a local variable to determine the stack top now.
11086// Given a size, returns an address that is that far from the current
11087// top of stack.
11088static uint32_t* ComputeStackLimit(uint32_t size) {
11089 uint32_t* answer = &size - (size / sizeof(size));
11090 // If the size is very large and the stack is very near the bottom of
11091 // memory then the calculation above may wrap around and give an address
11092 // that is above the (downwards-growing) stack. In that case we return
11093 // a very low address.
11094 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
11095 return answer;
11096}
11097
11098
11099TEST(SetResourceConstraints) {
11100 static const int K = 1024;
11101 uint32_t* set_limit = ComputeStackLimit(128 * K);
11102
11103 // Set stack limit.
11104 v8::ResourceConstraints constraints;
11105 constraints.set_stack_limit(set_limit);
11106 CHECK(v8::SetResourceConstraints(&constraints));
11107
11108 // Execute a script.
11109 v8::HandleScope scope;
11110 LocalContext env;
11111 Local<v8::FunctionTemplate> fun_templ =
11112 v8::FunctionTemplate::New(GetStackLimitCallback);
11113 Local<Function> fun = fun_templ->GetFunction();
11114 env->Global()->Set(v8_str("get_stack_limit"), fun);
11115 CompileRun("get_stack_limit();");
11116
11117 CHECK(stack_limit == set_limit);
11118}
11119
11120
11121TEST(SetResourceConstraintsInThread) {
11122 uint32_t* set_limit;
11123 {
11124 v8::Locker locker;
11125 static const int K = 1024;
11126 set_limit = ComputeStackLimit(128 * K);
11127
11128 // Set stack limit.
11129 v8::ResourceConstraints constraints;
11130 constraints.set_stack_limit(set_limit);
11131 CHECK(v8::SetResourceConstraints(&constraints));
11132
11133 // Execute a script.
11134 v8::HandleScope scope;
11135 LocalContext env;
11136 Local<v8::FunctionTemplate> fun_templ =
11137 v8::FunctionTemplate::New(GetStackLimitCallback);
11138 Local<Function> fun = fun_templ->GetFunction();
11139 env->Global()->Set(v8_str("get_stack_limit"), fun);
11140 CompileRun("get_stack_limit();");
11141
11142 CHECK(stack_limit == set_limit);
11143 }
11144 {
11145 v8::Locker locker;
11146 CHECK(stack_limit == set_limit);
11147 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000011148}
ager@chromium.org3811b432009-10-28 14:53:37 +000011149
11150
11151THREADED_TEST(GetHeapStatistics) {
11152 v8::HandleScope scope;
11153 LocalContext c1;
11154 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011155 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11156 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011157 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011158 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11159 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000011160}
11161
11162
11163static double DoubleFromBits(uint64_t value) {
11164 double target;
11165#ifdef BIG_ENDIAN_FLOATING_POINT
11166 const int kIntSize = 4;
11167 // Somebody swapped the lower and higher half of doubles.
11168 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11169 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11170#else
11171 memcpy(&target, &value, sizeof(target));
11172#endif
11173 return target;
11174}
11175
11176
11177static uint64_t DoubleToBits(double value) {
11178 uint64_t target;
11179#ifdef BIG_ENDIAN_FLOATING_POINT
11180 const int kIntSize = 4;
11181 // Somebody swapped the lower and higher half of doubles.
11182 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11183 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11184#else
11185 memcpy(&target, &value, sizeof(target));
11186#endif
11187 return target;
11188}
11189
11190
11191static double DoubleToDateTime(double input) {
11192 double date_limit = 864e13;
11193 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11194 return i::OS::nan_value();
11195 }
11196 return (input < 0) ? -(floor(-input)) : floor(input);
11197}
11198
11199// We don't have a consistent way to write 64-bit constants syntactically, so we
11200// split them into two 32-bit constants and combine them programmatically.
11201static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11202 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11203}
11204
11205
11206THREADED_TEST(QuietSignalingNaNs) {
11207 v8::HandleScope scope;
11208 LocalContext context;
11209 v8::TryCatch try_catch;
11210
11211 // Special double values.
11212 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11213 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11214 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11215 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11216 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11217 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11218 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11219
11220 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11221 // on either side of the epoch.
11222 double date_limit = 864e13;
11223
11224 double test_values[] = {
11225 snan,
11226 qnan,
11227 infinity,
11228 max_normal,
11229 date_limit + 1,
11230 date_limit,
11231 min_normal,
11232 max_denormal,
11233 min_denormal,
11234 0,
11235 -0,
11236 -min_denormal,
11237 -max_denormal,
11238 -min_normal,
11239 -date_limit,
11240 -date_limit - 1,
11241 -max_normal,
11242 -infinity,
11243 -qnan,
11244 -snan
11245 };
11246 int num_test_values = 20;
11247
11248 for (int i = 0; i < num_test_values; i++) {
11249 double test_value = test_values[i];
11250
11251 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11252 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11253 double stored_number = number->NumberValue();
11254 if (!IsNaN(test_value)) {
11255 CHECK_EQ(test_value, stored_number);
11256 } else {
11257 uint64_t stored_bits = DoubleToBits(stored_number);
11258 // Check if quiet nan (bits 51..62 all set).
11259 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11260 }
11261
11262 // Check that Date::New preserves non-NaNs in the date range and
11263 // quiets SNaNs.
11264 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11265 double expected_stored_date = DoubleToDateTime(test_value);
11266 double stored_date = date->NumberValue();
11267 if (!IsNaN(expected_stored_date)) {
11268 CHECK_EQ(expected_stored_date, stored_date);
11269 } else {
11270 uint64_t stored_bits = DoubleToBits(stored_date);
11271 // Check if quiet nan (bits 51..62 all set).
11272 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11273 }
11274 }
11275}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000011276
11277
11278static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11279 v8::HandleScope scope;
11280 v8::TryCatch tc;
11281 v8::Handle<v8::String> str = args[0]->ToString();
11282 if (tc.HasCaught())
11283 return tc.ReThrow();
11284 return v8::Undefined();
11285}
11286
11287
11288// Test that an exception can be propagated down through a spaghetti
11289// stack using ReThrow.
11290THREADED_TEST(SpaghettiStackReThrow) {
11291 v8::HandleScope scope;
11292 LocalContext context;
11293 context->Global()->Set(
11294 v8::String::New("s"),
11295 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11296 v8::TryCatch try_catch;
11297 CompileRun(
11298 "var i = 0;"
11299 "var o = {"
11300 " toString: function () {"
11301 " if (i == 10) {"
11302 " throw 'Hey!';"
11303 " } else {"
11304 " i++;"
11305 " return s(o);"
11306 " }"
11307 " }"
11308 "};"
11309 "s(o);");
11310 CHECK(try_catch.HasCaught());
11311 v8::String::Utf8Value value(try_catch.Exception());
11312 CHECK_EQ(0, strcmp(*value, "Hey!"));
11313}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011314
11315
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011316TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011317 v8::V8::Initialize();
11318
11319 v8::HandleScope scope;
11320 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000011321 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011322 int gc_count;
11323
ager@chromium.org60121232009-12-03 11:25:37 +000011324 // Create a context used to keep the code from aging in the compilation
11325 // cache.
11326 other_context = Context::New();
11327
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011328 // Context-dependent context data creates reference from the compilation
11329 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011330 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011331 context = Context::New();
11332 {
11333 v8::HandleScope scope;
11334
11335 context->Enter();
11336 Local<v8::String> obj = v8::String::New("");
11337 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000011338 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011339 context->Exit();
11340 }
11341 context.Dispose();
11342 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011343 other_context->Enter();
11344 CompileRun(source_simple);
11345 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011346 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011347 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011348 }
ager@chromium.org60121232009-12-03 11:25:37 +000011349 CHECK_GE(2, gc_count);
11350 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011351
11352 // Eval in a function creates reference from the compilation cache to the
11353 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011354 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011355 context = Context::New();
11356 {
11357 v8::HandleScope scope;
11358
11359 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000011360 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011361 context->Exit();
11362 }
11363 context.Dispose();
11364 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011365 other_context->Enter();
11366 CompileRun(source_eval);
11367 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011368 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011369 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011370 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011371 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000011372 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011373
11374 // Looking up the line number for an exception creates reference from the
11375 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000011376 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011377 context = Context::New();
11378 {
11379 v8::HandleScope scope;
11380
11381 context->Enter();
11382 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000011383 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011384 CHECK(try_catch.HasCaught());
11385 v8::Handle<v8::Message> message = try_catch.Message();
11386 CHECK(!message.IsEmpty());
11387 CHECK_EQ(1, message->GetLineNumber());
11388 context->Exit();
11389 }
11390 context.Dispose();
11391 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000011392 other_context->Enter();
11393 CompileRun(source_exception);
11394 other_context->Exit();
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011395 i::Heap::CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000011396 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011397 }
ager@chromium.org60121232009-12-03 11:25:37 +000011398 CHECK_GE(2, gc_count);
11399 CHECK_EQ(1, GetGlobalObjectsCount());
11400
11401 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000011402}
ager@chromium.org5c838252010-02-19 08:53:10 +000011403
11404
11405THREADED_TEST(ScriptOrigin) {
11406 v8::HandleScope scope;
11407 LocalContext env;
11408 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11409 v8::Handle<v8::String> script = v8::String::New(
11410 "function f() {}\n\nfunction g() {}");
11411 v8::Script::Compile(script, &origin)->Run();
11412 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11413 env->Global()->Get(v8::String::New("f")));
11414 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11415 env->Global()->Get(v8::String::New("g")));
11416
11417 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11418 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11419 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11420
11421 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11422 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11423 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11424}
11425
11426
11427THREADED_TEST(ScriptLineNumber) {
11428 v8::HandleScope scope;
11429 LocalContext env;
11430 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11431 v8::Handle<v8::String> script = v8::String::New(
11432 "function f() {}\n\nfunction g() {}");
11433 v8::Script::Compile(script, &origin)->Run();
11434 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11435 env->Global()->Get(v8::String::New("f")));
11436 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11437 env->Global()->Get(v8::String::New("g")));
11438 CHECK_EQ(0, f->GetScriptLineNumber());
11439 CHECK_EQ(2, g->GetScriptLineNumber());
11440}
11441
11442
11443static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11444 const AccessorInfo& info) {
11445 return v8_num(42);
11446}
11447
11448
11449static void SetterWhichSetsYOnThisTo23(Local<String> name,
11450 Local<Value> value,
11451 const AccessorInfo& info) {
11452 info.This()->Set(v8_str("y"), v8_num(23));
11453}
11454
11455
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011456TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000011457 v8::HandleScope scope;
11458 Local<ObjectTemplate> templ = ObjectTemplate::New();
11459 templ->SetAccessor(v8_str("x"),
11460 GetterWhichReturns42,
11461 SetterWhichSetsYOnThisTo23);
11462 LocalContext context;
11463 context->Global()->Set(v8_str("P"), templ->NewInstance());
11464 CompileRun("function C1() {"
11465 " this.x = 23;"
11466 "};"
11467 "C1.prototype = P;"
11468 "function C2() {"
11469 " this.x = 23"
11470 "};"
11471 "C2.prototype = { };"
11472 "C2.prototype.__proto__ = P;");
11473
11474 v8::Local<v8::Script> script;
11475 script = v8::Script::Compile(v8_str("new C1();"));
11476 for (int i = 0; i < 10; i++) {
11477 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11478 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11479 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11480 }
11481
11482 script = v8::Script::Compile(v8_str("new C2();"));
11483 for (int i = 0; i < 10; i++) {
11484 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11485 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11486 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11487 }
11488}
11489
11490
11491static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11492 Local<String> name, const AccessorInfo& info) {
11493 return v8_num(42);
11494}
11495
11496
11497static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11498 Local<String> name, Local<Value> value, const AccessorInfo& info) {
11499 if (name->Equals(v8_str("x"))) {
11500 info.This()->Set(v8_str("y"), v8_num(23));
11501 }
11502 return v8::Handle<Value>();
11503}
11504
11505
11506THREADED_TEST(InterceptorOnConstructorPrototype) {
11507 v8::HandleScope scope;
11508 Local<ObjectTemplate> templ = ObjectTemplate::New();
11509 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11510 NamedPropertySetterWhichSetsYOnThisTo23);
11511 LocalContext context;
11512 context->Global()->Set(v8_str("P"), templ->NewInstance());
11513 CompileRun("function C1() {"
11514 " this.x = 23;"
11515 "};"
11516 "C1.prototype = P;"
11517 "function C2() {"
11518 " this.x = 23"
11519 "};"
11520 "C2.prototype = { };"
11521 "C2.prototype.__proto__ = P;");
11522
11523 v8::Local<v8::Script> script;
11524 script = v8::Script::Compile(v8_str("new C1();"));
11525 for (int i = 0; i < 10; i++) {
11526 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11527 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11528 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11529 }
11530
11531 script = v8::Script::Compile(v8_str("new C2();"));
11532 for (int i = 0; i < 10; i++) {
11533 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11534 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11535 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11536 }
11537}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011538
11539
11540TEST(Bug618) {
11541 const char* source = "function C1() {"
11542 " this.x = 23;"
11543 "};"
11544 "C1.prototype = P;";
11545
11546 v8::HandleScope scope;
11547 LocalContext context;
11548 v8::Local<v8::Script> script;
11549
11550 // Use a simple object as prototype.
11551 v8::Local<v8::Object> prototype = v8::Object::New();
11552 prototype->Set(v8_str("y"), v8_num(42));
11553 context->Global()->Set(v8_str("P"), prototype);
11554
11555 // This compile will add the code to the compilation cache.
11556 CompileRun(source);
11557
11558 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011559 // Allow enough iterations for the inobject slack tracking logic
11560 // to finalize instance size and install the fast construct stub.
11561 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011562 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11563 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11564 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11565 }
11566
11567 // Use an API object with accessors as prototype.
11568 Local<ObjectTemplate> templ = ObjectTemplate::New();
11569 templ->SetAccessor(v8_str("x"),
11570 GetterWhichReturns42,
11571 SetterWhichSetsYOnThisTo23);
11572 context->Global()->Set(v8_str("P"), templ->NewInstance());
11573
11574 // This compile will get the code from the compilation cache.
11575 CompileRun(source);
11576
11577 script = v8::Script::Compile(v8_str("new C1();"));
11578 for (int i = 0; i < 10; i++) {
11579 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11580 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11581 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11582 }
11583}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011584
11585int prologue_call_count = 0;
11586int epilogue_call_count = 0;
11587int prologue_call_count_second = 0;
11588int epilogue_call_count_second = 0;
11589
11590void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11591 ++prologue_call_count;
11592}
11593
11594void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11595 ++epilogue_call_count;
11596}
11597
11598void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11599 ++prologue_call_count_second;
11600}
11601
11602void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11603 ++epilogue_call_count_second;
11604}
11605
11606TEST(GCCallbacks) {
11607 LocalContext context;
11608
11609 v8::V8::AddGCPrologueCallback(PrologueCallback);
11610 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11611 CHECK_EQ(0, prologue_call_count);
11612 CHECK_EQ(0, epilogue_call_count);
11613 i::Heap::CollectAllGarbage(false);
11614 CHECK_EQ(1, prologue_call_count);
11615 CHECK_EQ(1, epilogue_call_count);
11616 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11617 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11618 i::Heap::CollectAllGarbage(false);
11619 CHECK_EQ(2, prologue_call_count);
11620 CHECK_EQ(2, epilogue_call_count);
11621 CHECK_EQ(1, prologue_call_count_second);
11622 CHECK_EQ(1, epilogue_call_count_second);
11623 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11624 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11625 i::Heap::CollectAllGarbage(false);
11626 CHECK_EQ(2, prologue_call_count);
11627 CHECK_EQ(2, epilogue_call_count);
11628 CHECK_EQ(2, prologue_call_count_second);
11629 CHECK_EQ(2, epilogue_call_count_second);
11630 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11631 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11632 i::Heap::CollectAllGarbage(false);
11633 CHECK_EQ(2, prologue_call_count);
11634 CHECK_EQ(2, epilogue_call_count);
11635 CHECK_EQ(2, prologue_call_count_second);
11636 CHECK_EQ(2, epilogue_call_count_second);
11637}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011638
11639
11640THREADED_TEST(AddToJSFunctionResultCache) {
11641 i::FLAG_allow_natives_syntax = true;
11642 v8::HandleScope scope;
11643
11644 LocalContext context;
11645
11646 const char* code =
11647 "(function() {"
11648 " var key0 = 'a';"
11649 " var key1 = 'b';"
11650 " var r0 = %_GetFromCache(0, key0);"
11651 " var r1 = %_GetFromCache(0, key1);"
11652 " var r0_ = %_GetFromCache(0, key0);"
11653 " if (r0 !== r0_)"
11654 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11655 " var r1_ = %_GetFromCache(0, key1);"
11656 " if (r1 !== r1_)"
11657 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11658 " return 'PASSED';"
11659 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011660 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011661 ExpectString(code, "PASSED");
11662}
11663
11664
11665static const int k0CacheSize = 16;
11666
11667THREADED_TEST(FillJSFunctionResultCache) {
11668 i::FLAG_allow_natives_syntax = true;
11669 v8::HandleScope scope;
11670
11671 LocalContext context;
11672
11673 const char* code =
11674 "(function() {"
11675 " var k = 'a';"
11676 " var r = %_GetFromCache(0, k);"
11677 " for (var i = 0; i < 16; i++) {"
11678 " %_GetFromCache(0, 'a' + i);"
11679 " };"
11680 " if (r === %_GetFromCache(0, k))"
11681 " return 'FAILED: k0CacheSize is too small';"
11682 " return 'PASSED';"
11683 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011684 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011685 ExpectString(code, "PASSED");
11686}
11687
11688
11689THREADED_TEST(RoundRobinGetFromCache) {
11690 i::FLAG_allow_natives_syntax = true;
11691 v8::HandleScope scope;
11692
11693 LocalContext context;
11694
11695 const char* code =
11696 "(function() {"
11697 " var keys = [];"
11698 " for (var i = 0; i < 16; i++) keys.push(i);"
11699 " var values = [];"
11700 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11701 " for (var i = 0; i < 16; i++) {"
11702 " var v = %_GetFromCache(0, keys[i]);"
11703 " if (v !== values[i])"
11704 " return 'Wrong value for ' + "
11705 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11706 " };"
11707 " return 'PASSED';"
11708 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011709 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011710 ExpectString(code, "PASSED");
11711}
11712
11713
11714THREADED_TEST(ReverseGetFromCache) {
11715 i::FLAG_allow_natives_syntax = true;
11716 v8::HandleScope scope;
11717
11718 LocalContext context;
11719
11720 const char* code =
11721 "(function() {"
11722 " var keys = [];"
11723 " for (var i = 0; i < 16; i++) keys.push(i);"
11724 " var values = [];"
11725 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11726 " for (var i = 15; i >= 16; i--) {"
11727 " var v = %_GetFromCache(0, keys[i]);"
11728 " if (v !== values[i])"
11729 " return 'Wrong value for ' + "
11730 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11731 " };"
11732 " return 'PASSED';"
11733 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011734 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011735 ExpectString(code, "PASSED");
11736}
11737
11738
11739THREADED_TEST(TestEviction) {
11740 i::FLAG_allow_natives_syntax = true;
11741 v8::HandleScope scope;
11742
11743 LocalContext context;
11744
11745 const char* code =
11746 "(function() {"
11747 " for (var i = 0; i < 2*16; i++) {"
11748 " %_GetFromCache(0, 'a' + i);"
11749 " };"
11750 " return 'PASSED';"
11751 "})()";
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011752 i::Heap::ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000011753 ExpectString(code, "PASSED");
11754}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011755
11756
11757THREADED_TEST(TwoByteStringInAsciiCons) {
11758 // See Chromium issue 47824.
11759 v8::HandleScope scope;
11760
11761 LocalContext context;
11762 const char* init_code =
11763 "var str1 = 'abelspendabel';"
11764 "var str2 = str1 + str1 + str1;"
11765 "str2;";
11766 Local<Value> result = CompileRun(init_code);
11767
11768 CHECK(result->IsString());
11769 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11770 int length = string->length();
11771 CHECK(string->IsAsciiRepresentation());
11772
11773 FlattenString(string);
11774 i::Handle<i::String> flat_string = FlattenGetString(string);
11775
11776 CHECK(string->IsAsciiRepresentation());
11777 CHECK(flat_string->IsAsciiRepresentation());
11778
11779 // Create external resource.
11780 uint16_t* uc16_buffer = new uint16_t[length + 1];
11781
11782 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11783 uc16_buffer[length] = 0;
11784
11785 TestResource resource(uc16_buffer);
11786
11787 flat_string->MakeExternal(&resource);
11788
11789 CHECK(flat_string->IsTwoByteRepresentation());
11790
11791 // At this point, we should have a Cons string which is flat and ASCII,
11792 // with a first half that is a two-byte string (although it only contains
11793 // ASCII characters). This is a valid sequence of steps, and it can happen
11794 // in real pages.
11795
11796 CHECK(string->IsAsciiRepresentation());
11797 i::ConsString* cons = i::ConsString::cast(*string);
11798 CHECK_EQ(0, cons->second()->length());
11799 CHECK(cons->first()->IsTwoByteRepresentation());
11800
11801 // Check that some string operations work.
11802
11803 // Atom RegExp.
11804 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11805 CHECK_EQ(6, reresult->Int32Value());
11806
11807 // Nonatom RegExp.
11808 reresult = CompileRun("str2.match(/abe./g).length;");
11809 CHECK_EQ(6, reresult->Int32Value());
11810
11811 reresult = CompileRun("str2.search(/bel/g);");
11812 CHECK_EQ(1, reresult->Int32Value());
11813
11814 reresult = CompileRun("str2.search(/be./g);");
11815 CHECK_EQ(1, reresult->Int32Value());
11816
11817 ExpectTrue("/bel/g.test(str2);");
11818
11819 ExpectTrue("/be./g.test(str2);");
11820
11821 reresult = CompileRun("/bel/g.exec(str2);");
11822 CHECK(!reresult->IsNull());
11823
11824 reresult = CompileRun("/be./g.exec(str2);");
11825 CHECK(!reresult->IsNull());
11826
11827 ExpectString("str2.substring(2, 10);", "elspenda");
11828
11829 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11830
11831 ExpectString("str2.charAt(2);", "e");
11832
11833 reresult = CompileRun("str2.charCodeAt(2);");
11834 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11835}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000011836
11837
11838// Failed access check callback that performs a GC on each invocation.
11839void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11840 v8::AccessType type,
11841 Local<v8::Value> data) {
11842 i::Heap::CollectAllGarbage(true);
11843}
11844
11845
11846TEST(GCInFailedAccessCheckCallback) {
11847 // Install a failed access check callback that performs a GC on each
11848 // invocation. Then force the callback to be called from va
11849
11850 v8::V8::Initialize();
11851 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11852
11853 v8::HandleScope scope;
11854
11855 // Create an ObjectTemplate for global objects and install access
11856 // check callbacks that will block access.
11857 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11858 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11859 IndexedGetAccessBlocker,
11860 v8::Handle<v8::Value>(),
11861 false);
11862
11863 // Create a context and set an x property on it's global object.
11864 LocalContext context0(NULL, global_template);
11865 context0->Global()->Set(v8_str("x"), v8_num(42));
11866 v8::Handle<v8::Object> global0 = context0->Global();
11867
11868 // Create a context with a different security token so that the
11869 // failed access check callback will be called on each access.
11870 LocalContext context1(NULL, global_template);
11871 context1->Global()->Set(v8_str("other"), global0);
11872
11873 // Get property with failed access check.
11874 ExpectUndefined("other.x");
11875
11876 // Get element with failed access check.
11877 ExpectUndefined("other[0]");
11878
11879 // Set property with failed access check.
11880 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11881 CHECK(result->IsObject());
11882
11883 // Set element with failed access check.
11884 result = CompileRun("other[0] = new Object()");
11885 CHECK(result->IsObject());
11886
11887 // Get property attribute with failed access check.
11888 ExpectFalse("\'x\' in other");
11889
11890 // Get property attribute for element with failed access check.
11891 ExpectFalse("0 in other");
11892
11893 // Delete property.
11894 ExpectFalse("delete other.x");
11895
11896 // Delete element.
11897 CHECK_EQ(false, global0->Delete(0));
11898
11899 // DefineAccessor.
11900 CHECK_EQ(false,
11901 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11902
11903 // Define JavaScript accessor.
11904 ExpectUndefined("Object.prototype.__defineGetter__.call("
11905 " other, \'x\', function() { return 42; })");
11906
11907 // LookupAccessor.
11908 ExpectUndefined("Object.prototype.__lookupGetter__.call("
11909 " other, \'x\')");
11910
11911 // HasLocalElement.
11912 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11913
11914 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11915 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11916 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11917
11918 // Reset the failed access check callback so it does not influence
11919 // the other tests.
11920 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11921}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011922
11923
11924TEST(StringCheckMultipleContexts) {
11925 const char* code =
11926 "(function() { return \"a\".charAt(0); })()";
11927
11928 {
11929 // Run the code twice in the first context to initialize the call IC.
11930 v8::HandleScope scope;
11931 LocalContext context1;
11932 ExpectString(code, "a");
11933 ExpectString(code, "a");
11934 }
11935
11936 {
11937 // Change the String.prototype in the second context and check
11938 // that the right function gets called.
11939 v8::HandleScope scope;
11940 LocalContext context2;
11941 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11942 ExpectString(code, "not a");
11943 }
11944}
11945
11946
11947TEST(NumberCheckMultipleContexts) {
11948 const char* code =
11949 "(function() { return (42).toString(); })()";
11950
11951 {
11952 // Run the code twice in the first context to initialize the call IC.
11953 v8::HandleScope scope;
11954 LocalContext context1;
11955 ExpectString(code, "42");
11956 ExpectString(code, "42");
11957 }
11958
11959 {
11960 // Change the Number.prototype in the second context and check
11961 // that the right function gets called.
11962 v8::HandleScope scope;
11963 LocalContext context2;
11964 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11965 ExpectString(code, "not 42");
11966 }
11967}
11968
11969
11970TEST(BooleanCheckMultipleContexts) {
11971 const char* code =
11972 "(function() { return true.toString(); })()";
11973
11974 {
11975 // Run the code twice in the first context to initialize the call IC.
11976 v8::HandleScope scope;
11977 LocalContext context1;
11978 ExpectString(code, "true");
11979 ExpectString(code, "true");
11980 }
11981
11982 {
11983 // Change the Boolean.prototype in the second context and check
11984 // that the right function gets called.
11985 v8::HandleScope scope;
11986 LocalContext context2;
11987 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11988 ExpectString(code, "");
11989 }
11990}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011991
11992
11993TEST(DontDeleteCellLoadIC) {
11994 const char* function_code =
11995 "function readCell() { while (true) { return cell; } }";
11996
11997 {
11998 // Run the code twice in the first context to initialize the load
11999 // IC for a don't delete cell.
12000 v8::HandleScope scope;
12001 LocalContext context1;
12002 CompileRun("var cell = \"first\";");
12003 ExpectBoolean("delete cell", false);
12004 CompileRun(function_code);
12005 ExpectString("readCell()", "first");
12006 ExpectString("readCell()", "first");
12007 }
12008
12009 {
12010 // Use a deletable cell in the second context.
12011 v8::HandleScope scope;
12012 LocalContext context2;
12013 CompileRun("cell = \"second\";");
12014 CompileRun(function_code);
12015 ExpectString("readCell()", "second");
12016 ExpectBoolean("delete cell", true);
12017 ExpectString("(function() {"
12018 " try {"
12019 " return readCell();"
12020 " } catch(e) {"
12021 " return e.toString();"
12022 " }"
12023 "})()",
12024 "ReferenceError: cell is not defined");
12025 CompileRun("cell = \"new_second\";");
12026 i::Heap::CollectAllGarbage(true);
12027 ExpectString("readCell()", "new_second");
12028 ExpectString("readCell()", "new_second");
12029 }
12030}
12031
12032
12033TEST(DontDeleteCellLoadICForceDelete) {
12034 const char* function_code =
12035 "function readCell() { while (true) { return cell; } }";
12036
12037 // Run the code twice to initialize the load IC for a don't delete
12038 // cell.
12039 v8::HandleScope scope;
12040 LocalContext context;
12041 CompileRun("var cell = \"value\";");
12042 ExpectBoolean("delete cell", false);
12043 CompileRun(function_code);
12044 ExpectString("readCell()", "value");
12045 ExpectString("readCell()", "value");
12046
12047 // Delete the cell using the API and check the inlined code works
12048 // correctly.
12049 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12050 ExpectString("(function() {"
12051 " try {"
12052 " return readCell();"
12053 " } catch(e) {"
12054 " return e.toString();"
12055 " }"
12056 "})()",
12057 "ReferenceError: cell is not defined");
12058}
12059
12060
12061TEST(DontDeleteCellLoadICAPI) {
12062 const char* function_code =
12063 "function readCell() { while (true) { return cell; } }";
12064
12065 // Run the code twice to initialize the load IC for a don't delete
12066 // cell created using the API.
12067 v8::HandleScope scope;
12068 LocalContext context;
12069 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
12070 ExpectBoolean("delete cell", false);
12071 CompileRun(function_code);
12072 ExpectString("readCell()", "value");
12073 ExpectString("readCell()", "value");
12074
12075 // Delete the cell using the API and check the inlined code works
12076 // correctly.
12077 CHECK(context->Global()->ForceDelete(v8_str("cell")));
12078 ExpectString("(function() {"
12079 " try {"
12080 " return readCell();"
12081 " } catch(e) {"
12082 " return e.toString();"
12083 " }"
12084 "})()",
12085 "ReferenceError: cell is not defined");
12086}
12087
12088
12089TEST(GlobalLoadICGC) {
12090 const char* function_code =
12091 "function readCell() { while (true) { return cell; } }";
12092
12093 // Check inline load code for a don't delete cell is cleared during
12094 // GC.
12095 {
12096 v8::HandleScope scope;
12097 LocalContext context;
12098 CompileRun("var cell = \"value\";");
12099 ExpectBoolean("delete cell", false);
12100 CompileRun(function_code);
12101 ExpectString("readCell()", "value");
12102 ExpectString("readCell()", "value");
12103 }
12104 {
12105 v8::HandleScope scope;
12106 LocalContext context2;
12107 // Hold the code object in the second context.
12108 CompileRun(function_code);
12109 CheckSurvivingGlobalObjectsCount(1);
12110 }
12111
12112 // Check inline load code for a deletable cell is cleared during GC.
12113 {
12114 v8::HandleScope scope;
12115 LocalContext context;
12116 CompileRun("cell = \"value\";");
12117 CompileRun(function_code);
12118 ExpectString("readCell()", "value");
12119 ExpectString("readCell()", "value");
12120 }
12121 {
12122 v8::HandleScope scope;
12123 LocalContext context2;
12124 // Hold the code object in the second context.
12125 CompileRun(function_code);
12126 CheckSurvivingGlobalObjectsCount(1);
12127 }
12128}
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012129
12130
12131TEST(RegExp) {
12132 v8::HandleScope scope;
12133 LocalContext context;
12134
12135 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
12136 CHECK(re->IsRegExp());
12137 CHECK(re->GetSource()->Equals(v8_str("foo")));
12138 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12139
12140 re = v8::RegExp::New(v8_str("bar"),
12141 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12142 v8::RegExp::kGlobal));
12143 CHECK(re->IsRegExp());
12144 CHECK(re->GetSource()->Equals(v8_str("bar")));
12145 CHECK_EQ(static_cast<int>(re->GetFlags()),
12146 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12147
12148 re = v8::RegExp::New(v8_str("baz"),
12149 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12150 v8::RegExp::kMultiline));
12151 CHECK(re->IsRegExp());
12152 CHECK(re->GetSource()->Equals(v8_str("baz")));
12153 CHECK_EQ(static_cast<int>(re->GetFlags()),
12154 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12155
12156 re = CompileRun("/quux/").As<v8::RegExp>();
12157 CHECK(re->IsRegExp());
12158 CHECK(re->GetSource()->Equals(v8_str("quux")));
12159 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12160
12161 re = CompileRun("/quux/gm").As<v8::RegExp>();
12162 CHECK(re->IsRegExp());
12163 CHECK(re->GetSource()->Equals(v8_str("quux")));
12164 CHECK_EQ(static_cast<int>(re->GetFlags()),
12165 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12166
12167 // Override the RegExp constructor and check the API constructor
12168 // still works.
12169 CompileRun("RegExp = function() {}");
12170
12171 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12172 CHECK(re->IsRegExp());
12173 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12174 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12175
12176 re = v8::RegExp::New(v8_str("foobarbaz"),
12177 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12178 v8::RegExp::kMultiline));
12179 CHECK(re->IsRegExp());
12180 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12181 CHECK_EQ(static_cast<int>(re->GetFlags()),
12182 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12183
12184 context->Global()->Set(v8_str("re"), re);
12185 ExpectTrue("re.test('FoobarbaZ')");
12186
12187 v8::TryCatch try_catch;
12188 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12189 CHECK(re.IsEmpty());
12190 CHECK(try_catch.HasCaught());
12191 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12192 ExpectTrue("ex instanceof SyntaxError");
12193}
12194
12195
12196static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12197 const v8::AccessorInfo& info ) {
12198 return v8_str("42!");
12199}
12200
12201
12202static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12203 v8::Handle<v8::Array> result = v8::Array::New();
12204 result->Set(0, v8_str("universalAnswer"));
12205 return result;
12206}
12207
12208
12209TEST(NamedEnumeratorAndForIn) {
12210 v8::HandleScope handle_scope;
12211 LocalContext context;
12212 v8::Context::Scope context_scope(context.local());
12213
12214 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12215 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12216 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12217 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12218 "var result = []; for (var k in o) result.push(k); result"));
12219 CHECK_EQ(1, result->Length());
12220 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12221}