blob: 28a9be159937b9f1399efa6f7de5e9734751ba55 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 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"
ager@chromium.org3811b432009-10-28 14:53:37 +000037#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000038#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000039#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000040#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000042static const bool kLogThreading = true;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000043
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000044static bool IsNaN(double x) {
45#ifdef WIN32
46 return _isnan(x);
47#else
48 return isnan(x);
49#endif
50}
51
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000052using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000053using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000054using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000055using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000056using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000057using ::v8::FunctionTemplate;
58using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000059using ::v8::HandleScope;
60using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000061using ::v8::Message;
62using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000063using ::v8::Object;
64using ::v8::ObjectTemplate;
65using ::v8::Persistent;
66using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000067using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000068using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000069using ::v8::TryCatch;
70using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000071using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000072using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000073
lrn@chromium.org32d961d2010-06-30 09:09:34 +000074namespace i = ::i;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000075
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000076
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000077static void ExpectString(const char* code, const char* expected) {
78 Local<Value> result = CompileRun(code);
79 CHECK(result->IsString());
80 String::AsciiValue ascii(result);
81 CHECK_EQ(expected, *ascii);
82}
83
84
85static void ExpectBoolean(const char* code, bool expected) {
86 Local<Value> result = CompileRun(code);
87 CHECK(result->IsBoolean());
88 CHECK_EQ(expected, result->BooleanValue());
89}
90
91
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000092static void ExpectTrue(const char* code) {
93 ExpectBoolean(code, true);
94}
95
96
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000097static void ExpectFalse(const char* code) {
98 ExpectBoolean(code, false);
99}
100
101
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000102static void ExpectObject(const char* code, Local<Value> expected) {
103 Local<Value> result = CompileRun(code);
104 CHECK(result->Equals(expected));
105}
106
107
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000108static void ExpectUndefined(const char* code) {
109 Local<Value> result = CompileRun(code);
110 CHECK(result->IsUndefined());
111}
112
113
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114static int signature_callback_count;
115static v8::Handle<Value> IncrementingSignatureCallback(
116 const v8::Arguments& args) {
117 ApiTestFuzzer::Fuzz();
118 signature_callback_count++;
119 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
120 for (int i = 0; i < args.Length(); i++)
121 result->Set(v8::Integer::New(i), args[i]);
122 return result;
123}
124
125
126static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
127 ApiTestFuzzer::Fuzz();
128 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
129 for (int i = 0; i < args.Length(); i++) {
130 result->Set(v8::Integer::New(i), args[i]);
131 }
132 return result;
133}
134
135
136THREADED_TEST(Handles) {
137 v8::HandleScope scope;
138 Local<Context> local_env;
139 {
140 LocalContext env;
141 local_env = env.local();
142 }
143
144 // Local context should still be live.
145 CHECK(!local_env.IsEmpty());
146 local_env->Enter();
147
148 v8::Handle<v8::Primitive> undef = v8::Undefined();
149 CHECK(!undef.IsEmpty());
150 CHECK(undef->IsUndefined());
151
152 const char* c_source = "1 + 2 + 3";
153 Local<String> source = String::New(c_source);
154 Local<Script> script = Script::Compile(source);
155 CHECK_EQ(6, script->Run()->Int32Value());
156
157 local_env->Exit();
158}
159
160
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000161THREADED_TEST(ReceiverSignature) {
162 v8::HandleScope scope;
163 LocalContext env;
164 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
165 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
166 fun->PrototypeTemplate()->Set(
167 v8_str("m"),
168 v8::FunctionTemplate::New(IncrementingSignatureCallback,
169 v8::Handle<Value>(),
170 sig));
171 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
172 signature_callback_count = 0;
173 CompileRun(
174 "var o = new Fun();"
175 "o.m();");
176 CHECK_EQ(1, signature_callback_count);
177 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
178 sub_fun->Inherit(fun);
179 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
180 CompileRun(
181 "var o = new SubFun();"
182 "o.m();");
183 CHECK_EQ(2, signature_callback_count);
184
185 v8::TryCatch try_catch;
186 CompileRun(
187 "var o = { };"
188 "o.m = Fun.prototype.m;"
189 "o.m();");
190 CHECK_EQ(2, signature_callback_count);
191 CHECK(try_catch.HasCaught());
192 try_catch.Reset();
193 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
194 sub_fun->Inherit(fun);
195 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
196 CompileRun(
197 "var o = new UnrelFun();"
198 "o.m = Fun.prototype.m;"
199 "o.m();");
200 CHECK_EQ(2, signature_callback_count);
201 CHECK(try_catch.HasCaught());
202}
203
204
205
206
207THREADED_TEST(ArgumentSignature) {
208 v8::HandleScope scope;
209 LocalContext env;
210 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
211 cons->SetClassName(v8_str("Cons"));
212 v8::Handle<v8::Signature> sig =
213 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
214 v8::Handle<v8::FunctionTemplate> fun =
215 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
216 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
217 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
218
219 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000220 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000221
222 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000223 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
225 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000226 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227
228 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
229 cons1->SetClassName(v8_str("Cons1"));
230 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
231 cons2->SetClassName(v8_str("Cons2"));
232 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
233 cons3->SetClassName(v8_str("Cons3"));
234
235 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
236 v8::Handle<v8::Signature> wsig =
237 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
238 v8::Handle<v8::FunctionTemplate> fun2 =
239 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
240
241 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
242 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
243 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
244 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
245 v8::Handle<Value> value4 = CompileRun(
246 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
247 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000248 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249
250 v8::Handle<Value> value5 = CompileRun(
251 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000252 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000253
254 v8::Handle<Value> value6 = CompileRun(
255 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000256 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000257
258 v8::Handle<Value> value7 = CompileRun(
259 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
260 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000261 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000262
263 v8::Handle<Value> value8 = CompileRun(
264 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000265 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000266}
267
268
269THREADED_TEST(HulIgennem) {
270 v8::HandleScope scope;
271 LocalContext env;
272 v8::Handle<v8::Primitive> undef = v8::Undefined();
273 Local<String> undef_str = undef->ToString();
274 char* value = i::NewArray<char>(undef_str->Length() + 1);
275 undef_str->WriteAscii(value);
276 CHECK_EQ(0, strcmp(value, "undefined"));
277 i::DeleteArray(value);
278}
279
280
281THREADED_TEST(Access) {
282 v8::HandleScope scope;
283 LocalContext env;
284 Local<v8::Object> obj = v8::Object::New();
285 Local<Value> foo_before = obj->Get(v8_str("foo"));
286 CHECK(foo_before->IsUndefined());
287 Local<String> bar_str = v8_str("bar");
288 obj->Set(v8_str("foo"), bar_str);
289 Local<Value> foo_after = obj->Get(v8_str("foo"));
290 CHECK(!foo_after->IsUndefined());
291 CHECK(foo_after->IsString());
292 CHECK_EQ(bar_str, foo_after);
293}
294
295
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000296THREADED_TEST(AccessElement) {
297 v8::HandleScope scope;
298 LocalContext env;
299 Local<v8::Object> obj = v8::Object::New();
300 Local<Value> before = obj->Get(1);
301 CHECK(before->IsUndefined());
302 Local<String> bar_str = v8_str("bar");
303 obj->Set(1, bar_str);
304 Local<Value> after = obj->Get(1);
305 CHECK(!after->IsUndefined());
306 CHECK(after->IsString());
307 CHECK_EQ(bar_str, after);
308
309 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
310 CHECK_EQ(v8_str("a"), value->Get(0));
311 CHECK_EQ(v8_str("b"), value->Get(1));
312}
313
314
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000315THREADED_TEST(Script) {
316 v8::HandleScope scope;
317 LocalContext env;
318 const char* c_source = "1 + 2 + 3";
319 Local<String> source = String::New(c_source);
320 Local<Script> script = Script::Compile(source);
321 CHECK_EQ(6, script->Run()->Int32Value());
322}
323
324
325static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000326 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000327 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000328 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329 return converted;
330}
331
332
333class TestResource: public String::ExternalStringResource {
334 public:
335 static int dispose_count;
336
337 explicit TestResource(uint16_t* data)
338 : data_(data), length_(0) {
339 while (data[length_]) ++length_;
340 }
341
342 ~TestResource() {
343 i::DeleteArray(data_);
344 ++dispose_count;
345 }
346
347 const uint16_t* data() const {
348 return data_;
349 }
350
351 size_t length() const {
352 return length_;
353 }
354 private:
355 uint16_t* data_;
356 size_t length_;
357};
358
359
360int TestResource::dispose_count = 0;
361
362
363class TestAsciiResource: public String::ExternalAsciiStringResource {
364 public:
365 static int dispose_count;
366
ager@chromium.org5ec48922009-05-05 07:25:34 +0000367 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368 : data_(data),
369 length_(strlen(data)) { }
370
371 ~TestAsciiResource() {
372 i::DeleteArray(data_);
373 ++dispose_count;
374 }
375
376 const char* data() const {
377 return data_;
378 }
379
380 size_t length() const {
381 return length_;
382 }
383 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000384 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000385 size_t length_;
386};
387
388
389int TestAsciiResource::dispose_count = 0;
390
391
392THREADED_TEST(ScriptUsingStringResource) {
393 TestResource::dispose_count = 0;
394 const char* c_source = "1 + 2 * 3";
395 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
396 {
397 v8::HandleScope scope;
398 LocalContext env;
399 TestResource* resource = new TestResource(two_byte_source);
400 Local<String> source = String::NewExternal(resource);
401 Local<Script> script = Script::Compile(source);
402 Local<Value> value = script->Run();
403 CHECK(value->IsNumber());
404 CHECK_EQ(7, value->Int32Value());
405 CHECK(source->IsExternal());
406 CHECK_EQ(resource,
407 static_cast<TestResource*>(source->GetExternalStringResource()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409 CHECK_EQ(0, TestResource::dispose_count);
410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 v8::internal::Isolate::Current()->compilation_cache()->Clear();
412 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000413 CHECK_EQ(1, TestResource::dispose_count);
414}
415
416
417THREADED_TEST(ScriptUsingAsciiStringResource) {
418 TestAsciiResource::dispose_count = 0;
419 const char* c_source = "1 + 2 * 3";
420 {
421 v8::HandleScope scope;
422 LocalContext env;
423 Local<String> source =
424 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
425 Local<Script> script = Script::Compile(source);
426 Local<Value> value = script->Run();
427 CHECK(value->IsNumber());
428 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430 CHECK_EQ(0, TestAsciiResource::dispose_count);
431 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 i::Isolate::Current()->compilation_cache()->Clear();
433 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434 CHECK_EQ(1, TestAsciiResource::dispose_count);
435}
436
437
ager@chromium.org6f10e412009-02-13 10:11:16 +0000438THREADED_TEST(ScriptMakingExternalString) {
439 TestResource::dispose_count = 0;
440 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
441 {
442 v8::HandleScope scope;
443 LocalContext env;
444 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000445 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
447 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000448 bool success = source->MakeExternal(new TestResource(two_byte_source));
449 CHECK(success);
450 Local<Script> script = Script::Compile(source);
451 Local<Value> value = script->Run();
452 CHECK(value->IsNumber());
453 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000455 CHECK_EQ(0, TestResource::dispose_count);
456 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 i::Isolate::Current()->compilation_cache()->Clear();
458 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000459 CHECK_EQ(1, TestResource::dispose_count);
460}
461
462
463THREADED_TEST(ScriptMakingExternalAsciiString) {
464 TestAsciiResource::dispose_count = 0;
465 const char* c_source = "1 + 2 * 3";
466 {
467 v8::HandleScope scope;
468 LocalContext env;
469 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000470 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000471 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
472 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000473 bool success = source->MakeExternal(
474 new TestAsciiResource(i::StrDup(c_source)));
475 CHECK(success);
476 Local<Script> script = Script::Compile(source);
477 Local<Value> value = script->Run();
478 CHECK(value->IsNumber());
479 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000481 CHECK_EQ(0, TestAsciiResource::dispose_count);
482 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483 i::Isolate::Current()->compilation_cache()->Clear();
484 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000485 CHECK_EQ(1, TestAsciiResource::dispose_count);
486}
487
488
ager@chromium.org5c838252010-02-19 08:53:10 +0000489TEST(MakingExternalStringConditions) {
490 v8::HandleScope scope;
491 LocalContext env;
492
493 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000494 HEAP->CollectGarbage(i::NEW_SPACE);
495 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000496
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000497 uint16_t* two_byte_string = AsciiToTwoByteString("small");
498 Local<String> small_string = String::New(two_byte_string);
499 i::DeleteArray(two_byte_string);
500
ager@chromium.org5c838252010-02-19 08:53:10 +0000501 // We should refuse to externalize newly created small string.
502 CHECK(!small_string->CanMakeExternal());
503 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
505 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000506 // Old space strings should be accepted.
507 CHECK(small_string->CanMakeExternal());
508
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000509 two_byte_string = AsciiToTwoByteString("small 2");
510 small_string = String::New(two_byte_string);
511 i::DeleteArray(two_byte_string);
512
ager@chromium.org5c838252010-02-19 08:53:10 +0000513 // We should refuse externalizing newly created small string.
514 CHECK(!small_string->CanMakeExternal());
515 for (int i = 0; i < 100; i++) {
516 String::Value value(small_string);
517 }
518 // Frequently used strings should be accepted.
519 CHECK(small_string->CanMakeExternal());
520
521 const int buf_size = 10 * 1024;
522 char* buf = i::NewArray<char>(buf_size);
523 memset(buf, 'a', buf_size);
524 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000525
526 two_byte_string = AsciiToTwoByteString(buf);
527 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000528 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000529 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000530 // Large strings should be immediately accepted.
531 CHECK(large_string->CanMakeExternal());
532}
533
534
535TEST(MakingExternalAsciiStringConditions) {
536 v8::HandleScope scope;
537 LocalContext env;
538
539 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 HEAP->CollectGarbage(i::NEW_SPACE);
541 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000542
543 Local<String> small_string = String::New("small");
544 // We should refuse to externalize newly created small string.
545 CHECK(!small_string->CanMakeExternal());
546 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
548 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000549 // Old space strings should be accepted.
550 CHECK(small_string->CanMakeExternal());
551
552 small_string = String::New("small 2");
553 // We should refuse externalizing newly created small string.
554 CHECK(!small_string->CanMakeExternal());
555 for (int i = 0; i < 100; i++) {
556 String::Value value(small_string);
557 }
558 // Frequently used strings should be accepted.
559 CHECK(small_string->CanMakeExternal());
560
561 const int buf_size = 10 * 1024;
562 char* buf = i::NewArray<char>(buf_size);
563 memset(buf, 'a', buf_size);
564 buf[buf_size - 1] = '\0';
565 Local<String> large_string = String::New(buf);
566 i::DeleteArray(buf);
567 // Large strings should be immediately accepted.
568 CHECK(large_string->CanMakeExternal());
569}
570
571
ager@chromium.org6f10e412009-02-13 10:11:16 +0000572THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000573 {
574 v8::HandleScope scope;
575 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
576 Local<String> string =
577 String::NewExternal(new TestResource(two_byte_string));
578 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
579 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
581 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
582 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000583 CHECK(isymbol->IsSymbol());
584 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 HEAP->CollectAllGarbage(false);
586 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000587}
588
589
590THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000591 {
592 v8::HandleScope scope;
593 const char* one_byte_string = "test string";
594 Local<String> string = String::NewExternal(
595 new TestAsciiResource(i::StrDup(one_byte_string)));
596 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
597 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
599 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
600 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000601 CHECK(isymbol->IsSymbol());
602 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 HEAP->CollectAllGarbage(false);
604 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000605}
606
607
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000608THREADED_TEST(ScavengeExternalString) {
609 TestResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000610 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 {
612 v8::HandleScope scope;
613 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
614 Local<String> string =
615 String::NewExternal(new TestResource(two_byte_string));
616 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 HEAP->CollectGarbage(i::NEW_SPACE);
618 in_new_space = HEAP->InNewSpace(*istring);
619 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 CHECK_EQ(0, TestResource::dispose_count);
621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 CHECK_EQ(1, TestResource::dispose_count);
624}
625
626
627THREADED_TEST(ScavengeExternalAsciiString) {
628 TestAsciiResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000629 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 {
631 v8::HandleScope scope;
632 const char* one_byte_string = "test string";
633 Local<String> string = String::NewExternal(
634 new TestAsciiResource(i::StrDup(one_byte_string)));
635 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000636 HEAP->CollectGarbage(i::NEW_SPACE);
637 in_new_space = HEAP->InNewSpace(*istring);
638 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639 CHECK_EQ(0, TestAsciiResource::dispose_count);
640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000641 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000642 CHECK_EQ(1, TestAsciiResource::dispose_count);
643}
644
645
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000646class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
647 public:
648 static int dispose_calls;
649
650 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651 : TestAsciiResource(data),
652 dispose_(dispose) { }
653
654 void Dispose() {
655 ++dispose_calls;
656 if (dispose_) delete this;
657 }
658 private:
659 bool dispose_;
660};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000661
662
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000663int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000664
665
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000666TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000667 const char* c_source = "1 + 2 * 3";
668
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000669 // Use a stack allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000670 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000671 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
672 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000673 {
674 v8::HandleScope scope;
675 LocalContext env;
676 Local<String> source = String::NewExternal(&res_stack);
677 Local<Script> script = Script::Compile(source);
678 Local<Value> value = script->Run();
679 CHECK(value->IsNumber());
680 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000681 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000682 CHECK_EQ(0, TestAsciiResource::dispose_count);
683 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000684 i::Isolate::Current()->compilation_cache()->Clear();
685 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000686 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000687 CHECK_EQ(0, TestAsciiResource::dispose_count);
688
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000689 // Use a heap allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000690 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000691 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
692 TestAsciiResource* res_heap =
693 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000694 {
695 v8::HandleScope scope;
696 LocalContext env;
697 Local<String> source = String::NewExternal(res_heap);
698 Local<Script> script = Script::Compile(source);
699 Local<Value> value = script->Run();
700 CHECK(value->IsNumber());
701 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000703 CHECK_EQ(0, TestAsciiResource::dispose_count);
704 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000705 i::Isolate::Current()->compilation_cache()->Clear();
706 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000707 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000708 CHECK_EQ(1, TestAsciiResource::dispose_count);
709}
710
711
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000712THREADED_TEST(StringConcat) {
713 {
714 v8::HandleScope scope;
715 LocalContext env;
716 const char* one_byte_string_1 = "function a_times_t";
717 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
718 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
719 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
720 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
723 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000724
725 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
726 Local<String> right = String::New(two_byte_source);
727 i::DeleteArray(two_byte_source);
728
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000729 Local<String> source = String::Concat(left, right);
730 right = String::NewExternal(
731 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
732 source = String::Concat(source, right);
733 right = String::NewExternal(
734 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
735 source = String::Concat(source, right);
736 right = v8_str(one_byte_string_2);
737 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000738
739 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
740 right = String::New(two_byte_source);
741 i::DeleteArray(two_byte_source);
742
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000743 source = String::Concat(source, right);
744 right = String::NewExternal(
745 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
746 source = String::Concat(source, right);
747 Local<Script> script = Script::Compile(source);
748 Local<Value> value = script->Run();
749 CHECK(value->IsNumber());
750 CHECK_EQ(68, value->Int32Value());
751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000752 i::Isolate::Current()->compilation_cache()->Clear();
753 HEAP->CollectAllGarbage(false);
754 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000755}
756
757
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000758THREADED_TEST(GlobalProperties) {
759 v8::HandleScope scope;
760 LocalContext env;
761 v8::Handle<v8::Object> global = env->Global();
762 global->Set(v8_str("pi"), v8_num(3.1415926));
763 Local<Value> pi = global->Get(v8_str("pi"));
764 CHECK_EQ(3.1415926, pi->NumberValue());
765}
766
767
768static v8::Handle<Value> handle_call(const v8::Arguments& args) {
769 ApiTestFuzzer::Fuzz();
770 return v8_num(102);
771}
772
773
774static v8::Handle<Value> construct_call(const v8::Arguments& args) {
775 ApiTestFuzzer::Fuzz();
776 args.This()->Set(v8_str("x"), v8_num(1));
777 args.This()->Set(v8_str("y"), v8_num(2));
778 return args.This();
779}
780
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000781static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
782 ApiTestFuzzer::Fuzz();
783 return v8_num(239);
784}
785
786
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000787THREADED_TEST(FunctionTemplate) {
788 v8::HandleScope scope;
789 LocalContext env;
790 {
791 Local<v8::FunctionTemplate> fun_templ =
792 v8::FunctionTemplate::New(handle_call);
793 Local<Function> fun = fun_templ->GetFunction();
794 env->Global()->Set(v8_str("obj"), fun);
795 Local<Script> script = v8_compile("obj()");
796 CHECK_EQ(102, script->Run()->Int32Value());
797 }
798 // Use SetCallHandler to initialize a function template, should work like the
799 // previous one.
800 {
801 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
802 fun_templ->SetCallHandler(handle_call);
803 Local<Function> fun = fun_templ->GetFunction();
804 env->Global()->Set(v8_str("obj"), fun);
805 Local<Script> script = v8_compile("obj()");
806 CHECK_EQ(102, script->Run()->Int32Value());
807 }
808 // Test constructor calls.
809 {
810 Local<v8::FunctionTemplate> fun_templ =
811 v8::FunctionTemplate::New(construct_call);
812 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000813 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000814 Local<Function> fun = fun_templ->GetFunction();
815 env->Global()->Set(v8_str("obj"), fun);
816 Local<Script> script = v8_compile("var s = new obj(); s.x");
817 CHECK_EQ(1, script->Run()->Int32Value());
818
819 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
820 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000821
822 result = v8_compile("(new obj()).m")->Run();
823 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824 }
825}
826
827
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000828static void* expected_ptr;
829static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
830 void* ptr = v8::External::Unwrap(args.Data());
831 CHECK_EQ(expected_ptr, ptr);
832 return v8::Boolean::New(true);
833}
834
835
836static void TestExternalPointerWrapping() {
837 v8::HandleScope scope;
838 LocalContext env;
839
840 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
841
842 v8::Handle<v8::Object> obj = v8::Object::New();
843 obj->Set(v8_str("func"),
844 v8::FunctionTemplate::New(callback, data)->GetFunction());
845 env->Global()->Set(v8_str("obj"), obj);
846
847 CHECK(CompileRun(
848 "function foo() {\n"
849 " for (var i = 0; i < 13; i++) obj.func();\n"
850 "}\n"
851 "foo(), true")->BooleanValue());
852}
853
854
855THREADED_TEST(ExternalWrap) {
856 // Check heap allocated object.
857 int* ptr = new int;
858 expected_ptr = ptr;
859 TestExternalPointerWrapping();
860 delete ptr;
861
862 // Check stack allocated object.
863 int foo;
864 expected_ptr = &foo;
865 TestExternalPointerWrapping();
866
867 // Check not aligned addresses.
868 const int n = 100;
869 char* s = new char[n];
870 for (int i = 0; i < n; i++) {
871 expected_ptr = s + i;
872 TestExternalPointerWrapping();
873 }
874
875 delete[] s;
876
877 // Check several invalid addresses.
878 expected_ptr = reinterpret_cast<void*>(1);
879 TestExternalPointerWrapping();
880
881 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
882 TestExternalPointerWrapping();
883
884 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
885 TestExternalPointerWrapping();
886
887#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000888 // Check a value with a leading 1 bit in x64 Smi encoding.
889 expected_ptr = reinterpret_cast<void*>(0x400000000);
890 TestExternalPointerWrapping();
891
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000892 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
893 TestExternalPointerWrapping();
894
895 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
896 TestExternalPointerWrapping();
897#endif
898}
899
900
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000901THREADED_TEST(FindInstanceInPrototypeChain) {
902 v8::HandleScope scope;
903 LocalContext env;
904
905 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
906 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
907 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
908 derived->Inherit(base);
909
910 Local<v8::Function> base_function = base->GetFunction();
911 Local<v8::Function> derived_function = derived->GetFunction();
912 Local<v8::Function> other_function = other->GetFunction();
913
914 Local<v8::Object> base_instance = base_function->NewInstance();
915 Local<v8::Object> derived_instance = derived_function->NewInstance();
916 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
917 Local<v8::Object> other_instance = other_function->NewInstance();
918 derived_instance2->Set(v8_str("__proto__"), derived_instance);
919 other_instance->Set(v8_str("__proto__"), derived_instance2);
920
921 // base_instance is only an instance of base.
922 CHECK_EQ(base_instance,
923 base_instance->FindInstanceInPrototypeChain(base));
924 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
925 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
926
927 // derived_instance is an instance of base and derived.
928 CHECK_EQ(derived_instance,
929 derived_instance->FindInstanceInPrototypeChain(base));
930 CHECK_EQ(derived_instance,
931 derived_instance->FindInstanceInPrototypeChain(derived));
932 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
933
934 // other_instance is an instance of other and its immediate
935 // prototype derived_instance2 is an instance of base and derived.
936 // Note, derived_instance is an instance of base and derived too,
937 // but it comes after derived_instance2 in the prototype chain of
938 // other_instance.
939 CHECK_EQ(derived_instance2,
940 other_instance->FindInstanceInPrototypeChain(base));
941 CHECK_EQ(derived_instance2,
942 other_instance->FindInstanceInPrototypeChain(derived));
943 CHECK_EQ(other_instance,
944 other_instance->FindInstanceInPrototypeChain(other));
945}
946
947
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000948THREADED_TEST(TinyInteger) {
949 v8::HandleScope scope;
950 LocalContext env;
951 int32_t value = 239;
952 Local<v8::Integer> value_obj = v8::Integer::New(value);
953 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
954}
955
956
957THREADED_TEST(BigSmiInteger) {
958 v8::HandleScope scope;
959 LocalContext env;
960 int32_t value = i::Smi::kMaxValue;
961 // We cannot add one to a Smi::kMaxValue without wrapping.
962 if (i::kSmiValueSize < 32) {
963 CHECK(i::Smi::IsValid(value));
964 CHECK(!i::Smi::IsValid(value + 1));
965 Local<v8::Integer> value_obj = v8::Integer::New(value);
966 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
967 }
968}
969
970
971THREADED_TEST(BigInteger) {
972 v8::HandleScope scope;
973 LocalContext env;
974 // We cannot add one to a Smi::kMaxValue without wrapping.
975 if (i::kSmiValueSize < 32) {
976 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
977 // The code will not be run in that case, due to the "if" guard.
978 int32_t value =
979 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
980 CHECK(value > i::Smi::kMaxValue);
981 CHECK(!i::Smi::IsValid(value));
982 Local<v8::Integer> value_obj = v8::Integer::New(value);
983 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
984 }
985}
986
987
988THREADED_TEST(TinyUnsignedInteger) {
989 v8::HandleScope scope;
990 LocalContext env;
991 uint32_t value = 239;
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(BigUnsignedSmiInteger) {
998 v8::HandleScope scope;
999 LocalContext env;
1000 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1001 CHECK(i::Smi::IsValid(value));
1002 CHECK(!i::Smi::IsValid(value + 1));
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(BigUnsignedInteger) {
1009 v8::HandleScope scope;
1010 LocalContext env;
1011 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1012 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1013 CHECK(!i::Smi::IsValid(value));
1014 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1015 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1016}
1017
1018
1019THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1020 v8::HandleScope scope;
1021 LocalContext env;
1022 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1023 uint32_t value = INT32_MAX_AS_UINT + 1;
1024 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1025 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1026 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1027}
1028
1029
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001030THREADED_TEST(Number) {
1031 v8::HandleScope scope;
1032 LocalContext env;
1033 double PI = 3.1415926;
1034 Local<v8::Number> pi_obj = v8::Number::New(PI);
1035 CHECK_EQ(PI, pi_obj->NumberValue());
1036}
1037
1038
1039THREADED_TEST(ToNumber) {
1040 v8::HandleScope scope;
1041 LocalContext env;
1042 Local<String> str = v8_str("3.1415926");
1043 CHECK_EQ(3.1415926, str->NumberValue());
1044 v8::Handle<v8::Boolean> t = v8::True();
1045 CHECK_EQ(1.0, t->NumberValue());
1046 v8::Handle<v8::Boolean> f = v8::False();
1047 CHECK_EQ(0.0, f->NumberValue());
1048}
1049
1050
1051THREADED_TEST(Date) {
1052 v8::HandleScope scope;
1053 LocalContext env;
1054 double PI = 3.1415926;
1055 Local<Value> date_obj = v8::Date::New(PI);
1056 CHECK_EQ(3.0, date_obj->NumberValue());
1057}
1058
1059
1060THREADED_TEST(Boolean) {
1061 v8::HandleScope scope;
1062 LocalContext env;
1063 v8::Handle<v8::Boolean> t = v8::True();
1064 CHECK(t->Value());
1065 v8::Handle<v8::Boolean> f = v8::False();
1066 CHECK(!f->Value());
1067 v8::Handle<v8::Primitive> u = v8::Undefined();
1068 CHECK(!u->BooleanValue());
1069 v8::Handle<v8::Primitive> n = v8::Null();
1070 CHECK(!n->BooleanValue());
1071 v8::Handle<String> str1 = v8_str("");
1072 CHECK(!str1->BooleanValue());
1073 v8::Handle<String> str2 = v8_str("x");
1074 CHECK(str2->BooleanValue());
1075 CHECK(!v8::Number::New(0)->BooleanValue());
1076 CHECK(v8::Number::New(-1)->BooleanValue());
1077 CHECK(v8::Number::New(1)->BooleanValue());
1078 CHECK(v8::Number::New(42)->BooleanValue());
1079 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1080}
1081
1082
1083static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1084 ApiTestFuzzer::Fuzz();
1085 return v8_num(13.4);
1086}
1087
1088
1089static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1090 ApiTestFuzzer::Fuzz();
1091 return v8_num(876);
1092}
1093
1094
1095THREADED_TEST(GlobalPrototype) {
1096 v8::HandleScope scope;
1097 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1098 func_templ->PrototypeTemplate()->Set(
1099 "dummy",
1100 v8::FunctionTemplate::New(DummyCallHandler));
1101 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1102 templ->Set("x", v8_num(200));
1103 templ->SetAccessor(v8_str("m"), GetM);
1104 LocalContext env(0, templ);
1105 v8::Handle<v8::Object> obj = env->Global();
1106 v8::Handle<Script> script = v8_compile("dummy()");
1107 v8::Handle<Value> result = script->Run();
1108 CHECK_EQ(13.4, result->NumberValue());
1109 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1110 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1111}
1112
1113
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001114THREADED_TEST(ObjectTemplate) {
1115 v8::HandleScope scope;
1116 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1117 templ1->Set("x", v8_num(10));
1118 templ1->Set("y", v8_num(13));
1119 LocalContext env;
1120 Local<v8::Object> instance1 = templ1->NewInstance();
1121 env->Global()->Set(v8_str("p"), instance1);
1122 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1123 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1124 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1125 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1126 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1127 templ2->Set("a", v8_num(12));
1128 templ2->Set("b", templ1);
1129 Local<v8::Object> instance2 = templ2->NewInstance();
1130 env->Global()->Set(v8_str("q"), instance2);
1131 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1132 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1133 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1134 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1135}
1136
1137
1138static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1139 ApiTestFuzzer::Fuzz();
1140 return v8_num(17.2);
1141}
1142
1143
1144static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1145 ApiTestFuzzer::Fuzz();
1146 return v8_num(15.2);
1147}
1148
1149
1150THREADED_TEST(DescriptorInheritance) {
1151 v8::HandleScope scope;
1152 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1153 super->PrototypeTemplate()->Set("flabby",
1154 v8::FunctionTemplate::New(GetFlabby));
1155 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1156
1157 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1158
1159 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1160 base1->Inherit(super);
1161 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1162
1163 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1164 base2->Inherit(super);
1165 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1166
1167 LocalContext env;
1168
1169 env->Global()->Set(v8_str("s"), super->GetFunction());
1170 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1171 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1172
1173 // Checks right __proto__ chain.
1174 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1175 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1176
1177 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1178
1179 // Instance accessor should not be visible on function object or its prototype
1180 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1181 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1182 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1183
1184 env->Global()->Set(v8_str("obj"),
1185 base1->GetFunction()->NewInstance());
1186 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1187 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1188 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1189 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1190 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1191
1192 env->Global()->Set(v8_str("obj2"),
1193 base2->GetFunction()->NewInstance());
1194 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1195 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1196 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1197 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1198 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1199
1200 // base1 and base2 cannot cross reference to each's prototype
1201 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1202 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1203}
1204
1205
1206int echo_named_call_count;
1207
1208
1209static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1210 const AccessorInfo& info) {
1211 ApiTestFuzzer::Fuzz();
1212 CHECK_EQ(v8_str("data"), info.Data());
1213 echo_named_call_count++;
1214 return name;
1215}
1216
1217
1218THREADED_TEST(NamedPropertyHandlerGetter) {
1219 echo_named_call_count = 0;
1220 v8::HandleScope scope;
1221 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1222 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1223 0, 0, 0, 0,
1224 v8_str("data"));
1225 LocalContext env;
1226 env->Global()->Set(v8_str("obj"),
1227 templ->GetFunction()->NewInstance());
1228 CHECK_EQ(echo_named_call_count, 0);
1229 v8_compile("obj.x")->Run();
1230 CHECK_EQ(echo_named_call_count, 1);
1231 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1232 v8::Handle<Value> str = CompileRun(code);
1233 String::AsciiValue value(str);
1234 CHECK_EQ(*value, "oddlepoddle");
1235 // Check default behavior
1236 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1237 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1238 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1239}
1240
1241
1242int echo_indexed_call_count = 0;
1243
1244
1245static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1246 const AccessorInfo& info) {
1247 ApiTestFuzzer::Fuzz();
1248 CHECK_EQ(v8_num(637), info.Data());
1249 echo_indexed_call_count++;
1250 return v8_num(index);
1251}
1252
1253
1254THREADED_TEST(IndexedPropertyHandlerGetter) {
1255 v8::HandleScope scope;
1256 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1257 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1258 0, 0, 0, 0,
1259 v8_num(637));
1260 LocalContext env;
1261 env->Global()->Set(v8_str("obj"),
1262 templ->GetFunction()->NewInstance());
1263 Local<Script> script = v8_compile("obj[900]");
1264 CHECK_EQ(script->Run()->Int32Value(), 900);
1265}
1266
1267
1268v8::Handle<v8::Object> bottom;
1269
1270static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1271 uint32_t index,
1272 const AccessorInfo& info) {
1273 ApiTestFuzzer::Fuzz();
1274 CHECK(info.This()->Equals(bottom));
1275 return v8::Handle<Value>();
1276}
1277
1278static v8::Handle<Value> CheckThisNamedPropertyHandler(
1279 Local<String> name,
1280 const AccessorInfo& info) {
1281 ApiTestFuzzer::Fuzz();
1282 CHECK(info.This()->Equals(bottom));
1283 return v8::Handle<Value>();
1284}
1285
1286
1287v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1288 Local<Value> value,
1289 const AccessorInfo& info) {
1290 ApiTestFuzzer::Fuzz();
1291 CHECK(info.This()->Equals(bottom));
1292 return v8::Handle<Value>();
1293}
1294
1295
1296v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1297 Local<Value> value,
1298 const AccessorInfo& info) {
1299 ApiTestFuzzer::Fuzz();
1300 CHECK(info.This()->Equals(bottom));
1301 return v8::Handle<Value>();
1302}
1303
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001304v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001305 uint32_t index,
1306 const AccessorInfo& info) {
1307 ApiTestFuzzer::Fuzz();
1308 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001309 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001310}
1311
1312
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001313v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001314 const AccessorInfo& info) {
1315 ApiTestFuzzer::Fuzz();
1316 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001317 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001318}
1319
1320
1321v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1322 uint32_t index,
1323 const AccessorInfo& info) {
1324 ApiTestFuzzer::Fuzz();
1325 CHECK(info.This()->Equals(bottom));
1326 return v8::Handle<v8::Boolean>();
1327}
1328
1329
1330v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1331 Local<String> property,
1332 const AccessorInfo& info) {
1333 ApiTestFuzzer::Fuzz();
1334 CHECK(info.This()->Equals(bottom));
1335 return v8::Handle<v8::Boolean>();
1336}
1337
1338
1339v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1340 const AccessorInfo& info) {
1341 ApiTestFuzzer::Fuzz();
1342 CHECK(info.This()->Equals(bottom));
1343 return v8::Handle<v8::Array>();
1344}
1345
1346
1347v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1348 const AccessorInfo& info) {
1349 ApiTestFuzzer::Fuzz();
1350 CHECK(info.This()->Equals(bottom));
1351 return v8::Handle<v8::Array>();
1352}
1353
1354
1355THREADED_TEST(PropertyHandlerInPrototype) {
1356 v8::HandleScope scope;
1357 LocalContext env;
1358
1359 // Set up a prototype chain with three interceptors.
1360 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1361 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1362 CheckThisIndexedPropertyHandler,
1363 CheckThisIndexedPropertySetter,
1364 CheckThisIndexedPropertyQuery,
1365 CheckThisIndexedPropertyDeleter,
1366 CheckThisIndexedPropertyEnumerator);
1367
1368 templ->InstanceTemplate()->SetNamedPropertyHandler(
1369 CheckThisNamedPropertyHandler,
1370 CheckThisNamedPropertySetter,
1371 CheckThisNamedPropertyQuery,
1372 CheckThisNamedPropertyDeleter,
1373 CheckThisNamedPropertyEnumerator);
1374
1375 bottom = templ->GetFunction()->NewInstance();
1376 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1377 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1378
1379 bottom->Set(v8_str("__proto__"), middle);
1380 middle->Set(v8_str("__proto__"), top);
1381 env->Global()->Set(v8_str("obj"), bottom);
1382
1383 // Indexed and named get.
1384 Script::Compile(v8_str("obj[0]"))->Run();
1385 Script::Compile(v8_str("obj.x"))->Run();
1386
1387 // Indexed and named set.
1388 Script::Compile(v8_str("obj[1] = 42"))->Run();
1389 Script::Compile(v8_str("obj.y = 42"))->Run();
1390
1391 // Indexed and named query.
1392 Script::Compile(v8_str("0 in obj"))->Run();
1393 Script::Compile(v8_str("'x' in obj"))->Run();
1394
1395 // Indexed and named deleter.
1396 Script::Compile(v8_str("delete obj[0]"))->Run();
1397 Script::Compile(v8_str("delete obj.x"))->Run();
1398
1399 // Enumerators.
1400 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1401}
1402
1403
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001404static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1405 const AccessorInfo& info) {
1406 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001407 if (v8_str("pre")->Equals(key)) {
1408 return v8_str("PrePropertyHandler: pre");
1409 }
1410 return v8::Handle<String>();
1411}
1412
1413
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001414static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1415 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001416 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001417 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001418 }
1419
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001420 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001421}
1422
1423
1424THREADED_TEST(PrePropertyHandler) {
1425 v8::HandleScope scope;
1426 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1427 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1428 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001429 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001430 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001431 Script::Compile(v8_str(
1432 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1433 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1434 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1435 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1436 CHECK_EQ(v8_str("Object: on"), result_on);
1437 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1438 CHECK(result_post.IsEmpty());
1439}
1440
1441
ager@chromium.org870a0b62008-11-04 11:43:05 +00001442THREADED_TEST(UndefinedIsNotEnumerable) {
1443 v8::HandleScope scope;
1444 LocalContext env;
1445 v8::Handle<Value> result = Script::Compile(v8_str(
1446 "this.propertyIsEnumerable(undefined)"))->Run();
1447 CHECK(result->IsFalse());
1448}
1449
1450
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001451v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001452static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001453
1454
1455static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1456 ApiTestFuzzer::Fuzz();
1457 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1458 if (depth == kTargetRecursionDepth) return v8::Undefined();
1459 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1460 return call_recursively_script->Run();
1461}
1462
1463
1464static v8::Handle<Value> CallFunctionRecursivelyCall(
1465 const v8::Arguments& args) {
1466 ApiTestFuzzer::Fuzz();
1467 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1468 if (depth == kTargetRecursionDepth) {
1469 printf("[depth = %d]\n", depth);
1470 return v8::Undefined();
1471 }
1472 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1473 v8::Handle<Value> function =
1474 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001475 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001476}
1477
1478
1479THREADED_TEST(DeepCrossLanguageRecursion) {
1480 v8::HandleScope scope;
1481 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1482 global->Set(v8_str("callScriptRecursively"),
1483 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1484 global->Set(v8_str("callFunctionRecursively"),
1485 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1486 LocalContext env(NULL, global);
1487
1488 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1489 call_recursively_script = v8_compile("callScriptRecursively()");
1490 v8::Handle<Value> result = call_recursively_script->Run();
1491 call_recursively_script = v8::Handle<Script>();
1492
1493 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1494 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1495}
1496
1497
1498static v8::Handle<Value>
1499 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1500 ApiTestFuzzer::Fuzz();
1501 return v8::ThrowException(key);
1502}
1503
1504
1505static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1506 Local<Value>,
1507 const AccessorInfo&) {
1508 v8::ThrowException(key);
1509 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1510}
1511
1512
1513THREADED_TEST(CallbackExceptionRegression) {
1514 v8::HandleScope scope;
1515 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1516 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1517 ThrowingPropertyHandlerSet);
1518 LocalContext env;
1519 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1520 v8::Handle<Value> otto = Script::Compile(v8_str(
1521 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1522 CHECK_EQ(v8_str("otto"), otto);
1523 v8::Handle<Value> netto = Script::Compile(v8_str(
1524 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1525 CHECK_EQ(v8_str("netto"), netto);
1526}
1527
1528
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001529THREADED_TEST(FunctionPrototype) {
1530 v8::HandleScope scope;
1531 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1532 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1533 LocalContext env;
1534 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1535 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1536 CHECK_EQ(script->Run()->Int32Value(), 321);
1537}
1538
1539
1540THREADED_TEST(InternalFields) {
1541 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001542 LocalContext env;
1543
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001544 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1545 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1546 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001547 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1548 CHECK_EQ(1, obj->InternalFieldCount());
1549 CHECK(obj->GetInternalField(0)->IsUndefined());
1550 obj->SetInternalField(0, v8_num(17));
1551 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1552}
1553
1554
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001555THREADED_TEST(GlobalObjectInternalFields) {
1556 v8::HandleScope scope;
1557 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1558 global_template->SetInternalFieldCount(1);
1559 LocalContext env(NULL, global_template);
1560 v8::Handle<v8::Object> global_proxy = env->Global();
1561 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1562 CHECK_EQ(1, global->InternalFieldCount());
1563 CHECK(global->GetInternalField(0)->IsUndefined());
1564 global->SetInternalField(0, v8_num(17));
1565 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1566}
1567
1568
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001569THREADED_TEST(InternalFieldsNativePointers) {
1570 v8::HandleScope scope;
1571 LocalContext env;
1572
1573 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1574 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1575 instance_templ->SetInternalFieldCount(1);
1576 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1577 CHECK_EQ(1, obj->InternalFieldCount());
1578 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1579
1580 char* data = new char[100];
1581
1582 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001583 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001584 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001585 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001586
1587 // Check reading and writing aligned pointers.
1588 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001590 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1591
1592 // Check reading and writing unaligned pointers.
1593 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001595 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1596
1597 delete[] data;
1598}
1599
1600
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001601THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1602 v8::HandleScope scope;
1603 LocalContext env;
1604
1605 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1606 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1607 instance_templ->SetInternalFieldCount(1);
1608 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1609 CHECK_EQ(1, obj->InternalFieldCount());
1610 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1611
1612 char* data = new char[100];
1613
1614 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001615 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001616 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001617 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001618
1619 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001621 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1622
1623 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001625 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1626
1627 obj->SetInternalField(0, v8::External::Wrap(aligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001629 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1630
1631 obj->SetInternalField(0, v8::External::Wrap(unaligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001633 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1634
1635 delete[] data;
1636}
1637
1638
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001639THREADED_TEST(IdentityHash) {
1640 v8::HandleScope scope;
1641 LocalContext env;
1642
1643 // Ensure that the test starts with an fresh heap to test whether the hash
1644 // code is based on the address.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001646 Local<v8::Object> obj = v8::Object::New();
1647 int hash = obj->GetIdentityHash();
1648 int hash1 = obj->GetIdentityHash();
1649 CHECK_EQ(hash, hash1);
1650 int hash2 = v8::Object::New()->GetIdentityHash();
1651 // Since the identity hash is essentially a random number two consecutive
1652 // objects should not be assigned the same hash code. If the test below fails
1653 // the random number generator should be evaluated.
1654 CHECK_NE(hash, hash2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001655 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001656 int hash3 = v8::Object::New()->GetIdentityHash();
1657 // Make sure that the identity hash is not based on the initial address of
1658 // the object alone. If the test below fails the random number generator
1659 // should be evaluated.
1660 CHECK_NE(hash, hash3);
1661 int hash4 = obj->GetIdentityHash();
1662 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001663
1664 // Check identity hashes behaviour in the presence of JS accessors.
1665 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1666 {
1667 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1668 Local<v8::Object> o1 = v8::Object::New();
1669 Local<v8::Object> o2 = v8::Object::New();
1670 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1671 }
1672 {
1673 CompileRun(
1674 "function cnst() { return 42; };\n"
1675 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1676 Local<v8::Object> o1 = v8::Object::New();
1677 Local<v8::Object> o2 = v8::Object::New();
1678 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1679 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001680}
1681
1682
1683THREADED_TEST(HiddenProperties) {
1684 v8::HandleScope scope;
1685 LocalContext env;
1686
1687 v8::Local<v8::Object> obj = v8::Object::New();
1688 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1689 v8::Local<v8::String> empty = v8_str("");
1690 v8::Local<v8::String> prop_name = v8_str("prop_name");
1691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001692 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001693
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001694 // Make sure delete of a non-existent hidden value works
1695 CHECK(obj->DeleteHiddenValue(key));
1696
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001697 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1698 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1699 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1700 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001703
1704 // Make sure we do not find the hidden property.
1705 CHECK(!obj->Has(empty));
1706 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1707 CHECK(obj->Get(empty)->IsUndefined());
1708 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1709 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1710 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1711 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001714
1715 // Add another property and delete it afterwards to force the object in
1716 // slow case.
1717 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1718 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1719 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1720 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1721 CHECK(obj->Delete(prop_name));
1722 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001725
1726 CHECK(obj->DeleteHiddenValue(key));
1727 CHECK(obj->GetHiddenValue(key).IsEmpty());
1728}
1729
1730
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001731static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001732static v8::Handle<Value> InterceptorForHiddenProperties(
1733 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001734 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001735 return v8::Handle<Value>();
1736}
1737
1738
1739THREADED_TEST(HiddenPropertiesWithInterceptors) {
1740 v8::HandleScope scope;
1741 LocalContext context;
1742
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001743 interceptor_for_hidden_properties_called = false;
1744
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001745 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1746
1747 // Associate an interceptor with an object and start setting hidden values.
1748 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1749 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1750 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1751 Local<v8::Function> function = fun_templ->GetFunction();
1752 Local<v8::Object> obj = function->NewInstance();
1753 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1754 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001755 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001756}
1757
1758
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001759THREADED_TEST(External) {
1760 v8::HandleScope scope;
1761 int x = 3;
1762 Local<v8::External> ext = v8::External::New(&x);
1763 LocalContext env;
1764 env->Global()->Set(v8_str("ext"), ext);
1765 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001766 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001767 int* ptr = static_cast<int*>(reext->Value());
1768 CHECK_EQ(x, 3);
1769 *ptr = 10;
1770 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001771
1772 // Make sure unaligned pointers are wrapped properly.
1773 char* data = i::StrDup("0123456789");
1774 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1775 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1776 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1777 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1778
1779 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1780 CHECK_EQ('0', *char_ptr);
1781 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1782 CHECK_EQ('1', *char_ptr);
1783 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1784 CHECK_EQ('2', *char_ptr);
1785 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1786 CHECK_EQ('3', *char_ptr);
1787 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001788}
1789
1790
1791THREADED_TEST(GlobalHandle) {
1792 v8::Persistent<String> global;
1793 {
1794 v8::HandleScope scope;
1795 Local<String> str = v8_str("str");
1796 global = v8::Persistent<String>::New(str);
1797 }
1798 CHECK_EQ(global->Length(), 3);
1799 global.Dispose();
1800}
1801
1802
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001803static int NumberOfWeakCalls = 0;
1804static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1805 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1806 NumberOfWeakCalls++;
1807 handle.Dispose();
1808}
1809
1810THREADED_TEST(ApiObjectGroups) {
1811 HandleScope scope;
1812 LocalContext env;
1813
1814 NumberOfWeakCalls = 0;
1815
1816 Persistent<Object> g1s1;
1817 Persistent<Object> g1s2;
1818 Persistent<Object> g1c1;
1819 Persistent<Object> g2s1;
1820 Persistent<Object> g2s2;
1821 Persistent<Object> g2c1;
1822
1823 {
1824 HandleScope scope;
1825 g1s1 = Persistent<Object>::New(Object::New());
1826 g1s2 = Persistent<Object>::New(Object::New());
1827 g1c1 = Persistent<Object>::New(Object::New());
1828 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1829 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1830 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1831
1832 g2s1 = Persistent<Object>::New(Object::New());
1833 g2s2 = Persistent<Object>::New(Object::New());
1834 g2c1 = Persistent<Object>::New(Object::New());
1835 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1836 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1837 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1838 }
1839
1840 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1841
1842 // Connect group 1 and 2, make a cycle.
1843 CHECK(g1s2->Set(0, g2s2));
1844 CHECK(g2s1->Set(0, g1s1));
1845
1846 {
1847 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1848 Persistent<Value> g1_children[] = { g1c1 };
1849 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1850 Persistent<Value> g2_children[] = { g2c1 };
1851 V8::AddObjectGroup(g1_objects, 2);
1852 V8::AddImplicitReferences(g1s1, g1_children, 1);
1853 V8::AddObjectGroup(g2_objects, 2);
1854 V8::AddImplicitReferences(g2s2, g2_children, 1);
1855 }
1856 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001858
1859 // All object should be alive.
1860 CHECK_EQ(0, NumberOfWeakCalls);
1861
1862 // Weaken the root.
1863 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1864 // But make children strong roots---all the objects (except for children)
1865 // should be collectable now.
1866 g1c1.ClearWeak();
1867 g2c1.ClearWeak();
1868
1869 // Groups are deleted, rebuild groups.
1870 {
1871 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1872 Persistent<Value> g1_children[] = { g1c1 };
1873 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1874 Persistent<Value> g2_children[] = { g2c1 };
1875 V8::AddObjectGroup(g1_objects, 2);
1876 V8::AddImplicitReferences(g1s1, g1_children, 1);
1877 V8::AddObjectGroup(g2_objects, 2);
1878 V8::AddImplicitReferences(g2s2, g2_children, 1);
1879 }
1880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001882
1883 // All objects should be gone. 5 global handles in total.
1884 CHECK_EQ(5, NumberOfWeakCalls);
1885
1886 // And now make children weak again and collect them.
1887 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1888 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001891 CHECK_EQ(7, NumberOfWeakCalls);
1892}
1893
1894
1895THREADED_TEST(ApiObjectGroupsCycle) {
1896 HandleScope scope;
1897 LocalContext env;
1898
1899 NumberOfWeakCalls = 0;
1900
1901 Persistent<Object> g1s1;
1902 Persistent<Object> g1s2;
1903 Persistent<Object> g2s1;
1904 Persistent<Object> g2s2;
1905 Persistent<Object> g3s1;
1906 Persistent<Object> g3s2;
1907
1908 {
1909 HandleScope scope;
1910 g1s1 = Persistent<Object>::New(Object::New());
1911 g1s2 = Persistent<Object>::New(Object::New());
1912 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1913 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914
1915 g2s1 = Persistent<Object>::New(Object::New());
1916 g2s2 = Persistent<Object>::New(Object::New());
1917 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1918 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1919
1920 g3s1 = Persistent<Object>::New(Object::New());
1921 g3s2 = Persistent<Object>::New(Object::New());
1922 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1923 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1924 }
1925
1926 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1927
1928 // Connect groups. We're building the following cycle:
1929 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
1930 // groups.
1931 {
1932 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1933 Persistent<Value> g1_children[] = { g2s1 };
1934 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1935 Persistent<Value> g2_children[] = { g3s1 };
1936 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1937 Persistent<Value> g3_children[] = { g1s1 };
1938 V8::AddObjectGroup(g1_objects, 2);
1939 V8::AddImplicitReferences(g1s1, g1_children, 1);
1940 V8::AddObjectGroup(g2_objects, 2);
1941 V8::AddImplicitReferences(g2s1, g2_children, 1);
1942 V8::AddObjectGroup(g3_objects, 2);
1943 V8::AddImplicitReferences(g3s1, g3_children, 1);
1944 }
1945 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001947
1948 // All object should be alive.
1949 CHECK_EQ(0, NumberOfWeakCalls);
1950
1951 // Weaken the root.
1952 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1953
1954 // Groups are deleted, rebuild groups.
1955 {
1956 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1957 Persistent<Value> g1_children[] = { g2s1 };
1958 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1959 Persistent<Value> g2_children[] = { g3s1 };
1960 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1961 Persistent<Value> g3_children[] = { g1s1 };
1962 V8::AddObjectGroup(g1_objects, 2);
1963 V8::AddImplicitReferences(g1s1, g1_children, 1);
1964 V8::AddObjectGroup(g2_objects, 2);
1965 V8::AddImplicitReferences(g2s1, g2_children, 1);
1966 V8::AddObjectGroup(g3_objects, 2);
1967 V8::AddImplicitReferences(g3s1, g3_children, 1);
1968 }
1969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001971
1972 // All objects should be gone. 7 global handles in total.
1973 CHECK_EQ(7, NumberOfWeakCalls);
1974}
1975
1976
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001977THREADED_TEST(ScriptException) {
1978 v8::HandleScope scope;
1979 LocalContext env;
1980 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1981 v8::TryCatch try_catch;
1982 Local<Value> result = script->Run();
1983 CHECK(result.IsEmpty());
1984 CHECK(try_catch.HasCaught());
1985 String::AsciiValue exception_value(try_catch.Exception());
1986 CHECK_EQ(*exception_value, "panama!");
1987}
1988
1989
1990bool message_received;
1991
1992
1993static void check_message(v8::Handle<v8::Message> message,
1994 v8::Handle<Value> data) {
1995 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001996 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001997 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001998 message_received = true;
1999}
2000
2001
2002THREADED_TEST(MessageHandlerData) {
2003 message_received = false;
2004 v8::HandleScope scope;
2005 CHECK(!message_received);
2006 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2007 LocalContext context;
2008 v8::ScriptOrigin origin =
2009 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002010 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2011 &origin);
2012 script->SetData(v8_str("7.56"));
2013 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002014 CHECK(message_received);
2015 // clear out the message listener
2016 v8::V8::RemoveMessageListeners(check_message);
2017}
2018
2019
2020THREADED_TEST(GetSetProperty) {
2021 v8::HandleScope scope;
2022 LocalContext context;
2023 context->Global()->Set(v8_str("foo"), v8_num(14));
2024 context->Global()->Set(v8_str("12"), v8_num(92));
2025 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2026 context->Global()->Set(v8_num(13), v8_num(56));
2027 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2028 CHECK_EQ(14, foo->Int32Value());
2029 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2030 CHECK_EQ(92, twelve->Int32Value());
2031 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2032 CHECK_EQ(32, sixteen->Int32Value());
2033 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2034 CHECK_EQ(56, thirteen->Int32Value());
2035 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2036 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2037 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2038 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2039 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2040 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2041 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2042 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2043 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2044}
2045
2046
2047THREADED_TEST(PropertyAttributes) {
2048 v8::HandleScope scope;
2049 LocalContext context;
2050 // read-only
2051 Local<String> prop = v8_str("read_only");
2052 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2053 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2054 Script::Compile(v8_str("read_only = 9"))->Run();
2055 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2056 context->Global()->Set(prop, v8_num(10));
2057 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2058 // dont-delete
2059 prop = v8_str("dont_delete");
2060 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2061 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2062 Script::Compile(v8_str("delete dont_delete"))->Run();
2063 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2064}
2065
2066
2067THREADED_TEST(Array) {
2068 v8::HandleScope scope;
2069 LocalContext context;
2070 Local<v8::Array> array = v8::Array::New();
2071 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002072 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002073 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002074 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002076 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002077 CHECK_EQ(3, array->Length());
2078 CHECK(!array->Has(0));
2079 CHECK(!array->Has(1));
2080 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002081 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002082 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002083 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002084 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002085 CHECK_EQ(1, arr->Get(0)->Int32Value());
2086 CHECK_EQ(2, arr->Get(1)->Int32Value());
2087 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002088 array = v8::Array::New(27);
2089 CHECK_EQ(27, array->Length());
2090 array = v8::Array::New(-27);
2091 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002092}
2093
2094
2095v8::Handle<Value> HandleF(const v8::Arguments& args) {
2096 v8::HandleScope scope;
2097 ApiTestFuzzer::Fuzz();
2098 Local<v8::Array> result = v8::Array::New(args.Length());
2099 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002100 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002101 return scope.Close(result);
2102}
2103
2104
2105THREADED_TEST(Vector) {
2106 v8::HandleScope scope;
2107 Local<ObjectTemplate> global = ObjectTemplate::New();
2108 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2109 LocalContext context(0, global);
2110
2111 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002112 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002113 CHECK_EQ(0, a0->Length());
2114
2115 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002116 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002117 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002118 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002119
2120 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002121 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002122 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002123 CHECK_EQ(12, a2->Get(0)->Int32Value());
2124 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002125
2126 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002127 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002128 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002129 CHECK_EQ(14, a3->Get(0)->Int32Value());
2130 CHECK_EQ(15, a3->Get(1)->Int32Value());
2131 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002132
2133 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002134 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002135 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002136 CHECK_EQ(17, a4->Get(0)->Int32Value());
2137 CHECK_EQ(18, a4->Get(1)->Int32Value());
2138 CHECK_EQ(19, a4->Get(2)->Int32Value());
2139 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002140}
2141
2142
2143THREADED_TEST(FunctionCall) {
2144 v8::HandleScope scope;
2145 LocalContext context;
2146 CompileRun(
2147 "function Foo() {"
2148 " var result = [];"
2149 " for (var i = 0; i < arguments.length; i++) {"
2150 " result.push(arguments[i]);"
2151 " }"
2152 " return result;"
2153 "}");
2154 Local<Function> Foo =
2155 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2156
2157 v8::Handle<Value>* args0 = NULL;
2158 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2159 CHECK_EQ(0, a0->Length());
2160
2161 v8::Handle<Value> args1[] = { v8_num(1.1) };
2162 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2163 CHECK_EQ(1, a1->Length());
2164 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2165
2166 v8::Handle<Value> args2[] = { v8_num(2.2),
2167 v8_num(3.3) };
2168 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2169 CHECK_EQ(2, a2->Length());
2170 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2171 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2172
2173 v8::Handle<Value> args3[] = { v8_num(4.4),
2174 v8_num(5.5),
2175 v8_num(6.6) };
2176 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2177 CHECK_EQ(3, a3->Length());
2178 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2179 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2180 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2181
2182 v8::Handle<Value> args4[] = { v8_num(7.7),
2183 v8_num(8.8),
2184 v8_num(9.9),
2185 v8_num(10.11) };
2186 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2187 CHECK_EQ(4, a4->Length());
2188 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2189 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2190 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2191 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2192}
2193
2194
2195static const char* js_code_causing_out_of_memory =
2196 "var a = new Array(); while(true) a.push(a);";
2197
2198
2199// These tests run for a long time and prevent us from running tests
2200// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002201TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002202 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002203 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002204 // Set heap limits.
2205 static const int K = 1024;
2206 v8::ResourceConstraints constraints;
2207 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002208 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002209 v8::SetResourceConstraints(&constraints);
2210
2211 // Execute a script that causes out of memory.
2212 v8::HandleScope scope;
2213 LocalContext context;
2214 v8::V8::IgnoreOutOfMemoryException();
2215 Local<Script> script =
2216 Script::Compile(String::New(js_code_causing_out_of_memory));
2217 Local<Value> result = script->Run();
2218
2219 // Check for out of memory state.
2220 CHECK(result.IsEmpty());
2221 CHECK(context->HasOutOfMemoryException());
2222}
2223
2224
2225v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2226 ApiTestFuzzer::Fuzz();
2227
2228 v8::HandleScope scope;
2229 LocalContext context;
2230 Local<Script> script =
2231 Script::Compile(String::New(js_code_causing_out_of_memory));
2232 Local<Value> result = script->Run();
2233
2234 // Check for out of memory state.
2235 CHECK(result.IsEmpty());
2236 CHECK(context->HasOutOfMemoryException());
2237
2238 return result;
2239}
2240
2241
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002242TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002243 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002244 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002245 // Set heap limits.
2246 static const int K = 1024;
2247 v8::ResourceConstraints constraints;
2248 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002249 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002250 v8::SetResourceConstraints(&constraints);
2251
2252 v8::HandleScope scope;
2253 Local<ObjectTemplate> templ = ObjectTemplate::New();
2254 templ->Set(v8_str("ProvokeOutOfMemory"),
2255 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2256 LocalContext context(0, templ);
2257 v8::V8::IgnoreOutOfMemoryException();
2258 Local<Value> result = CompileRun(
2259 "var thrown = false;"
2260 "try {"
2261 " ProvokeOutOfMemory();"
2262 "} catch (e) {"
2263 " thrown = true;"
2264 "}");
2265 // Check for out of memory state.
2266 CHECK(result.IsEmpty());
2267 CHECK(context->HasOutOfMemoryException());
2268}
2269
2270
2271TEST(HugeConsStringOutOfMemory) {
2272 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002273 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002274 // Set heap limits.
2275 static const int K = 1024;
2276 v8::ResourceConstraints constraints;
2277 constraints.set_max_young_space_size(256 * K);
2278 constraints.set_max_old_space_size(2 * K * K);
2279 v8::SetResourceConstraints(&constraints);
2280
2281 // Execute a script that causes out of memory.
2282 v8::V8::IgnoreOutOfMemoryException();
2283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 v8::HandleScope scope;
2285 LocalContext context;
2286
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002287 // Build huge string. This should fail with out of memory exception.
2288 Local<Value> result = CompileRun(
2289 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002290 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002291
2292 // Check for out of memory state.
2293 CHECK(result.IsEmpty());
2294 CHECK(context->HasOutOfMemoryException());
2295}
2296
2297
2298THREADED_TEST(ConstructCall) {
2299 v8::HandleScope scope;
2300 LocalContext context;
2301 CompileRun(
2302 "function Foo() {"
2303 " var result = [];"
2304 " for (var i = 0; i < arguments.length; i++) {"
2305 " result.push(arguments[i]);"
2306 " }"
2307 " return result;"
2308 "}");
2309 Local<Function> Foo =
2310 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2311
2312 v8::Handle<Value>* args0 = NULL;
2313 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2314 CHECK_EQ(0, a0->Length());
2315
2316 v8::Handle<Value> args1[] = { v8_num(1.1) };
2317 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2318 CHECK_EQ(1, a1->Length());
2319 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2320
2321 v8::Handle<Value> args2[] = { v8_num(2.2),
2322 v8_num(3.3) };
2323 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2324 CHECK_EQ(2, a2->Length());
2325 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2326 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2327
2328 v8::Handle<Value> args3[] = { v8_num(4.4),
2329 v8_num(5.5),
2330 v8_num(6.6) };
2331 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2332 CHECK_EQ(3, a3->Length());
2333 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2334 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2335 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2336
2337 v8::Handle<Value> args4[] = { v8_num(7.7),
2338 v8_num(8.8),
2339 v8_num(9.9),
2340 v8_num(10.11) };
2341 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2342 CHECK_EQ(4, a4->Length());
2343 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2344 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2345 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2346 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2347}
2348
2349
2350static void CheckUncle(v8::TryCatch* try_catch) {
2351 CHECK(try_catch->HasCaught());
2352 String::AsciiValue str_value(try_catch->Exception());
2353 CHECK_EQ(*str_value, "uncle?");
2354 try_catch->Reset();
2355}
2356
2357
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002358THREADED_TEST(ConversionNumber) {
2359 v8::HandleScope scope;
2360 LocalContext env;
2361 // Very large number.
2362 CompileRun("var obj = Math.pow(2,32) * 1237;");
2363 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2364 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2365 CHECK_EQ(0, obj->ToInt32()->Value());
2366 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2367 // Large number.
2368 CompileRun("var obj = -1234567890123;");
2369 obj = env->Global()->Get(v8_str("obj"));
2370 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2371 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2372 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2373 // Small positive integer.
2374 CompileRun("var obj = 42;");
2375 obj = env->Global()->Get(v8_str("obj"));
2376 CHECK_EQ(42.0, obj->ToNumber()->Value());
2377 CHECK_EQ(42, obj->ToInt32()->Value());
2378 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2379 // Negative integer.
2380 CompileRun("var obj = -37;");
2381 obj = env->Global()->Get(v8_str("obj"));
2382 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2383 CHECK_EQ(-37, obj->ToInt32()->Value());
2384 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2385 // Positive non-int32 integer.
2386 CompileRun("var obj = 0x81234567;");
2387 obj = env->Global()->Get(v8_str("obj"));
2388 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2389 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2390 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2391 // Fraction.
2392 CompileRun("var obj = 42.3;");
2393 obj = env->Global()->Get(v8_str("obj"));
2394 CHECK_EQ(42.3, obj->ToNumber()->Value());
2395 CHECK_EQ(42, obj->ToInt32()->Value());
2396 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2397 // Large negative fraction.
2398 CompileRun("var obj = -5726623061.75;");
2399 obj = env->Global()->Get(v8_str("obj"));
2400 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2401 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2402 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2403}
2404
2405
2406THREADED_TEST(isNumberType) {
2407 v8::HandleScope scope;
2408 LocalContext env;
2409 // Very large number.
2410 CompileRun("var obj = Math.pow(2,32) * 1237;");
2411 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2412 CHECK(!obj->IsInt32());
2413 CHECK(!obj->IsUint32());
2414 // Large negative number.
2415 CompileRun("var obj = -1234567890123;");
2416 obj = env->Global()->Get(v8_str("obj"));
2417 CHECK(!obj->IsInt32());
2418 CHECK(!obj->IsUint32());
2419 // Small positive integer.
2420 CompileRun("var obj = 42;");
2421 obj = env->Global()->Get(v8_str("obj"));
2422 CHECK(obj->IsInt32());
2423 CHECK(obj->IsUint32());
2424 // Negative integer.
2425 CompileRun("var obj = -37;");
2426 obj = env->Global()->Get(v8_str("obj"));
2427 CHECK(obj->IsInt32());
2428 CHECK(!obj->IsUint32());
2429 // Positive non-int32 integer.
2430 CompileRun("var obj = 0x81234567;");
2431 obj = env->Global()->Get(v8_str("obj"));
2432 CHECK(!obj->IsInt32());
2433 CHECK(obj->IsUint32());
2434 // Fraction.
2435 CompileRun("var obj = 42.3;");
2436 obj = env->Global()->Get(v8_str("obj"));
2437 CHECK(!obj->IsInt32());
2438 CHECK(!obj->IsUint32());
2439 // Large negative fraction.
2440 CompileRun("var obj = -5726623061.75;");
2441 obj = env->Global()->Get(v8_str("obj"));
2442 CHECK(!obj->IsInt32());
2443 CHECK(!obj->IsUint32());
2444}
2445
2446
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002447THREADED_TEST(ConversionException) {
2448 v8::HandleScope scope;
2449 LocalContext env;
2450 CompileRun(
2451 "function TestClass() { };"
2452 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2453 "var obj = new TestClass();");
2454 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2455
2456 v8::TryCatch try_catch;
2457
2458 Local<Value> to_string_result = obj->ToString();
2459 CHECK(to_string_result.IsEmpty());
2460 CheckUncle(&try_catch);
2461
2462 Local<Value> to_number_result = obj->ToNumber();
2463 CHECK(to_number_result.IsEmpty());
2464 CheckUncle(&try_catch);
2465
2466 Local<Value> to_integer_result = obj->ToInteger();
2467 CHECK(to_integer_result.IsEmpty());
2468 CheckUncle(&try_catch);
2469
2470 Local<Value> to_uint32_result = obj->ToUint32();
2471 CHECK(to_uint32_result.IsEmpty());
2472 CheckUncle(&try_catch);
2473
2474 Local<Value> to_int32_result = obj->ToInt32();
2475 CHECK(to_int32_result.IsEmpty());
2476 CheckUncle(&try_catch);
2477
2478 Local<Value> to_object_result = v8::Undefined()->ToObject();
2479 CHECK(to_object_result.IsEmpty());
2480 CHECK(try_catch.HasCaught());
2481 try_catch.Reset();
2482
2483 int32_t int32_value = obj->Int32Value();
2484 CHECK_EQ(0, int32_value);
2485 CheckUncle(&try_catch);
2486
2487 uint32_t uint32_value = obj->Uint32Value();
2488 CHECK_EQ(0, uint32_value);
2489 CheckUncle(&try_catch);
2490
2491 double number_value = obj->NumberValue();
2492 CHECK_NE(0, IsNaN(number_value));
2493 CheckUncle(&try_catch);
2494
2495 int64_t integer_value = obj->IntegerValue();
2496 CHECK_EQ(0.0, static_cast<double>(integer_value));
2497 CheckUncle(&try_catch);
2498}
2499
2500
2501v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2502 ApiTestFuzzer::Fuzz();
2503 return v8::ThrowException(v8_str("konto"));
2504}
2505
2506
ager@chromium.org8bb60582008-12-11 12:02:20 +00002507v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2508 if (args.Length() < 1) return v8::Boolean::New(false);
2509 v8::HandleScope scope;
2510 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002511 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2512 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002513 return v8::Boolean::New(try_catch.HasCaught());
2514}
2515
2516
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002517THREADED_TEST(APICatch) {
2518 v8::HandleScope scope;
2519 Local<ObjectTemplate> templ = ObjectTemplate::New();
2520 templ->Set(v8_str("ThrowFromC"),
2521 v8::FunctionTemplate::New(ThrowFromC));
2522 LocalContext context(0, templ);
2523 CompileRun(
2524 "var thrown = false;"
2525 "try {"
2526 " ThrowFromC();"
2527 "} catch (e) {"
2528 " thrown = true;"
2529 "}");
2530 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2531 CHECK(thrown->BooleanValue());
2532}
2533
2534
ager@chromium.org8bb60582008-12-11 12:02:20 +00002535THREADED_TEST(APIThrowTryCatch) {
2536 v8::HandleScope scope;
2537 Local<ObjectTemplate> templ = ObjectTemplate::New();
2538 templ->Set(v8_str("ThrowFromC"),
2539 v8::FunctionTemplate::New(ThrowFromC));
2540 LocalContext context(0, templ);
2541 v8::TryCatch try_catch;
2542 CompileRun("ThrowFromC();");
2543 CHECK(try_catch.HasCaught());
2544}
2545
2546
2547// Test that a try-finally block doesn't shadow a try-catch block
2548// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002549//
2550// BUG(271): Some of the exception propagation does not work on the
2551// ARM simulator because the simulator separates the C++ stack and the
2552// JS stack. This test therefore fails on the simulator. The test is
2553// not threaded to allow the threading tests to run on the simulator.
2554TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002555 v8::HandleScope scope;
2556 Local<ObjectTemplate> templ = ObjectTemplate::New();
2557 templ->Set(v8_str("CCatcher"),
2558 v8::FunctionTemplate::New(CCatcher));
2559 LocalContext context(0, templ);
2560 Local<Value> result = CompileRun("try {"
2561 " try {"
2562 " CCatcher('throw 7;');"
2563 " } finally {"
2564 " }"
2565 "} catch (e) {"
2566 "}");
2567 CHECK(result->IsTrue());
2568}
2569
2570
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002571static void check_reference_error_message(
2572 v8::Handle<v8::Message> message,
2573 v8::Handle<v8::Value> data) {
2574 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2575 CHECK(message->Get()->Equals(v8_str(reference_error)));
2576}
2577
2578
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002579static v8::Handle<Value> Fail(const v8::Arguments& args) {
2580 ApiTestFuzzer::Fuzz();
2581 CHECK(false);
2582 return v8::Undefined();
2583}
2584
2585
2586// Test that overwritten methods are not invoked on uncaught exception
2587// formatting. However, they are invoked when performing normal error
2588// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002589TEST(APIThrowMessageOverwrittenToString) {
2590 v8::HandleScope scope;
2591 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002592 Local<ObjectTemplate> templ = ObjectTemplate::New();
2593 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2594 LocalContext context(NULL, templ);
2595 CompileRun("asdf;");
2596 CompileRun("var limit = {};"
2597 "limit.valueOf = fail;"
2598 "Error.stackTraceLimit = limit;");
2599 CompileRun("asdf");
2600 CompileRun("Array.prototype.pop = fail;");
2601 CompileRun("Object.prototype.hasOwnProperty = fail;");
2602 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002603 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2604 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002605 CompileRun("ReferenceError.prototype.toString ="
2606 " function() { return 'Whoops' }");
2607 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002608 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2609 CompileRun("asdf;");
2610 CompileRun("ReferenceError.prototype.constructor = void 0;");
2611 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002612 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2613 CompileRun("asdf;");
2614 CompileRun("ReferenceError.prototype = new Object();");
2615 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002616 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2617 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002618 CompileRun("ReferenceError.prototype.constructor = new Object();"
2619 "ReferenceError.prototype.constructor.name = 1;"
2620 "Number.prototype.toString = function() { return 'Whoops'; };"
2621 "ReferenceError.prototype.toString = Object.prototype.toString;");
2622 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002623 v8::V8::RemoveMessageListeners(check_message);
2624}
2625
2626
ager@chromium.org8bb60582008-12-11 12:02:20 +00002627static void receive_message(v8::Handle<v8::Message> message,
2628 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002629 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002630 message_received = true;
2631}
2632
2633
2634TEST(APIThrowMessage) {
2635 message_received = false;
2636 v8::HandleScope scope;
2637 v8::V8::AddMessageListener(receive_message);
2638 Local<ObjectTemplate> templ = ObjectTemplate::New();
2639 templ->Set(v8_str("ThrowFromC"),
2640 v8::FunctionTemplate::New(ThrowFromC));
2641 LocalContext context(0, templ);
2642 CompileRun("ThrowFromC();");
2643 CHECK(message_received);
2644 v8::V8::RemoveMessageListeners(check_message);
2645}
2646
2647
2648TEST(APIThrowMessageAndVerboseTryCatch) {
2649 message_received = false;
2650 v8::HandleScope scope;
2651 v8::V8::AddMessageListener(receive_message);
2652 Local<ObjectTemplate> templ = ObjectTemplate::New();
2653 templ->Set(v8_str("ThrowFromC"),
2654 v8::FunctionTemplate::New(ThrowFromC));
2655 LocalContext context(0, templ);
2656 v8::TryCatch try_catch;
2657 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002658 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002659 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002660 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002661 CHECK(message_received);
2662 v8::V8::RemoveMessageListeners(check_message);
2663}
2664
2665
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002666TEST(APIStackOverflowAndVerboseTryCatch) {
2667 message_received = false;
2668 v8::HandleScope scope;
2669 v8::V8::AddMessageListener(receive_message);
2670 LocalContext context;
2671 v8::TryCatch try_catch;
2672 try_catch.SetVerbose(true);
2673 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2674 CHECK(try_catch.HasCaught());
2675 CHECK(result.IsEmpty());
2676 CHECK(message_received);
2677 v8::V8::RemoveMessageListeners(receive_message);
2678}
2679
2680
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002681THREADED_TEST(ExternalScriptException) {
2682 v8::HandleScope scope;
2683 Local<ObjectTemplate> templ = ObjectTemplate::New();
2684 templ->Set(v8_str("ThrowFromC"),
2685 v8::FunctionTemplate::New(ThrowFromC));
2686 LocalContext context(0, templ);
2687
2688 v8::TryCatch try_catch;
2689 Local<Script> script
2690 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2691 Local<Value> result = script->Run();
2692 CHECK(result.IsEmpty());
2693 CHECK(try_catch.HasCaught());
2694 String::AsciiValue exception_value(try_catch.Exception());
2695 CHECK_EQ("konto", *exception_value);
2696}
2697
2698
2699
2700v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2701 ApiTestFuzzer::Fuzz();
2702 CHECK_EQ(4, args.Length());
2703 int count = args[0]->Int32Value();
2704 int cInterval = args[2]->Int32Value();
2705 if (count == 0) {
2706 return v8::ThrowException(v8_str("FromC"));
2707 } else {
2708 Local<v8::Object> global = Context::GetCurrent()->Global();
2709 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2710 v8::Handle<Value> argv[] = { v8_num(count - 1),
2711 args[1],
2712 args[2],
2713 args[3] };
2714 if (count % cInterval == 0) {
2715 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002716 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002717 int expected = args[3]->Int32Value();
2718 if (try_catch.HasCaught()) {
2719 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002720 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002721 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002722 } else {
2723 CHECK_NE(expected, count);
2724 }
2725 return result;
2726 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002727 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002728 }
2729 }
2730}
2731
2732
2733v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2734 ApiTestFuzzer::Fuzz();
2735 CHECK_EQ(3, args.Length());
2736 bool equality = args[0]->BooleanValue();
2737 int count = args[1]->Int32Value();
2738 int expected = args[2]->Int32Value();
2739 if (equality) {
2740 CHECK_EQ(count, expected);
2741 } else {
2742 CHECK_NE(count, expected);
2743 }
2744 return v8::Undefined();
2745}
2746
2747
ager@chromium.org8bb60582008-12-11 12:02:20 +00002748THREADED_TEST(EvalInTryFinally) {
2749 v8::HandleScope scope;
2750 LocalContext context;
2751 v8::TryCatch try_catch;
2752 CompileRun("(function() {"
2753 " try {"
2754 " eval('asldkf (*&^&*^');"
2755 " } finally {"
2756 " return;"
2757 " }"
2758 "})()");
2759 CHECK(!try_catch.HasCaught());
2760}
2761
2762
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002763// This test works by making a stack of alternating JavaScript and C
2764// activations. These activations set up exception handlers with regular
2765// intervals, one interval for C activations and another for JavaScript
2766// activations. When enough activations have been created an exception is
2767// thrown and we check that the right activation catches the exception and that
2768// no other activations do. The right activation is always the topmost one with
2769// a handler, regardless of whether it is in JavaScript or C.
2770//
2771// The notation used to describe a test case looks like this:
2772//
2773// *JS[4] *C[3] @JS[2] C[1] JS[0]
2774//
2775// Each entry is an activation, either JS or C. The index is the count at that
2776// level. Stars identify activations with exception handlers, the @ identifies
2777// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002778//
2779// BUG(271): Some of the exception propagation does not work on the
2780// ARM simulator because the simulator separates the C++ stack and the
2781// JS stack. This test therefore fails on the simulator. The test is
2782// not threaded to allow the threading tests to run on the simulator.
2783TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002784 v8::HandleScope scope;
2785 Local<ObjectTemplate> templ = ObjectTemplate::New();
2786 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2787 templ->Set(v8_str("CThrowCountDown"),
2788 v8::FunctionTemplate::New(CThrowCountDown));
2789 LocalContext context(0, templ);
2790 CompileRun(
2791 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2792 " if (count == 0) throw 'FromJS';"
2793 " if (count % jsInterval == 0) {"
2794 " try {"
2795 " var value = CThrowCountDown(count - 1,"
2796 " jsInterval,"
2797 " cInterval,"
2798 " expected);"
2799 " check(false, count, expected);"
2800 " return value;"
2801 " } catch (e) {"
2802 " check(true, count, expected);"
2803 " }"
2804 " } else {"
2805 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2806 " }"
2807 "}");
2808 Local<Function> fun =
2809 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2810
2811 const int argc = 4;
2812 // count jsInterval cInterval expected
2813
2814 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2815 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2816 fun->Call(fun, argc, a0);
2817
2818 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2819 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2820 fun->Call(fun, argc, a1);
2821
2822 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2823 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2824 fun->Call(fun, argc, a2);
2825
2826 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2827 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2828 fun->Call(fun, argc, a3);
2829
2830 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2831 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2832 fun->Call(fun, argc, a4);
2833
2834 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2835 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2836 fun->Call(fun, argc, a5);
2837}
2838
2839
2840v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2841 ApiTestFuzzer::Fuzz();
2842 CHECK_EQ(1, args.Length());
2843 return v8::ThrowException(args[0]);
2844}
2845
2846
2847THREADED_TEST(ThrowValues) {
2848 v8::HandleScope scope;
2849 Local<ObjectTemplate> templ = ObjectTemplate::New();
2850 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2851 LocalContext context(0, templ);
2852 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2853 "function Run(obj) {"
2854 " try {"
2855 " Throw(obj);"
2856 " } catch (e) {"
2857 " return e;"
2858 " }"
2859 " return 'no exception';"
2860 "}"
2861 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2862 CHECK_EQ(5, result->Length());
2863 CHECK(result->Get(v8::Integer::New(0))->IsString());
2864 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2865 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2866 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2867 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2868 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2869 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2870}
2871
2872
2873THREADED_TEST(CatchZero) {
2874 v8::HandleScope scope;
2875 LocalContext context;
2876 v8::TryCatch try_catch;
2877 CHECK(!try_catch.HasCaught());
2878 Script::Compile(v8_str("throw 10"))->Run();
2879 CHECK(try_catch.HasCaught());
2880 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2881 try_catch.Reset();
2882 CHECK(!try_catch.HasCaught());
2883 Script::Compile(v8_str("throw 0"))->Run();
2884 CHECK(try_catch.HasCaught());
2885 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2886}
2887
2888
2889THREADED_TEST(CatchExceptionFromWith) {
2890 v8::HandleScope scope;
2891 LocalContext context;
2892 v8::TryCatch try_catch;
2893 CHECK(!try_catch.HasCaught());
2894 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2895 CHECK(try_catch.HasCaught());
2896}
2897
2898
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002899THREADED_TEST(TryCatchAndFinallyHidingException) {
2900 v8::HandleScope scope;
2901 LocalContext context;
2902 v8::TryCatch try_catch;
2903 CHECK(!try_catch.HasCaught());
2904 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
2905 CompileRun("f({toString: function() { throw 42; }});");
2906 CHECK(!try_catch.HasCaught());
2907}
2908
2909
2910v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
2911 v8::TryCatch try_catch;
2912 return v8::Undefined();
2913}
2914
2915
2916THREADED_TEST(TryCatchAndFinally) {
2917 v8::HandleScope scope;
2918 LocalContext context;
2919 context->Global()->Set(
2920 v8_str("native_with_try_catch"),
2921 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
2922 v8::TryCatch try_catch;
2923 CHECK(!try_catch.HasCaught());
2924 CompileRun(
2925 "try {\n"
2926 " throw new Error('a');\n"
2927 "} finally {\n"
2928 " native_with_try_catch();\n"
2929 "}\n");
2930 CHECK(try_catch.HasCaught());
2931}
2932
2933
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002934THREADED_TEST(Equality) {
2935 v8::HandleScope scope;
2936 LocalContext context;
2937 // Check that equality works at all before relying on CHECK_EQ
2938 CHECK(v8_str("a")->Equals(v8_str("a")));
2939 CHECK(!v8_str("a")->Equals(v8_str("b")));
2940
2941 CHECK_EQ(v8_str("a"), v8_str("a"));
2942 CHECK_NE(v8_str("a"), v8_str("b"));
2943 CHECK_EQ(v8_num(1), v8_num(1));
2944 CHECK_EQ(v8_num(1.00), v8_num(1));
2945 CHECK_NE(v8_num(1), v8_num(2));
2946
2947 // Assume String is not symbol.
2948 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2949 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2950 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2951 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2952 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2953 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2954 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2955 CHECK(!not_a_number->StrictEquals(not_a_number));
2956 CHECK(v8::False()->StrictEquals(v8::False()));
2957 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2958
2959 v8::Handle<v8::Object> obj = v8::Object::New();
2960 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2961 CHECK(alias->StrictEquals(obj));
2962 alias.Dispose();
2963}
2964
2965
2966THREADED_TEST(MultiRun) {
2967 v8::HandleScope scope;
2968 LocalContext context;
2969 Local<Script> script = Script::Compile(v8_str("x"));
2970 for (int i = 0; i < 10; i++)
2971 script->Run();
2972}
2973
2974
2975static v8::Handle<Value> GetXValue(Local<String> name,
2976 const AccessorInfo& info) {
2977 ApiTestFuzzer::Fuzz();
2978 CHECK_EQ(info.Data(), v8_str("donut"));
2979 CHECK_EQ(name, v8_str("x"));
2980 return name;
2981}
2982
2983
2984THREADED_TEST(SimplePropertyRead) {
2985 v8::HandleScope scope;
2986 Local<ObjectTemplate> templ = ObjectTemplate::New();
2987 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2988 LocalContext context;
2989 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2990 Local<Script> script = Script::Compile(v8_str("obj.x"));
2991 for (int i = 0; i < 10; i++) {
2992 Local<Value> result = script->Run();
2993 CHECK_EQ(result, v8_str("x"));
2994 }
2995}
2996
ager@chromium.org5c838252010-02-19 08:53:10 +00002997THREADED_TEST(DefinePropertyOnAPIAccessor) {
2998 v8::HandleScope scope;
2999 Local<ObjectTemplate> templ = ObjectTemplate::New();
3000 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3001 LocalContext context;
3002 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3003
3004 // Uses getOwnPropertyDescriptor to check the configurable status
3005 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003006 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003007 "obj, 'x');"
3008 "prop.configurable;"));
3009 Local<Value> result = script_desc->Run();
3010 CHECK_EQ(result->BooleanValue(), true);
3011
3012 // Redefine get - but still configurable
3013 Local<Script> script_define
3014 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3015 " configurable: true };"
3016 "Object.defineProperty(obj, 'x', desc);"
3017 "obj.x"));
3018 result = script_define->Run();
3019 CHECK_EQ(result, v8_num(42));
3020
3021 // Check that the accessor is still configurable
3022 result = script_desc->Run();
3023 CHECK_EQ(result->BooleanValue(), true);
3024
3025 // Redefine to a non-configurable
3026 script_define
3027 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3028 " configurable: false };"
3029 "Object.defineProperty(obj, 'x', desc);"
3030 "obj.x"));
3031 result = script_define->Run();
3032 CHECK_EQ(result, v8_num(43));
3033 result = script_desc->Run();
3034 CHECK_EQ(result->BooleanValue(), false);
3035
3036 // Make sure that it is not possible to redefine again
3037 v8::TryCatch try_catch;
3038 result = script_define->Run();
3039 CHECK(try_catch.HasCaught());
3040 String::AsciiValue exception_value(try_catch.Exception());
3041 CHECK_EQ(*exception_value,
3042 "TypeError: Cannot redefine property: defineProperty");
3043}
3044
3045THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3046 v8::HandleScope scope;
3047 Local<ObjectTemplate> templ = ObjectTemplate::New();
3048 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3049 LocalContext context;
3050 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3051
3052 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3053 "Object.getOwnPropertyDescriptor( "
3054 "obj, 'x');"
3055 "prop.configurable;"));
3056 Local<Value> result = script_desc->Run();
3057 CHECK_EQ(result->BooleanValue(), true);
3058
3059 Local<Script> script_define =
3060 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3061 " configurable: true };"
3062 "Object.defineProperty(obj, 'x', desc);"
3063 "obj.x"));
3064 result = script_define->Run();
3065 CHECK_EQ(result, v8_num(42));
3066
3067
3068 result = script_desc->Run();
3069 CHECK_EQ(result->BooleanValue(), true);
3070
3071
3072 script_define =
3073 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3074 " configurable: false };"
3075 "Object.defineProperty(obj, 'x', desc);"
3076 "obj.x"));
3077 result = script_define->Run();
3078 CHECK_EQ(result, v8_num(43));
3079 result = script_desc->Run();
3080
3081 CHECK_EQ(result->BooleanValue(), false);
3082
3083 v8::TryCatch try_catch;
3084 result = script_define->Run();
3085 CHECK(try_catch.HasCaught());
3086 String::AsciiValue exception_value(try_catch.Exception());
3087 CHECK_EQ(*exception_value,
3088 "TypeError: Cannot redefine property: defineProperty");
3089}
3090
3091
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003092static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3093 char const* name) {
3094 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3095}
ager@chromium.org5c838252010-02-19 08:53:10 +00003096
3097
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003098THREADED_TEST(DefineAPIAccessorOnObject) {
3099 v8::HandleScope scope;
3100 Local<ObjectTemplate> templ = ObjectTemplate::New();
3101 LocalContext context;
3102
3103 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3104 CompileRun("var obj2 = {};");
3105
3106 CHECK(CompileRun("obj1.x")->IsUndefined());
3107 CHECK(CompileRun("obj2.x")->IsUndefined());
3108
3109 CHECK(GetGlobalProperty(&context, "obj1")->
3110 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3111
3112 ExpectString("obj1.x", "x");
3113 CHECK(CompileRun("obj2.x")->IsUndefined());
3114
3115 CHECK(GetGlobalProperty(&context, "obj2")->
3116 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3117
3118 ExpectString("obj1.x", "x");
3119 ExpectString("obj2.x", "x");
3120
3121 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3122 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3123
3124 CompileRun("Object.defineProperty(obj1, 'x',"
3125 "{ get: function() { return 'y'; }, configurable: true })");
3126
3127 ExpectString("obj1.x", "y");
3128 ExpectString("obj2.x", "x");
3129
3130 CompileRun("Object.defineProperty(obj2, 'x',"
3131 "{ get: function() { return 'y'; }, configurable: true })");
3132
3133 ExpectString("obj1.x", "y");
3134 ExpectString("obj2.x", "y");
3135
3136 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3137 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3138
3139 CHECK(GetGlobalProperty(&context, "obj1")->
3140 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3141 CHECK(GetGlobalProperty(&context, "obj2")->
3142 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3143
3144 ExpectString("obj1.x", "x");
3145 ExpectString("obj2.x", "x");
3146
3147 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3148 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3149
3150 // Define getters/setters, but now make them not configurable.
3151 CompileRun("Object.defineProperty(obj1, 'x',"
3152 "{ get: function() { return 'z'; }, configurable: false })");
3153 CompileRun("Object.defineProperty(obj2, 'x',"
3154 "{ get: function() { return 'z'; }, configurable: false })");
3155
3156 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3157 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3158
3159 ExpectString("obj1.x", "z");
3160 ExpectString("obj2.x", "z");
3161
3162 CHECK(!GetGlobalProperty(&context, "obj1")->
3163 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3164 CHECK(!GetGlobalProperty(&context, "obj2")->
3165 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3166
3167 ExpectString("obj1.x", "z");
3168 ExpectString("obj2.x", "z");
3169}
3170
3171
3172THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3173 v8::HandleScope scope;
3174 Local<ObjectTemplate> templ = ObjectTemplate::New();
3175 LocalContext context;
3176
3177 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3178 CompileRun("var obj2 = {};");
3179
3180 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3181 v8_str("x"),
3182 GetXValue, NULL,
3183 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3184 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3185 v8_str("x"),
3186 GetXValue, NULL,
3187 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3188
3189 ExpectString("obj1.x", "x");
3190 ExpectString("obj2.x", "x");
3191
3192 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3193 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3194
3195 CHECK(!GetGlobalProperty(&context, "obj1")->
3196 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3197 CHECK(!GetGlobalProperty(&context, "obj2")->
3198 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3199
3200 {
3201 v8::TryCatch try_catch;
3202 CompileRun("Object.defineProperty(obj1, 'x',"
3203 "{get: function() { return 'func'; }})");
3204 CHECK(try_catch.HasCaught());
3205 String::AsciiValue exception_value(try_catch.Exception());
3206 CHECK_EQ(*exception_value,
3207 "TypeError: Cannot redefine property: defineProperty");
3208 }
3209 {
3210 v8::TryCatch try_catch;
3211 CompileRun("Object.defineProperty(obj2, 'x',"
3212 "{get: function() { return 'func'; }})");
3213 CHECK(try_catch.HasCaught());
3214 String::AsciiValue exception_value(try_catch.Exception());
3215 CHECK_EQ(*exception_value,
3216 "TypeError: Cannot redefine property: defineProperty");
3217 }
3218}
3219
3220
3221static v8::Handle<Value> Get239Value(Local<String> name,
3222 const AccessorInfo& info) {
3223 ApiTestFuzzer::Fuzz();
3224 CHECK_EQ(info.Data(), v8_str("donut"));
3225 CHECK_EQ(name, v8_str("239"));
3226 return name;
3227}
3228
3229
3230THREADED_TEST(ElementAPIAccessor) {
3231 v8::HandleScope scope;
3232 Local<ObjectTemplate> templ = ObjectTemplate::New();
3233 LocalContext context;
3234
3235 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3236 CompileRun("var obj2 = {};");
3237
3238 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3239 v8_str("239"),
3240 Get239Value, NULL,
3241 v8_str("donut")));
3242 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3243 v8_str("239"),
3244 Get239Value, NULL,
3245 v8_str("donut")));
3246
3247 ExpectString("obj1[239]", "239");
3248 ExpectString("obj2[239]", "239");
3249 ExpectString("obj1['239']", "239");
3250 ExpectString("obj2['239']", "239");
3251}
3252
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003253
3254v8::Persistent<Value> xValue;
3255
3256
3257static void SetXValue(Local<String> name,
3258 Local<Value> value,
3259 const AccessorInfo& info) {
3260 CHECK_EQ(value, v8_num(4));
3261 CHECK_EQ(info.Data(), v8_str("donut"));
3262 CHECK_EQ(name, v8_str("x"));
3263 CHECK(xValue.IsEmpty());
3264 xValue = v8::Persistent<Value>::New(value);
3265}
3266
3267
3268THREADED_TEST(SimplePropertyWrite) {
3269 v8::HandleScope scope;
3270 Local<ObjectTemplate> templ = ObjectTemplate::New();
3271 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3272 LocalContext context;
3273 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3274 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3275 for (int i = 0; i < 10; i++) {
3276 CHECK(xValue.IsEmpty());
3277 script->Run();
3278 CHECK_EQ(v8_num(4), xValue);
3279 xValue.Dispose();
3280 xValue = v8::Persistent<Value>();
3281 }
3282}
3283
3284
3285static v8::Handle<Value> XPropertyGetter(Local<String> property,
3286 const AccessorInfo& info) {
3287 ApiTestFuzzer::Fuzz();
3288 CHECK(info.Data()->IsUndefined());
3289 return property;
3290}
3291
3292
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003293THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003294 v8::HandleScope scope;
3295 Local<ObjectTemplate> templ = ObjectTemplate::New();
3296 templ->SetNamedPropertyHandler(XPropertyGetter);
3297 LocalContext context;
3298 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3299 Local<Script> script = Script::Compile(v8_str("obj.x"));
3300 for (int i = 0; i < 10; i++) {
3301 Local<Value> result = script->Run();
3302 CHECK_EQ(result, v8_str("x"));
3303 }
3304}
3305
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003306
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003307THREADED_TEST(NamedInterceptorDictionaryIC) {
3308 v8::HandleScope scope;
3309 Local<ObjectTemplate> templ = ObjectTemplate::New();
3310 templ->SetNamedPropertyHandler(XPropertyGetter);
3311 LocalContext context;
3312 // Create an object with a named interceptor.
3313 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3314 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3315 for (int i = 0; i < 10; i++) {
3316 Local<Value> result = script->Run();
3317 CHECK_EQ(result, v8_str("x"));
3318 }
3319 // Create a slow case object and a function accessing a property in
3320 // that slow case object (with dictionary probing in generated
3321 // code). Then force object with a named interceptor into slow-case,
3322 // pass it to the function, and check that the interceptor is called
3323 // instead of accessing the local property.
3324 Local<Value> result =
3325 CompileRun("function get_x(o) { return o.x; };"
3326 "var obj = { x : 42, y : 0 };"
3327 "delete obj.y;"
3328 "for (var i = 0; i < 10; i++) get_x(obj);"
3329 "interceptor_obj.x = 42;"
3330 "interceptor_obj.y = 10;"
3331 "delete interceptor_obj.y;"
3332 "get_x(interceptor_obj)");
3333 CHECK_EQ(result, v8_str("x"));
3334}
3335
3336
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003337THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3338 v8::HandleScope scope;
3339
3340 v8::Persistent<Context> context1 = Context::New();
3341
3342 context1->Enter();
3343 Local<ObjectTemplate> templ = ObjectTemplate::New();
3344 templ->SetNamedPropertyHandler(XPropertyGetter);
3345 // Create an object with a named interceptor.
3346 v8::Local<v8::Object> object = templ->NewInstance();
3347 context1->Global()->Set(v8_str("interceptor_obj"), object);
3348
3349 // Force the object into the slow case.
3350 CompileRun("interceptor_obj.y = 0;"
3351 "delete interceptor_obj.y;");
3352 context1->Exit();
3353
3354 {
3355 // Introduce the object into a different context.
3356 // Repeat named loads to exercise ICs.
3357 LocalContext context2;
3358 context2->Global()->Set(v8_str("interceptor_obj"), object);
3359 Local<Value> result =
3360 CompileRun("function get_x(o) { return o.x; }"
3361 "interceptor_obj.x = 42;"
3362 "for (var i=0; i != 10; i++) {"
3363 " get_x(interceptor_obj);"
3364 "}"
3365 "get_x(interceptor_obj)");
3366 // Check that the interceptor was actually invoked.
3367 CHECK_EQ(result, v8_str("x"));
3368 }
3369
3370 // Return to the original context and force some object to the slow case
3371 // to cause the NormalizedMapCache to verify.
3372 context1->Enter();
3373 CompileRun("var obj = { x : 0 }; delete obj.x;");
3374 context1->Exit();
3375
3376 context1.Dispose();
3377}
3378
3379
ager@chromium.org5c838252010-02-19 08:53:10 +00003380static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3381 const AccessorInfo& info) {
3382 // Set x on the prototype object and do not handle the get request.
3383 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003384 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003385 return v8::Handle<Value>();
3386}
3387
3388
3389// This is a regression test for http://crbug.com/20104. Map
3390// transitions should not interfere with post interceptor lookup.
3391THREADED_TEST(NamedInterceptorMapTransitionRead) {
3392 v8::HandleScope scope;
3393 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3394 Local<v8::ObjectTemplate> instance_template
3395 = function_template->InstanceTemplate();
3396 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3397 LocalContext context;
3398 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3399 // Create an instance of F and introduce a map transition for x.
3400 CompileRun("var o = new F(); o.x = 23;");
3401 // Create an instance of F and invoke the getter. The result should be 23.
3402 Local<Value> result = CompileRun("o = new F(); o.x");
3403 CHECK_EQ(result->Int32Value(), 23);
3404}
3405
3406
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003407static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3408 const AccessorInfo& info) {
3409 ApiTestFuzzer::Fuzz();
3410 if (index == 37) {
3411 return v8::Handle<Value>(v8_num(625));
3412 }
3413 return v8::Handle<Value>();
3414}
3415
3416
3417static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3418 Local<Value> value,
3419 const AccessorInfo& info) {
3420 ApiTestFuzzer::Fuzz();
3421 if (index == 39) {
3422 return value;
3423 }
3424 return v8::Handle<Value>();
3425}
3426
3427
3428THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3429 v8::HandleScope scope;
3430 Local<ObjectTemplate> templ = ObjectTemplate::New();
3431 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3432 IndexedPropertySetter);
3433 LocalContext context;
3434 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3435 Local<Script> getter_script = Script::Compile(v8_str(
3436 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3437 Local<Script> setter_script = Script::Compile(v8_str(
3438 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3439 "obj[17] = 23;"
3440 "obj.foo;"));
3441 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3442 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3443 "obj[39] = 47;"
3444 "obj.foo;")); // This setter should not run, due to the interceptor.
3445 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3446 "obj[37];"));
3447 Local<Value> result = getter_script->Run();
3448 CHECK_EQ(v8_num(5), result);
3449 result = setter_script->Run();
3450 CHECK_EQ(v8_num(23), result);
3451 result = interceptor_setter_script->Run();
3452 CHECK_EQ(v8_num(23), result);
3453 result = interceptor_getter_script->Run();
3454 CHECK_EQ(v8_num(625), result);
3455}
3456
3457
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003458static v8::Handle<Value> IdentityIndexedPropertyGetter(
3459 uint32_t index,
3460 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003461 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003462}
3463
3464
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003465THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3466 v8::HandleScope scope;
3467 Local<ObjectTemplate> templ = ObjectTemplate::New();
3468 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3469
3470 LocalContext context;
3471 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3472
3473 // Check fast object case.
3474 const char* fast_case_code =
3475 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3476 ExpectString(fast_case_code, "0");
3477
3478 // Check slow case.
3479 const char* slow_case_code =
3480 "obj.x = 1; delete obj.x;"
3481 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3482 ExpectString(slow_case_code, "1");
3483}
3484
3485
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003486THREADED_TEST(IndexedInterceptorWithNoSetter) {
3487 v8::HandleScope scope;
3488 Local<ObjectTemplate> templ = ObjectTemplate::New();
3489 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3490
3491 LocalContext context;
3492 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3493
3494 const char* code =
3495 "try {"
3496 " obj[0] = 239;"
3497 " for (var i = 0; i < 100; i++) {"
3498 " var v = obj[0];"
3499 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3500 " }"
3501 " 'PASSED'"
3502 "} catch(e) {"
3503 " e"
3504 "}";
3505 ExpectString(code, "PASSED");
3506}
3507
3508
ager@chromium.org5c838252010-02-19 08:53:10 +00003509THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3510 v8::HandleScope scope;
3511 Local<ObjectTemplate> templ = ObjectTemplate::New();
3512 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3513
3514 LocalContext context;
3515 Local<v8::Object> obj = templ->NewInstance();
3516 obj->TurnOnAccessCheck();
3517 context->Global()->Set(v8_str("obj"), obj);
3518
3519 const char* code =
3520 "try {"
3521 " for (var i = 0; i < 100; i++) {"
3522 " var v = obj[0];"
3523 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3524 " }"
3525 " 'PASSED'"
3526 "} catch(e) {"
3527 " e"
3528 "}";
3529 ExpectString(code, "PASSED");
3530}
3531
3532
3533THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3534 i::FLAG_allow_natives_syntax = true;
3535 v8::HandleScope scope;
3536 Local<ObjectTemplate> templ = ObjectTemplate::New();
3537 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3538
3539 LocalContext context;
3540 Local<v8::Object> obj = templ->NewInstance();
3541 context->Global()->Set(v8_str("obj"), obj);
3542
3543 const char* code =
3544 "try {"
3545 " for (var i = 0; i < 100; i++) {"
3546 " var expected = i;"
3547 " if (i == 5) {"
3548 " %EnableAccessChecks(obj);"
3549 " expected = undefined;"
3550 " }"
3551 " var v = obj[i];"
3552 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3553 " if (i == 5) %DisableAccessChecks(obj);"
3554 " }"
3555 " 'PASSED'"
3556 "} catch(e) {"
3557 " e"
3558 "}";
3559 ExpectString(code, "PASSED");
3560}
3561
3562
3563THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3564 v8::HandleScope scope;
3565 Local<ObjectTemplate> templ = ObjectTemplate::New();
3566 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3567
3568 LocalContext context;
3569 Local<v8::Object> obj = templ->NewInstance();
3570 context->Global()->Set(v8_str("obj"), obj);
3571
3572 const char* code =
3573 "try {"
3574 " for (var i = 0; i < 100; i++) {"
3575 " var v = obj[i];"
3576 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3577 " }"
3578 " 'PASSED'"
3579 "} catch(e) {"
3580 " e"
3581 "}";
3582 ExpectString(code, "PASSED");
3583}
3584
3585
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003586THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3587 v8::HandleScope scope;
3588 Local<ObjectTemplate> templ = ObjectTemplate::New();
3589 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3590
3591 LocalContext context;
3592 Local<v8::Object> obj = templ->NewInstance();
3593 context->Global()->Set(v8_str("obj"), obj);
3594
3595 const char* code =
3596 "try {"
3597 " for (var i = 0; i < 100; i++) {"
3598 " var expected = i;"
3599 " var key = i;"
3600 " if (i == 25) {"
3601 " key = -1;"
3602 " expected = undefined;"
3603 " }"
3604 " if (i == 50) {"
3605 " /* probe minimal Smi number on 32-bit platforms */"
3606 " key = -(1 << 30);"
3607 " expected = undefined;"
3608 " }"
3609 " if (i == 75) {"
3610 " /* probe minimal Smi number on 64-bit platforms */"
3611 " key = 1 << 31;"
3612 " expected = undefined;"
3613 " }"
3614 " var v = obj[key];"
3615 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3616 " }"
3617 " 'PASSED'"
3618 "} catch(e) {"
3619 " e"
3620 "}";
3621 ExpectString(code, "PASSED");
3622}
3623
3624
ager@chromium.org5c838252010-02-19 08:53:10 +00003625THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3626 v8::HandleScope scope;
3627 Local<ObjectTemplate> templ = ObjectTemplate::New();
3628 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3629
3630 LocalContext context;
3631 Local<v8::Object> obj = templ->NewInstance();
3632 context->Global()->Set(v8_str("obj"), obj);
3633
3634 const char* code =
3635 "try {"
3636 " for (var i = 0; i < 100; i++) {"
3637 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003638 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003639 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003640 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003641 " expected = undefined;"
3642 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003643 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003644 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3645 " }"
3646 " 'PASSED'"
3647 "} catch(e) {"
3648 " e"
3649 "}";
3650 ExpectString(code, "PASSED");
3651}
3652
3653
3654THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3655 v8::HandleScope scope;
3656 Local<ObjectTemplate> templ = ObjectTemplate::New();
3657 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3658
3659 LocalContext context;
3660 Local<v8::Object> obj = templ->NewInstance();
3661 context->Global()->Set(v8_str("obj"), obj);
3662
3663 const char* code =
3664 "var original = obj;"
3665 "try {"
3666 " for (var i = 0; i < 100; i++) {"
3667 " var expected = i;"
3668 " if (i == 50) {"
3669 " obj = {50: 'foobar'};"
3670 " expected = 'foobar';"
3671 " }"
3672 " var v = obj[i];"
3673 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3674 " if (i == 50) obj = original;"
3675 " }"
3676 " 'PASSED'"
3677 "} catch(e) {"
3678 " e"
3679 "}";
3680 ExpectString(code, "PASSED");
3681}
3682
3683
3684THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3685 v8::HandleScope scope;
3686 Local<ObjectTemplate> templ = ObjectTemplate::New();
3687 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3688
3689 LocalContext context;
3690 Local<v8::Object> obj = templ->NewInstance();
3691 context->Global()->Set(v8_str("obj"), obj);
3692
3693 const char* code =
3694 "var original = obj;"
3695 "try {"
3696 " for (var i = 0; i < 100; i++) {"
3697 " var expected = i;"
3698 " if (i == 5) {"
3699 " obj = 239;"
3700 " expected = undefined;"
3701 " }"
3702 " var v = obj[i];"
3703 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3704 " if (i == 5) obj = original;"
3705 " }"
3706 " 'PASSED'"
3707 "} catch(e) {"
3708 " e"
3709 "}";
3710 ExpectString(code, "PASSED");
3711}
3712
3713
3714THREADED_TEST(IndexedInterceptorOnProto) {
3715 v8::HandleScope scope;
3716 Local<ObjectTemplate> templ = ObjectTemplate::New();
3717 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3718
3719 LocalContext context;
3720 Local<v8::Object> obj = templ->NewInstance();
3721 context->Global()->Set(v8_str("obj"), obj);
3722
3723 const char* code =
3724 "var o = {__proto__: obj};"
3725 "try {"
3726 " for (var i = 0; i < 100; i++) {"
3727 " var v = o[i];"
3728 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3729 " }"
3730 " 'PASSED'"
3731 "} catch(e) {"
3732 " e"
3733 "}";
3734 ExpectString(code, "PASSED");
3735}
3736
3737
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003738THREADED_TEST(MultiContexts) {
3739 v8::HandleScope scope;
3740 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3741 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3742
3743 Local<String> password = v8_str("Password");
3744
3745 // Create an environment
3746 LocalContext context0(0, templ);
3747 context0->SetSecurityToken(password);
3748 v8::Handle<v8::Object> global0 = context0->Global();
3749 global0->Set(v8_str("custom"), v8_num(1234));
3750 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3751
3752 // Create an independent environment
3753 LocalContext context1(0, templ);
3754 context1->SetSecurityToken(password);
3755 v8::Handle<v8::Object> global1 = context1->Global();
3756 global1->Set(v8_str("custom"), v8_num(1234));
3757 CHECK_NE(global0, global1);
3758 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3759 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3760
3761 // Now create a new context with the old global
3762 LocalContext context2(0, templ, global1);
3763 context2->SetSecurityToken(password);
3764 v8::Handle<v8::Object> global2 = context2->Global();
3765 CHECK_EQ(global1, global2);
3766 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3767 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3768}
3769
3770
3771THREADED_TEST(FunctionPrototypeAcrossContexts) {
3772 // Make sure that functions created by cloning boilerplates cannot
3773 // communicate through their __proto__ field.
3774
3775 v8::HandleScope scope;
3776
3777 LocalContext env0;
3778 v8::Handle<v8::Object> global0 =
3779 env0->Global();
3780 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003781 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003782 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003783 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003784 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003785 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003786 proto0->Set(v8_str("custom"), v8_num(1234));
3787
3788 LocalContext env1;
3789 v8::Handle<v8::Object> global1 =
3790 env1->Global();
3791 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003792 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003793 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003794 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003795 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003796 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003797 CHECK(!proto1->Has(v8_str("custom")));
3798}
3799
3800
3801THREADED_TEST(Regress892105) {
3802 // Make sure that object and array literals created by cloning
3803 // boilerplates cannot communicate through their __proto__
3804 // field. This is rather difficult to check, but we try to add stuff
3805 // to Object.prototype and Array.prototype and create a new
3806 // environment. This should succeed.
3807
3808 v8::HandleScope scope;
3809
3810 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3811 "Array.prototype.arr = 4567;"
3812 "8901");
3813
3814 LocalContext env0;
3815 Local<Script> script0 = Script::Compile(source);
3816 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3817
3818 LocalContext env1;
3819 Local<Script> script1 = Script::Compile(source);
3820 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3821}
3822
3823
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003824THREADED_TEST(UndetectableObject) {
3825 v8::HandleScope scope;
3826 LocalContext env;
3827
3828 Local<v8::FunctionTemplate> desc =
3829 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3830 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3831
3832 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3833 env->Global()->Set(v8_str("undetectable"), obj);
3834
3835 ExpectString("undetectable.toString()", "[object Object]");
3836 ExpectString("typeof undetectable", "undefined");
3837 ExpectString("typeof(undetectable)", "undefined");
3838 ExpectBoolean("typeof undetectable == 'undefined'", true);
3839 ExpectBoolean("typeof undetectable == 'object'", false);
3840 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3841 ExpectBoolean("!undetectable", true);
3842
3843 ExpectObject("true&&undetectable", obj);
3844 ExpectBoolean("false&&undetectable", false);
3845 ExpectBoolean("true||undetectable", true);
3846 ExpectObject("false||undetectable", obj);
3847
3848 ExpectObject("undetectable&&true", obj);
3849 ExpectObject("undetectable&&false", obj);
3850 ExpectBoolean("undetectable||true", true);
3851 ExpectBoolean("undetectable||false", false);
3852
3853 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003854 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003855 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003856 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003857 ExpectBoolean("undetectable==undetectable", true);
3858
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003859
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003860 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003861 ExpectBoolean("null===undetectable", false);
3862 ExpectBoolean("undetectable===undefined", false);
3863 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003864 ExpectBoolean("undetectable===undetectable", true);
3865}
3866
3867
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003868
3869THREADED_TEST(ExtensibleOnUndetectable) {
3870 v8::HandleScope scope;
3871 LocalContext env;
3872
3873 Local<v8::FunctionTemplate> desc =
3874 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3875 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3876
3877 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3878 env->Global()->Set(v8_str("undetectable"), obj);
3879
3880 Local<String> source = v8_str("undetectable.x = 42;"
3881 "undetectable.x");
3882
3883 Local<Script> script = Script::Compile(source);
3884
3885 CHECK_EQ(v8::Integer::New(42), script->Run());
3886
3887 ExpectBoolean("Object.isExtensible(undetectable)", true);
3888
3889 source = v8_str("Object.preventExtensions(undetectable);");
3890 script = Script::Compile(source);
3891 script->Run();
3892 ExpectBoolean("Object.isExtensible(undetectable)", false);
3893
3894 source = v8_str("undetectable.y = 2000;");
3895 script = Script::Compile(source);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003896 Local<Value> result = script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003897 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003898}
3899
3900
3901
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003902THREADED_TEST(UndetectableString) {
3903 v8::HandleScope scope;
3904 LocalContext env;
3905
3906 Local<String> obj = String::NewUndetectable("foo");
3907 env->Global()->Set(v8_str("undetectable"), obj);
3908
3909 ExpectString("undetectable", "foo");
3910 ExpectString("typeof undetectable", "undefined");
3911 ExpectString("typeof(undetectable)", "undefined");
3912 ExpectBoolean("typeof undetectable == 'undefined'", true);
3913 ExpectBoolean("typeof undetectable == 'string'", false);
3914 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3915 ExpectBoolean("!undetectable", true);
3916
3917 ExpectObject("true&&undetectable", obj);
3918 ExpectBoolean("false&&undetectable", false);
3919 ExpectBoolean("true||undetectable", true);
3920 ExpectObject("false||undetectable", obj);
3921
3922 ExpectObject("undetectable&&true", obj);
3923 ExpectObject("undetectable&&false", obj);
3924 ExpectBoolean("undetectable||true", true);
3925 ExpectBoolean("undetectable||false", false);
3926
3927 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003928 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003929 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003930 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931 ExpectBoolean("undetectable==undetectable", true);
3932
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003933
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003934 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003935 ExpectBoolean("null===undetectable", false);
3936 ExpectBoolean("undetectable===undefined", false);
3937 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003938 ExpectBoolean("undetectable===undetectable", true);
3939}
3940
3941
3942template <typename T> static void USE(T) { }
3943
3944
3945// This test is not intended to be run, just type checked.
3946static void PersistentHandles() {
3947 USE(PersistentHandles);
3948 Local<String> str = v8_str("foo");
3949 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3950 USE(p_str);
3951 Local<Script> scr = Script::Compile(v8_str(""));
3952 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3953 USE(p_scr);
3954 Local<ObjectTemplate> templ = ObjectTemplate::New();
3955 v8::Persistent<ObjectTemplate> p_templ =
3956 v8::Persistent<ObjectTemplate>::New(templ);
3957 USE(p_templ);
3958}
3959
3960
3961static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3962 ApiTestFuzzer::Fuzz();
3963 return v8::Undefined();
3964}
3965
3966
3967THREADED_TEST(GlobalObjectTemplate) {
3968 v8::HandleScope handle_scope;
3969 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3970 global_template->Set(v8_str("JSNI_Log"),
3971 v8::FunctionTemplate::New(HandleLogDelegator));
3972 v8::Persistent<Context> context = Context::New(0, global_template);
3973 Context::Scope context_scope(context);
3974 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3975 context.Dispose();
3976}
3977
3978
3979static const char* kSimpleExtensionSource =
3980 "function Foo() {"
3981 " return 4;"
3982 "}";
3983
3984
3985THREADED_TEST(SimpleExtensions) {
3986 v8::HandleScope handle_scope;
3987 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3988 const char* extension_names[] = { "simpletest" };
3989 v8::ExtensionConfiguration extensions(1, extension_names);
3990 v8::Handle<Context> context = Context::New(&extensions);
3991 Context::Scope lock(context);
3992 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3993 CHECK_EQ(result, v8::Integer::New(4));
3994}
3995
3996
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003997static const char* kEvalExtensionSource1 =
3998 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00003999 " var x = 42;"
4000 " return eval('x');"
4001 "}";
4002
4003
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004004static const char* kEvalExtensionSource2 =
4005 "(function() {"
4006 " var x = 42;"
4007 " function e() {"
4008 " return eval('x');"
4009 " }"
4010 " this.UseEval2 = e;"
4011 "})()";
4012
4013
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004014THREADED_TEST(UseEvalFromExtension) {
4015 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004016 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4017 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4018 const char* extension_names[] = { "evaltest1", "evaltest2" };
4019 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004020 v8::Handle<Context> context = Context::New(&extensions);
4021 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004022 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4023 CHECK_EQ(result, v8::Integer::New(42));
4024 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004025 CHECK_EQ(result, v8::Integer::New(42));
4026}
4027
4028
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004029static const char* kWithExtensionSource1 =
4030 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004031 " var x = 42;"
4032 " with({x:87}) { return x; }"
4033 "}";
4034
4035
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004036
4037static const char* kWithExtensionSource2 =
4038 "(function() {"
4039 " var x = 42;"
4040 " function e() {"
4041 " with ({x:87}) { return x; }"
4042 " }"
4043 " this.UseWith2 = e;"
4044 "})()";
4045
4046
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004047THREADED_TEST(UseWithFromExtension) {
4048 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004049 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4050 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4051 const char* extension_names[] = { "withtest1", "withtest2" };
4052 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004053 v8::Handle<Context> context = Context::New(&extensions);
4054 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004055 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4056 CHECK_EQ(result, v8::Integer::New(87));
4057 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004058 CHECK_EQ(result, v8::Integer::New(87));
4059}
4060
4061
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004062THREADED_TEST(AutoExtensions) {
4063 v8::HandleScope handle_scope;
4064 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4065 extension->set_auto_enable(true);
4066 v8::RegisterExtension(extension);
4067 v8::Handle<Context> context = Context::New();
4068 Context::Scope lock(context);
4069 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4070 CHECK_EQ(result, v8::Integer::New(4));
4071}
4072
4073
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004074static const char* kSyntaxErrorInExtensionSource =
4075 "[";
4076
4077
4078// Test that a syntax error in an extension does not cause a fatal
4079// error but results in an empty context.
4080THREADED_TEST(SyntaxErrorExtensions) {
4081 v8::HandleScope handle_scope;
4082 v8::RegisterExtension(new Extension("syntaxerror",
4083 kSyntaxErrorInExtensionSource));
4084 const char* extension_names[] = { "syntaxerror" };
4085 v8::ExtensionConfiguration extensions(1, extension_names);
4086 v8::Handle<Context> context = Context::New(&extensions);
4087 CHECK(context.IsEmpty());
4088}
4089
4090
4091static const char* kExceptionInExtensionSource =
4092 "throw 42";
4093
4094
4095// Test that an exception when installing an extension does not cause
4096// a fatal error but results in an empty context.
4097THREADED_TEST(ExceptionExtensions) {
4098 v8::HandleScope handle_scope;
4099 v8::RegisterExtension(new Extension("exception",
4100 kExceptionInExtensionSource));
4101 const char* extension_names[] = { "exception" };
4102 v8::ExtensionConfiguration extensions(1, extension_names);
4103 v8::Handle<Context> context = Context::New(&extensions);
4104 CHECK(context.IsEmpty());
4105}
4106
4107
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004108static const char* kNativeCallInExtensionSource =
4109 "function call_runtime_last_index_of(x) {"
4110 " return %StringLastIndexOf(x, 'bob', 10);"
4111 "}";
4112
4113
4114static const char* kNativeCallTest =
4115 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4116
4117// Test that a native runtime calls are supported in extensions.
4118THREADED_TEST(NativeCallInExtensions) {
4119 v8::HandleScope handle_scope;
4120 v8::RegisterExtension(new Extension("nativecall",
4121 kNativeCallInExtensionSource));
4122 const char* extension_names[] = { "nativecall" };
4123 v8::ExtensionConfiguration extensions(1, extension_names);
4124 v8::Handle<Context> context = Context::New(&extensions);
4125 Context::Scope lock(context);
4126 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4127 CHECK_EQ(result, v8::Integer::New(3));
4128}
4129
4130
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004131static void CheckDependencies(const char* name, const char* expected) {
4132 v8::HandleScope handle_scope;
4133 v8::ExtensionConfiguration config(1, &name);
4134 LocalContext context(&config);
4135 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4136}
4137
4138
4139/*
4140 * Configuration:
4141 *
4142 * /-- B <--\
4143 * A <- -- D <-- E
4144 * \-- C <--/
4145 */
4146THREADED_TEST(ExtensionDependency) {
4147 static const char* kEDeps[] = { "D" };
4148 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4149 static const char* kDDeps[] = { "B", "C" };
4150 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4151 static const char* kBCDeps[] = { "A" };
4152 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4153 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4154 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4155 CheckDependencies("A", "undefinedA");
4156 CheckDependencies("B", "undefinedAB");
4157 CheckDependencies("C", "undefinedAC");
4158 CheckDependencies("D", "undefinedABCD");
4159 CheckDependencies("E", "undefinedABCDE");
4160 v8::HandleScope handle_scope;
4161 static const char* exts[2] = { "C", "E" };
4162 v8::ExtensionConfiguration config(2, exts);
4163 LocalContext context(&config);
4164 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4165}
4166
4167
4168static const char* kExtensionTestScript =
4169 "native function A();"
4170 "native function B();"
4171 "native function C();"
4172 "function Foo(i) {"
4173 " if (i == 0) return A();"
4174 " if (i == 1) return B();"
4175 " if (i == 2) return C();"
4176 "}";
4177
4178
4179static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4180 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004181 if (args.IsConstructCall()) {
4182 args.This()->Set(v8_str("data"), args.Data());
4183 return v8::Null();
4184 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004185 return args.Data();
4186}
4187
4188
4189class FunctionExtension : public Extension {
4190 public:
4191 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4192 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4193 v8::Handle<String> name);
4194};
4195
4196
4197static int lookup_count = 0;
4198v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4199 v8::Handle<String> name) {
4200 lookup_count++;
4201 if (name->Equals(v8_str("A"))) {
4202 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4203 } else if (name->Equals(v8_str("B"))) {
4204 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4205 } else if (name->Equals(v8_str("C"))) {
4206 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4207 } else {
4208 return v8::Handle<v8::FunctionTemplate>();
4209 }
4210}
4211
4212
4213THREADED_TEST(FunctionLookup) {
4214 v8::RegisterExtension(new FunctionExtension());
4215 v8::HandleScope handle_scope;
4216 static const char* exts[1] = { "functiontest" };
4217 v8::ExtensionConfiguration config(1, exts);
4218 LocalContext context(&config);
4219 CHECK_EQ(3, lookup_count);
4220 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4221 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4222 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4223}
4224
4225
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004226THREADED_TEST(NativeFunctionConstructCall) {
4227 v8::RegisterExtension(new FunctionExtension());
4228 v8::HandleScope handle_scope;
4229 static const char* exts[1] = { "functiontest" };
4230 v8::ExtensionConfiguration config(1, exts);
4231 LocalContext context(&config);
4232 for (int i = 0; i < 10; i++) {
4233 // Run a few times to ensure that allocation of objects doesn't
4234 // change behavior of a constructor function.
4235 CHECK_EQ(v8::Integer::New(8),
4236 Script::Compile(v8_str("(new A()).data"))->Run());
4237 CHECK_EQ(v8::Integer::New(7),
4238 Script::Compile(v8_str("(new B()).data"))->Run());
4239 CHECK_EQ(v8::Integer::New(6),
4240 Script::Compile(v8_str("(new C()).data"))->Run());
4241 }
4242}
4243
4244
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004245static const char* last_location;
4246static const char* last_message;
4247void StoringErrorCallback(const char* location, const char* message) {
4248 if (last_location == NULL) {
4249 last_location = location;
4250 last_message = message;
4251 }
4252}
4253
4254
4255// ErrorReporting creates a circular extensions configuration and
4256// tests that the fatal error handler gets called. This renders V8
4257// unusable and therefore this test cannot be run in parallel.
4258TEST(ErrorReporting) {
4259 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4260 static const char* aDeps[] = { "B" };
4261 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4262 static const char* bDeps[] = { "A" };
4263 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4264 last_location = NULL;
4265 v8::ExtensionConfiguration config(1, bDeps);
4266 v8::Handle<Context> context = Context::New(&config);
4267 CHECK(context.IsEmpty());
4268 CHECK_NE(last_location, NULL);
4269}
4270
4271
ager@chromium.org7c537e22008-10-16 08:43:32 +00004272static const char* js_code_causing_huge_string_flattening =
4273 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004274 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004275 " str = str + str;"
4276 "}"
4277 "str.match(/X/);";
4278
4279
4280void OOMCallback(const char* location, const char* message) {
4281 exit(0);
4282}
4283
4284
4285TEST(RegexpOutOfMemory) {
4286 // Execute a script that causes out of memory when flattening a string.
4287 v8::HandleScope scope;
4288 v8::V8::SetFatalErrorHandler(OOMCallback);
4289 LocalContext context;
4290 Local<Script> script =
4291 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4292 last_location = NULL;
4293 Local<Value> result = script->Run();
4294
4295 CHECK(false); // Should not return.
4296}
4297
4298
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004299static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4300 v8::Handle<Value> data) {
4301 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004302 CHECK(message->GetScriptResourceName()->IsUndefined());
4303 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004304 message->GetLineNumber();
4305 message->GetSourceLine();
4306}
4307
4308
4309THREADED_TEST(ErrorWithMissingScriptInfo) {
4310 v8::HandleScope scope;
4311 LocalContext context;
4312 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4313 Script::Compile(v8_str("throw Error()"))->Run();
4314 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4315}
4316
4317
4318int global_index = 0;
4319
4320class Snorkel {
4321 public:
4322 Snorkel() { index_ = global_index++; }
4323 int index_;
4324};
4325
4326class Whammy {
4327 public:
4328 Whammy() {
4329 cursor_ = 0;
4330 }
4331 ~Whammy() {
4332 script_.Dispose();
4333 }
4334 v8::Handle<Script> getScript() {
4335 if (script_.IsEmpty())
4336 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4337 return Local<Script>(*script_);
4338 }
4339
4340 public:
4341 static const int kObjectCount = 256;
4342 int cursor_;
4343 v8::Persistent<v8::Object> objects_[kObjectCount];
4344 v8::Persistent<Script> script_;
4345};
4346
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004347static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004348 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4349 delete snorkel;
4350 obj.ClearWeak();
4351}
4352
4353v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4354 const AccessorInfo& info) {
4355 Whammy* whammy =
4356 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4357
4358 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4359
4360 v8::Handle<v8::Object> obj = v8::Object::New();
4361 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4362 if (!prev.IsEmpty()) {
4363 prev->Set(v8_str("next"), obj);
4364 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4365 whammy->objects_[whammy->cursor_].Clear();
4366 }
4367 whammy->objects_[whammy->cursor_] = global;
4368 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4369 return whammy->getScript()->Run();
4370}
4371
4372THREADED_TEST(WeakReference) {
4373 v8::HandleScope handle_scope;
4374 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004375 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004376 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4377 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004378 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004379 const char* extension_list[] = { "v8/gc" };
4380 v8::ExtensionConfiguration extensions(1, extension_list);
4381 v8::Persistent<Context> context = Context::New(&extensions);
4382 Context::Scope context_scope(context);
4383
4384 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4385 context->Global()->Set(v8_str("whammy"), interceptor);
4386 const char* code =
4387 "var last;"
4388 "for (var i = 0; i < 10000; i++) {"
4389 " var obj = whammy.length;"
4390 " if (last) last.next = obj;"
4391 " last = obj;"
4392 "}"
4393 "gc();"
4394 "4";
4395 v8::Handle<Value> result = CompileRun(code);
4396 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004397 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004398 context.Dispose();
4399}
4400
4401
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004402static bool in_scavenge = false;
4403static int last = -1;
4404
4405static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4406 CHECK_EQ(-1, last);
4407 last = 0;
4408 obj.Dispose();
4409 obj.Clear();
4410 in_scavenge = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004411 HEAP->PerformScavenge();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004412 in_scavenge = false;
4413 *(reinterpret_cast<bool*>(data)) = true;
4414}
4415
4416static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4417 void* data) {
4418 CHECK_EQ(0, last);
4419 last = 1;
4420 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4421 obj.Dispose();
4422 obj.Clear();
4423}
4424
4425THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4426 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4427 // Calling callbacks from scavenges is unsafe as objects held by those
4428 // handlers might have become strongly reachable, but scavenge doesn't
4429 // check that.
4430 v8::Persistent<Context> context = Context::New();
4431 Context::Scope context_scope(context);
4432
4433 v8::Persistent<v8::Object> object_a;
4434 v8::Persistent<v8::Object> object_b;
4435
4436 {
4437 v8::HandleScope handle_scope;
4438 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4439 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4440 }
4441
4442 bool object_a_disposed = false;
4443 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4444 bool released_in_scavenge = false;
4445 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4446
4447 while (!object_a_disposed) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004449 }
4450 CHECK(!released_in_scavenge);
4451}
4452
4453
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004454v8::Handle<Function> args_fun;
4455
4456
4457static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4458 ApiTestFuzzer::Fuzz();
4459 CHECK_EQ(args_fun, args.Callee());
4460 CHECK_EQ(3, args.Length());
4461 CHECK_EQ(v8::Integer::New(1), args[0]);
4462 CHECK_EQ(v8::Integer::New(2), args[1]);
4463 CHECK_EQ(v8::Integer::New(3), args[2]);
4464 CHECK_EQ(v8::Undefined(), args[3]);
4465 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004466 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004467 return v8::Undefined();
4468}
4469
4470
4471THREADED_TEST(Arguments) {
4472 v8::HandleScope scope;
4473 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4474 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4475 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004476 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004477 v8_compile("f(1, 2, 3)")->Run();
4478}
4479
4480
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4482 const AccessorInfo&) {
4483 return v8::Handle<Value>();
4484}
4485
4486
4487static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4488 const AccessorInfo&) {
4489 return v8::Handle<Value>();
4490}
4491
4492
4493static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4494 const AccessorInfo&) {
4495 if (!name->Equals(v8_str("foo"))) {
4496 return v8::Handle<v8::Boolean>(); // not intercepted
4497 }
4498
4499 return v8::False(); // intercepted, and don't delete the property
4500}
4501
4502
4503static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4504 if (index != 2) {
4505 return v8::Handle<v8::Boolean>(); // not intercepted
4506 }
4507
4508 return v8::False(); // intercepted, and don't delete the property
4509}
4510
4511
4512THREADED_TEST(Deleter) {
4513 v8::HandleScope scope;
4514 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4515 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4516 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4517 LocalContext context;
4518 context->Global()->Set(v8_str("k"), obj->NewInstance());
4519 CompileRun(
4520 "k.foo = 'foo';"
4521 "k.bar = 'bar';"
4522 "k[2] = 2;"
4523 "k[4] = 4;");
4524 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4525 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4526
4527 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4528 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4529
4530 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4531 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4532
4533 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4534 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4535}
4536
4537
4538static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4539 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004540 if (name->Equals(v8_str("foo")) ||
4541 name->Equals(v8_str("bar")) ||
4542 name->Equals(v8_str("baz"))) {
4543 return v8::Undefined();
4544 }
4545 return v8::Handle<Value>();
4546}
4547
4548
4549static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4550 ApiTestFuzzer::Fuzz();
4551 if (index == 0 || index == 1) return v8::Undefined();
4552 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004553}
4554
4555
4556static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4557 ApiTestFuzzer::Fuzz();
4558 v8::Handle<v8::Array> result = v8::Array::New(3);
4559 result->Set(v8::Integer::New(0), v8_str("foo"));
4560 result->Set(v8::Integer::New(1), v8_str("bar"));
4561 result->Set(v8::Integer::New(2), v8_str("baz"));
4562 return result;
4563}
4564
4565
4566static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4567 ApiTestFuzzer::Fuzz();
4568 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004569 result->Set(v8::Integer::New(0), v8_str("0"));
4570 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004571 return result;
4572}
4573
4574
4575THREADED_TEST(Enumerators) {
4576 v8::HandleScope scope;
4577 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4578 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004579 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004580 LocalContext context;
4581 context->Global()->Set(v8_str("k"), obj->NewInstance());
4582 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004583 "k[10] = 0;"
4584 "k.a = 0;"
4585 "k[5] = 0;"
4586 "k.b = 0;"
4587 "k[4294967295] = 0;"
4588 "k.c = 0;"
4589 "k[4294967296] = 0;"
4590 "k.d = 0;"
4591 "k[140000] = 0;"
4592 "k.e = 0;"
4593 "k[30000000000] = 0;"
4594 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004595 "var result = [];"
4596 "for (var prop in k) {"
4597 " result.push(prop);"
4598 "}"
4599 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004600 // Check that we get all the property names returned including the
4601 // ones from the enumerators in the right order: indexed properties
4602 // in numerical order, indexed interceptor properties, named
4603 // properties in insertion order, named interceptor properties.
4604 // This order is not mandated by the spec, so this test is just
4605 // documenting our behavior.
4606 CHECK_EQ(17, result->Length());
4607 // Indexed properties in numerical order.
4608 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4609 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4610 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4611 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4612 // Indexed interceptor properties in the order they are returned
4613 // from the enumerator interceptor.
4614 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4615 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4616 // Named properties in insertion order.
4617 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4618 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4619 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4620 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4621 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4622 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4623 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4624 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4625 // Named interceptor properties.
4626 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4627 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4628 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004629}
4630
4631
4632int p_getter_count;
4633int p_getter_count2;
4634
4635
4636static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4637 ApiTestFuzzer::Fuzz();
4638 p_getter_count++;
4639 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4640 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4641 if (name->Equals(v8_str("p1"))) {
4642 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4643 } else if (name->Equals(v8_str("p2"))) {
4644 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4645 } else if (name->Equals(v8_str("p3"))) {
4646 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4647 } else if (name->Equals(v8_str("p4"))) {
4648 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4649 }
4650 return v8::Undefined();
4651}
4652
4653
4654static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4655 ApiTestFuzzer::Fuzz();
4656 LocalContext context;
4657 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4658 CompileRun(
4659 "o1.__proto__ = { };"
4660 "var o2 = { __proto__: o1 };"
4661 "var o3 = { __proto__: o2 };"
4662 "var o4 = { __proto__: o3 };"
4663 "for (var i = 0; i < 10; i++) o4.p4;"
4664 "for (var i = 0; i < 10; i++) o3.p3;"
4665 "for (var i = 0; i < 10; i++) o2.p2;"
4666 "for (var i = 0; i < 10; i++) o1.p1;");
4667}
4668
4669
4670static v8::Handle<Value> PGetter2(Local<String> name,
4671 const AccessorInfo& info) {
4672 ApiTestFuzzer::Fuzz();
4673 p_getter_count2++;
4674 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4675 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4676 if (name->Equals(v8_str("p1"))) {
4677 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4678 } else if (name->Equals(v8_str("p2"))) {
4679 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4680 } else if (name->Equals(v8_str("p3"))) {
4681 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4682 } else if (name->Equals(v8_str("p4"))) {
4683 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4684 }
4685 return v8::Undefined();
4686}
4687
4688
4689THREADED_TEST(GetterHolders) {
4690 v8::HandleScope scope;
4691 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4692 obj->SetAccessor(v8_str("p1"), PGetter);
4693 obj->SetAccessor(v8_str("p2"), PGetter);
4694 obj->SetAccessor(v8_str("p3"), PGetter);
4695 obj->SetAccessor(v8_str("p4"), PGetter);
4696 p_getter_count = 0;
4697 RunHolderTest(obj);
4698 CHECK_EQ(40, p_getter_count);
4699}
4700
4701
4702THREADED_TEST(PreInterceptorHolders) {
4703 v8::HandleScope scope;
4704 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4705 obj->SetNamedPropertyHandler(PGetter2);
4706 p_getter_count2 = 0;
4707 RunHolderTest(obj);
4708 CHECK_EQ(40, p_getter_count2);
4709}
4710
4711
4712THREADED_TEST(ObjectInstantiation) {
4713 v8::HandleScope scope;
4714 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4715 templ->SetAccessor(v8_str("t"), PGetter2);
4716 LocalContext context;
4717 context->Global()->Set(v8_str("o"), templ->NewInstance());
4718 for (int i = 0; i < 100; i++) {
4719 v8::HandleScope inner_scope;
4720 v8::Handle<v8::Object> obj = templ->NewInstance();
4721 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4722 context->Global()->Set(v8_str("o2"), obj);
4723 v8::Handle<Value> value =
4724 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4725 CHECK_EQ(v8::True(), value);
4726 context->Global()->Set(v8_str("o"), obj);
4727 }
4728}
4729
4730
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004731static int StrCmp16(uint16_t* a, uint16_t* b) {
4732 while (true) {
4733 if (*a == 0 && *b == 0) return 0;
4734 if (*a != *b) return 0 + *a - *b;
4735 a++;
4736 b++;
4737 }
4738}
4739
4740
4741static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4742 while (true) {
4743 if (n-- == 0) return 0;
4744 if (*a == 0 && *b == 0) return 0;
4745 if (*a != *b) return 0 + *a - *b;
4746 a++;
4747 b++;
4748 }
4749}
4750
4751
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004752THREADED_TEST(StringWrite) {
4753 v8::HandleScope scope;
4754 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004755 // abc<Icelandic eth><Unicode snowman>.
4756 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4757
4758 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004759
4760 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004761 char utf8buf[100];
4762 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004763 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004764 int charlen;
4765
4766 memset(utf8buf, 0x1, sizeof(utf8buf));
4767 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004768 CHECK_EQ(9, len);
4769 CHECK_EQ(5, charlen);
4770 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004771
4772 memset(utf8buf, 0x1, sizeof(utf8buf));
4773 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004774 CHECK_EQ(8, len);
4775 CHECK_EQ(5, charlen);
4776 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004777
4778 memset(utf8buf, 0x1, sizeof(utf8buf));
4779 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004780 CHECK_EQ(5, len);
4781 CHECK_EQ(4, charlen);
4782 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004783
4784 memset(utf8buf, 0x1, sizeof(utf8buf));
4785 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004786 CHECK_EQ(5, len);
4787 CHECK_EQ(4, charlen);
4788 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004789
4790 memset(utf8buf, 0x1, sizeof(utf8buf));
4791 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004792 CHECK_EQ(5, len);
4793 CHECK_EQ(4, charlen);
4794 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004795
4796 memset(utf8buf, 0x1, sizeof(utf8buf));
4797 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004798 CHECK_EQ(3, len);
4799 CHECK_EQ(3, charlen);
4800 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004801
4802 memset(utf8buf, 0x1, sizeof(utf8buf));
4803 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004804 CHECK_EQ(3, len);
4805 CHECK_EQ(3, charlen);
4806 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004807
4808 memset(utf8buf, 0x1, sizeof(utf8buf));
4809 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004810 CHECK_EQ(2, len);
4811 CHECK_EQ(2, charlen);
4812 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004813
4814 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004815 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004816 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004817 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004818 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004819 CHECK_EQ(5, len);
4820 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004821 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004822 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004823
4824 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004825 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004826 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004827 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004828 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004829 CHECK_EQ(4, len);
4830 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004831 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004832 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004833
4834 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004835 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004836 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004837 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004838 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004839 CHECK_EQ(5, len);
4840 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004841 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004842 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004843
4844 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004845 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004846 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004847 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004848 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004849 CHECK_EQ(5, len);
4850 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004851 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004852 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004853
4854 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004855 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004856 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004857 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004858 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004859 CHECK_EQ(1, len);
4860 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004861 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004862 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004863
4864 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004865 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004866 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004867 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004868 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004869 CHECK_EQ(1, len);
4870 CHECK_EQ(0, strcmp("e", buf));
4871 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004872
4873 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004874 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004875 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004876 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004877 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004878 CHECK_EQ(1, len);
4879 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004880 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004881 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004882
4883 memset(buf, 0x1, sizeof(buf));
4884 memset(wbuf, 0x1, sizeof(wbuf));
4885 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004886 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004887 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004888 CHECK_EQ(1, len);
4889 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004890 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004891 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004892}
4893
4894
4895THREADED_TEST(ToArrayIndex) {
4896 v8::HandleScope scope;
4897 LocalContext context;
4898
4899 v8::Handle<String> str = v8_str("42");
4900 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4901 CHECK(!index.IsEmpty());
4902 CHECK_EQ(42.0, index->Uint32Value());
4903 str = v8_str("42asdf");
4904 index = str->ToArrayIndex();
4905 CHECK(index.IsEmpty());
4906 str = v8_str("-42");
4907 index = str->ToArrayIndex();
4908 CHECK(index.IsEmpty());
4909 str = v8_str("4294967295");
4910 index = str->ToArrayIndex();
4911 CHECK(!index.IsEmpty());
4912 CHECK_EQ(4294967295.0, index->Uint32Value());
4913 v8::Handle<v8::Number> num = v8::Number::New(1);
4914 index = num->ToArrayIndex();
4915 CHECK(!index.IsEmpty());
4916 CHECK_EQ(1.0, index->Uint32Value());
4917 num = v8::Number::New(-1);
4918 index = num->ToArrayIndex();
4919 CHECK(index.IsEmpty());
4920 v8::Handle<v8::Object> obj = v8::Object::New();
4921 index = obj->ToArrayIndex();
4922 CHECK(index.IsEmpty());
4923}
4924
4925
4926THREADED_TEST(ErrorConstruction) {
4927 v8::HandleScope scope;
4928 LocalContext context;
4929
4930 v8::Handle<String> foo = v8_str("foo");
4931 v8::Handle<String> message = v8_str("message");
4932 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4933 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004934 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4935 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004936 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4937 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004938 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004939 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4940 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004941 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004942 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4943 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004944 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004945 v8::Handle<Value> error = v8::Exception::Error(foo);
4946 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004947 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004948}
4949
4950
4951static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4952 ApiTestFuzzer::Fuzz();
4953 return v8_num(10);
4954}
4955
4956
4957static void YSetter(Local<String> name,
4958 Local<Value> value,
4959 const AccessorInfo& info) {
4960 if (info.This()->Has(name)) {
4961 info.This()->Delete(name);
4962 }
4963 info.This()->Set(name, value);
4964}
4965
4966
4967THREADED_TEST(DeleteAccessor) {
4968 v8::HandleScope scope;
4969 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4970 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4971 LocalContext context;
4972 v8::Handle<v8::Object> holder = obj->NewInstance();
4973 context->Global()->Set(v8_str("holder"), holder);
4974 v8::Handle<Value> result = CompileRun(
4975 "holder.y = 11; holder.y = 12; holder.y");
4976 CHECK_EQ(12, result->Uint32Value());
4977}
4978
4979
4980THREADED_TEST(TypeSwitch) {
4981 v8::HandleScope scope;
4982 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4983 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4984 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4985 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4986 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4987 LocalContext context;
4988 v8::Handle<v8::Object> obj0 = v8::Object::New();
4989 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4990 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4991 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4992 for (int i = 0; i < 10; i++) {
4993 CHECK_EQ(0, type_switch->match(obj0));
4994 CHECK_EQ(1, type_switch->match(obj1));
4995 CHECK_EQ(2, type_switch->match(obj2));
4996 CHECK_EQ(3, type_switch->match(obj3));
4997 CHECK_EQ(3, type_switch->match(obj3));
4998 CHECK_EQ(2, type_switch->match(obj2));
4999 CHECK_EQ(1, type_switch->match(obj1));
5000 CHECK_EQ(0, type_switch->match(obj0));
5001 }
5002}
5003
5004
5005// For use within the TestSecurityHandler() test.
5006static bool g_security_callback_result = false;
5007static bool NamedSecurityTestCallback(Local<v8::Object> global,
5008 Local<Value> name,
5009 v8::AccessType type,
5010 Local<Value> data) {
5011 // Always allow read access.
5012 if (type == v8::ACCESS_GET)
5013 return true;
5014
5015 // Sometimes allow other access.
5016 return g_security_callback_result;
5017}
5018
5019
5020static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5021 uint32_t key,
5022 v8::AccessType type,
5023 Local<Value> data) {
5024 // Always allow read access.
5025 if (type == v8::ACCESS_GET)
5026 return true;
5027
5028 // Sometimes allow other access.
5029 return g_security_callback_result;
5030}
5031
5032
5033static int trouble_nesting = 0;
5034static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5035 ApiTestFuzzer::Fuzz();
5036 trouble_nesting++;
5037
5038 // Call a JS function that throws an uncaught exception.
5039 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5040 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5041 arg_this->Get(v8_str("trouble_callee")) :
5042 arg_this->Get(v8_str("trouble_caller"));
5043 CHECK(trouble_callee->IsFunction());
5044 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5045}
5046
5047
5048static int report_count = 0;
5049static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5050 v8::Handle<Value>) {
5051 report_count++;
5052}
5053
5054
5055// Counts uncaught exceptions, but other tests running in parallel
5056// also have uncaught exceptions.
5057TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005058 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005059 v8::HandleScope scope;
5060 LocalContext env;
5061 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5062
5063 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5064 v8::Local<v8::Object> global = env->Global();
5065 global->Set(v8_str("trouble"), fun->GetFunction());
5066
5067 Script::Compile(v8_str("function trouble_callee() {"
5068 " var x = null;"
5069 " return x.foo;"
5070 "};"
5071 "function trouble_caller() {"
5072 " trouble();"
5073 "};"))->Run();
5074 Local<Value> trouble = global->Get(v8_str("trouble"));
5075 CHECK(trouble->IsFunction());
5076 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5077 CHECK(trouble_callee->IsFunction());
5078 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5079 CHECK(trouble_caller->IsFunction());
5080 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5081 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005082 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5083}
5084
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005085static const char* script_resource_name = "ExceptionInNativeScript.js";
5086static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5087 v8::Handle<Value>) {
5088 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5089 CHECK(!name_val.IsEmpty() && name_val->IsString());
5090 v8::String::AsciiValue name(message->GetScriptResourceName());
5091 CHECK_EQ(script_resource_name, *name);
5092 CHECK_EQ(3, message->GetLineNumber());
5093 v8::String::AsciiValue source_line(message->GetSourceLine());
5094 CHECK_EQ(" new o.foo();", *source_line);
5095}
5096
5097TEST(ExceptionInNativeScript) {
5098 v8::HandleScope scope;
5099 LocalContext env;
5100 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5101
5102 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5103 v8::Local<v8::Object> global = env->Global();
5104 global->Set(v8_str("trouble"), fun->GetFunction());
5105
5106 Script::Compile(v8_str("function trouble() {\n"
5107 " var o = {};\n"
5108 " new o.foo();\n"
5109 "};"), v8::String::New(script_resource_name))->Run();
5110 Local<Value> trouble = global->Get(v8_str("trouble"));
5111 CHECK(trouble->IsFunction());
5112 Function::Cast(*trouble)->Call(global, 0, NULL);
5113 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5114}
5115
ager@chromium.org8bb60582008-12-11 12:02:20 +00005116
5117TEST(CompilationErrorUsingTryCatchHandler) {
5118 v8::HandleScope scope;
5119 LocalContext env;
5120 v8::TryCatch try_catch;
5121 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5122 CHECK_NE(NULL, *try_catch.Exception());
5123 CHECK(try_catch.HasCaught());
5124}
5125
5126
5127TEST(TryCatchFinallyUsingTryCatchHandler) {
5128 v8::HandleScope scope;
5129 LocalContext env;
5130 v8::TryCatch try_catch;
5131 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5132 CHECK(!try_catch.HasCaught());
5133 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5134 CHECK(try_catch.HasCaught());
5135 try_catch.Reset();
5136 Script::Compile(v8_str("(function() {"
5137 "try { throw ''; } finally { return; }"
5138 "})()"))->Run();
5139 CHECK(!try_catch.HasCaught());
5140 Script::Compile(v8_str("(function()"
5141 " { try { throw ''; } finally { throw 0; }"
5142 "})()"))->Run();
5143 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005144}
5145
5146
5147// SecurityHandler can't be run twice
5148TEST(SecurityHandler) {
5149 v8::HandleScope scope0;
5150 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5151 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5152 IndexedSecurityTestCallback);
5153 // Create an environment
5154 v8::Persistent<Context> context0 =
5155 Context::New(NULL, global_template);
5156 context0->Enter();
5157
5158 v8::Handle<v8::Object> global0 = context0->Global();
5159 v8::Handle<Script> script0 = v8_compile("foo = 111");
5160 script0->Run();
5161 global0->Set(v8_str("0"), v8_num(999));
5162 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5163 CHECK_EQ(111, foo0->Int32Value());
5164 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5165 CHECK_EQ(999, z0->Int32Value());
5166
5167 // Create another environment, should fail security checks.
5168 v8::HandleScope scope1;
5169
5170 v8::Persistent<Context> context1 =
5171 Context::New(NULL, global_template);
5172 context1->Enter();
5173
5174 v8::Handle<v8::Object> global1 = context1->Global();
5175 global1->Set(v8_str("othercontext"), global0);
5176 // This set will fail the security check.
5177 v8::Handle<Script> script1 =
5178 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5179 script1->Run();
5180 // This read will pass the security check.
5181 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5182 CHECK_EQ(111, foo1->Int32Value());
5183 // This read will pass the security check.
5184 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5185 CHECK_EQ(999, z1->Int32Value());
5186
5187 // Create another environment, should pass security checks.
5188 { g_security_callback_result = true; // allow security handler to pass.
5189 v8::HandleScope scope2;
5190 LocalContext context2;
5191 v8::Handle<v8::Object> global2 = context2->Global();
5192 global2->Set(v8_str("othercontext"), global0);
5193 v8::Handle<Script> script2 =
5194 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5195 script2->Run();
5196 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5197 CHECK_EQ(333, foo2->Int32Value());
5198 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5199 CHECK_EQ(888, z2->Int32Value());
5200 }
5201
5202 context1->Exit();
5203 context1.Dispose();
5204
5205 context0->Exit();
5206 context0.Dispose();
5207}
5208
5209
5210THREADED_TEST(SecurityChecks) {
5211 v8::HandleScope handle_scope;
5212 LocalContext env1;
5213 v8::Persistent<Context> env2 = Context::New();
5214
5215 Local<Value> foo = v8_str("foo");
5216 Local<Value> bar = v8_str("bar");
5217
5218 // Set to the same domain.
5219 env1->SetSecurityToken(foo);
5220
5221 // Create a function in env1.
5222 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5223 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5224 CHECK(spy->IsFunction());
5225
5226 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005227 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005228 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5229 CHECK(spy2->IsFunction());
5230
5231 // Switch to env2 in the same domain and invoke spy on env2.
5232 {
5233 env2->SetSecurityToken(foo);
5234 // Enter env2
5235 Context::Scope scope_env2(env2);
5236 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5237 CHECK(result->IsFunction());
5238 }
5239
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005240 {
5241 env2->SetSecurityToken(bar);
5242 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005243
5244 // Call cross_domain_call, it should throw an exception
5245 v8::TryCatch try_catch;
5246 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5247 CHECK(try_catch.HasCaught());
5248 }
5249
5250 env2.Dispose();
5251}
5252
5253
5254// Regression test case for issue 1183439.
5255THREADED_TEST(SecurityChecksForPrototypeChain) {
5256 v8::HandleScope scope;
5257 LocalContext current;
5258 v8::Persistent<Context> other = Context::New();
5259
5260 // Change context to be able to get to the Object function in the
5261 // other context without hitting the security checks.
5262 v8::Local<Value> other_object;
5263 { Context::Scope scope(other);
5264 other_object = other->Global()->Get(v8_str("Object"));
5265 other->Global()->Set(v8_num(42), v8_num(87));
5266 }
5267
5268 current->Global()->Set(v8_str("other"), other->Global());
5269 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5270
5271 // Make sure the security check fails here and we get an undefined
5272 // result instead of getting the Object function. Repeat in a loop
5273 // to make sure to exercise the IC code.
5274 v8::Local<Script> access_other0 = v8_compile("other.Object");
5275 v8::Local<Script> access_other1 = v8_compile("other[42]");
5276 for (int i = 0; i < 5; i++) {
5277 CHECK(!access_other0->Run()->Equals(other_object));
5278 CHECK(access_other0->Run()->IsUndefined());
5279 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5280 CHECK(access_other1->Run()->IsUndefined());
5281 }
5282
5283 // Create an object that has 'other' in its prototype chain and make
5284 // sure we cannot access the Object function indirectly through
5285 // that. Repeat in a loop to make sure to exercise the IC code.
5286 v8_compile("function F() { };"
5287 "F.prototype = other;"
5288 "var f = new F();")->Run();
5289 v8::Local<Script> access_f0 = v8_compile("f.Object");
5290 v8::Local<Script> access_f1 = v8_compile("f[42]");
5291 for (int j = 0; j < 5; j++) {
5292 CHECK(!access_f0->Run()->Equals(other_object));
5293 CHECK(access_f0->Run()->IsUndefined());
5294 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5295 CHECK(access_f1->Run()->IsUndefined());
5296 }
5297
5298 // Now it gets hairy: Set the prototype for the other global object
5299 // to be the current global object. The prototype chain for 'f' now
5300 // goes through 'other' but ends up in the current global object.
5301 { Context::Scope scope(other);
5302 other->Global()->Set(v8_str("__proto__"), current->Global());
5303 }
5304 // Set a named and an index property on the current global
5305 // object. To force the lookup to go through the other global object,
5306 // the properties must not exist in the other global object.
5307 current->Global()->Set(v8_str("foo"), v8_num(100));
5308 current->Global()->Set(v8_num(99), v8_num(101));
5309 // Try to read the properties from f and make sure that the access
5310 // gets stopped by the security checks on the other global object.
5311 Local<Script> access_f2 = v8_compile("f.foo");
5312 Local<Script> access_f3 = v8_compile("f[99]");
5313 for (int k = 0; k < 5; k++) {
5314 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5315 CHECK(access_f2->Run()->IsUndefined());
5316 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5317 CHECK(access_f3->Run()->IsUndefined());
5318 }
5319 other.Dispose();
5320}
5321
5322
5323THREADED_TEST(CrossDomainDelete) {
5324 v8::HandleScope handle_scope;
5325 LocalContext env1;
5326 v8::Persistent<Context> env2 = Context::New();
5327
5328 Local<Value> foo = v8_str("foo");
5329 Local<Value> bar = v8_str("bar");
5330
5331 // Set to the same domain.
5332 env1->SetSecurityToken(foo);
5333 env2->SetSecurityToken(foo);
5334
5335 env1->Global()->Set(v8_str("prop"), v8_num(3));
5336 env2->Global()->Set(v8_str("env1"), env1->Global());
5337
5338 // Change env2 to a different domain and delete env1.prop.
5339 env2->SetSecurityToken(bar);
5340 {
5341 Context::Scope scope_env2(env2);
5342 Local<Value> result =
5343 Script::Compile(v8_str("delete env1.prop"))->Run();
5344 CHECK(result->IsFalse());
5345 }
5346
5347 // Check that env1.prop still exists.
5348 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5349 CHECK(v->IsNumber());
5350 CHECK_EQ(3, v->Int32Value());
5351
5352 env2.Dispose();
5353}
5354
5355
ager@chromium.org870a0b62008-11-04 11:43:05 +00005356THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5357 v8::HandleScope handle_scope;
5358 LocalContext env1;
5359 v8::Persistent<Context> env2 = Context::New();
5360
5361 Local<Value> foo = v8_str("foo");
5362 Local<Value> bar = v8_str("bar");
5363
5364 // Set to the same domain.
5365 env1->SetSecurityToken(foo);
5366 env2->SetSecurityToken(foo);
5367
5368 env1->Global()->Set(v8_str("prop"), v8_num(3));
5369 env2->Global()->Set(v8_str("env1"), env1->Global());
5370
5371 // env1.prop is enumerable in env2.
5372 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5373 {
5374 Context::Scope scope_env2(env2);
5375 Local<Value> result = Script::Compile(test)->Run();
5376 CHECK(result->IsTrue());
5377 }
5378
5379 // Change env2 to a different domain and test again.
5380 env2->SetSecurityToken(bar);
5381 {
5382 Context::Scope scope_env2(env2);
5383 Local<Value> result = Script::Compile(test)->Run();
5384 CHECK(result->IsFalse());
5385 }
5386
5387 env2.Dispose();
5388}
5389
5390
ager@chromium.org236ad962008-09-25 09:45:57 +00005391THREADED_TEST(CrossDomainForIn) {
5392 v8::HandleScope handle_scope;
5393 LocalContext env1;
5394 v8::Persistent<Context> env2 = Context::New();
5395
5396 Local<Value> foo = v8_str("foo");
5397 Local<Value> bar = v8_str("bar");
5398
5399 // Set to the same domain.
5400 env1->SetSecurityToken(foo);
5401 env2->SetSecurityToken(foo);
5402
5403 env1->Global()->Set(v8_str("prop"), v8_num(3));
5404 env2->Global()->Set(v8_str("env1"), env1->Global());
5405
5406 // Change env2 to a different domain and set env1's global object
5407 // as the __proto__ of an object in env2 and enumerate properties
5408 // in for-in. It shouldn't enumerate properties on env1's global
5409 // object.
5410 env2->SetSecurityToken(bar);
5411 {
5412 Context::Scope scope_env2(env2);
5413 Local<Value> result =
5414 CompileRun("(function(){var obj = {'__proto__':env1};"
5415 "for (var p in obj)"
5416 " if (p == 'prop') return false;"
5417 "return true;})()");
5418 CHECK(result->IsTrue());
5419 }
5420 env2.Dispose();
5421}
5422
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005423
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005424TEST(ContextDetachGlobal) {
5425 v8::HandleScope handle_scope;
5426 LocalContext env1;
5427 v8::Persistent<Context> env2 = Context::New();
5428
5429 Local<v8::Object> global1 = env1->Global();
5430
5431 Local<Value> foo = v8_str("foo");
5432
5433 // Set to the same domain.
5434 env1->SetSecurityToken(foo);
5435 env2->SetSecurityToken(foo);
5436
5437 // Enter env2
5438 env2->Enter();
5439
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005440 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005441 Local<v8::Object> global2 = env2->Global();
5442 global2->Set(v8_str("prop"), v8::Integer::New(1));
5443 CompileRun("function getProp() {return prop;}");
5444
5445 env1->Global()->Set(v8_str("getProp"),
5446 global2->Get(v8_str("getProp")));
5447
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005448 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005449 env2->Exit();
5450 env2->DetachGlobal();
5451 // env2 has a new global object.
5452 CHECK(!env2->Global()->Equals(global2));
5453
5454 v8::Persistent<Context> env3 =
5455 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5456 env3->SetSecurityToken(v8_str("bar"));
5457 env3->Enter();
5458
5459 Local<v8::Object> global3 = env3->Global();
5460 CHECK_EQ(global2, global3);
5461 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5462 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5463 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5464 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5465 env3->Exit();
5466
5467 // Call getProp in env1, and it should return the value 1
5468 {
5469 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5470 CHECK(get_prop->IsFunction());
5471 v8::TryCatch try_catch;
5472 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5473 CHECK(!try_catch.HasCaught());
5474 CHECK_EQ(1, r->Int32Value());
5475 }
5476
5477 // Check that env3 is not accessible from env1
5478 {
5479 Local<Value> r = global3->Get(v8_str("prop2"));
5480 CHECK(r->IsUndefined());
5481 }
5482
5483 env2.Dispose();
5484 env3.Dispose();
5485}
5486
5487
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005488TEST(DetachAndReattachGlobal) {
5489 v8::HandleScope scope;
5490 LocalContext env1;
5491
5492 // Create second environment.
5493 v8::Persistent<Context> env2 = Context::New();
5494
5495 Local<Value> foo = v8_str("foo");
5496
5497 // Set same security token for env1 and env2.
5498 env1->SetSecurityToken(foo);
5499 env2->SetSecurityToken(foo);
5500
5501 // Create a property on the global object in env2.
5502 {
5503 v8::Context::Scope scope(env2);
5504 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5505 }
5506
5507 // Create a reference to env2 global from env1 global.
5508 env1->Global()->Set(v8_str("other"), env2->Global());
5509
5510 // Check that we have access to other.p in env2 from env1.
5511 Local<Value> result = CompileRun("other.p");
5512 CHECK(result->IsInt32());
5513 CHECK_EQ(42, result->Int32Value());
5514
5515 // Hold on to global from env2 and detach global from env2.
5516 Local<v8::Object> global2 = env2->Global();
5517 env2->DetachGlobal();
5518
5519 // Check that the global has been detached. No other.p property can
5520 // be found.
5521 result = CompileRun("other.p");
5522 CHECK(result->IsUndefined());
5523
5524 // Reuse global2 for env3.
5525 v8::Persistent<Context> env3 =
5526 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5527 CHECK_EQ(global2, env3->Global());
5528
5529 // Start by using the same security token for env3 as for env1 and env2.
5530 env3->SetSecurityToken(foo);
5531
5532 // Create a property on the global object in env3.
5533 {
5534 v8::Context::Scope scope(env3);
5535 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5536 }
5537
5538 // Check that other.p is now the property in env3 and that we have access.
5539 result = CompileRun("other.p");
5540 CHECK(result->IsInt32());
5541 CHECK_EQ(24, result->Int32Value());
5542
5543 // Change security token for env3 to something different from env1 and env2.
5544 env3->SetSecurityToken(v8_str("bar"));
5545
5546 // Check that we do not have access to other.p in env1. |other| is now
5547 // the global object for env3 which has a different security token,
5548 // so access should be blocked.
5549 result = CompileRun("other.p");
5550 CHECK(result->IsUndefined());
5551
5552 // Detach the global for env3 and reattach it to env2.
5553 env3->DetachGlobal();
5554 env2->ReattachGlobal(global2);
5555
5556 // Check that we have access to other.p again in env1. |other| is now
5557 // the global object for env2 which has the same security token as env1.
5558 result = CompileRun("other.p");
5559 CHECK(result->IsInt32());
5560 CHECK_EQ(42, result->Int32Value());
5561
5562 env2.Dispose();
5563 env3.Dispose();
5564}
5565
5566
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005567static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005568static bool NamedAccessBlocker(Local<v8::Object> global,
5569 Local<Value> name,
5570 v8::AccessType type,
5571 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005572 return Context::GetCurrent()->Global()->Equals(global) ||
5573 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005574}
5575
5576
5577static bool IndexedAccessBlocker(Local<v8::Object> global,
5578 uint32_t key,
5579 v8::AccessType type,
5580 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005581 return Context::GetCurrent()->Global()->Equals(global) ||
5582 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005583}
5584
5585
5586static int g_echo_value = -1;
5587static v8::Handle<Value> EchoGetter(Local<String> name,
5588 const AccessorInfo& info) {
5589 return v8_num(g_echo_value);
5590}
5591
5592
5593static void EchoSetter(Local<String> name,
5594 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005595 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005596 if (value->IsNumber())
5597 g_echo_value = value->Int32Value();
5598}
5599
5600
5601static v8::Handle<Value> UnreachableGetter(Local<String> name,
5602 const AccessorInfo& info) {
5603 CHECK(false); // This function should not be called..
5604 return v8::Undefined();
5605}
5606
5607
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005608static void UnreachableSetter(Local<String>, Local<Value>,
5609 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005610 CHECK(false); // This function should nto be called.
5611}
5612
5613
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005614TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005615 v8::HandleScope handle_scope;
5616 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5617
5618 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5619 IndexedAccessBlocker);
5620
5621 // Add an accessor accessible by cross-domain JS code.
5622 global_template->SetAccessor(
5623 v8_str("accessible_prop"),
5624 EchoGetter, EchoSetter,
5625 v8::Handle<Value>(),
5626 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5627
5628 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005629 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005630 UnreachableGetter, UnreachableSetter,
5631 v8::Handle<Value>(),
5632 v8::DEFAULT);
5633
5634 // Create an environment
5635 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5636 context0->Enter();
5637
5638 v8::Handle<v8::Object> global0 = context0->Global();
5639
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005640 // Define a property with JS getter and setter.
5641 CompileRun(
5642 "function getter() { return 'getter'; };\n"
5643 "function setter() { return 'setter'; }\n"
5644 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5645
5646 Local<Value> getter = global0->Get(v8_str("getter"));
5647 Local<Value> setter = global0->Get(v8_str("setter"));
5648
5649 // And define normal element.
5650 global0->Set(239, v8_str("239"));
5651
5652 // Define an element with JS getter and setter.
5653 CompileRun(
5654 "function el_getter() { return 'el_getter'; };\n"
5655 "function el_setter() { return 'el_setter'; };\n"
5656 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5657
5658 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5659 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5660
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005661 v8::HandleScope scope1;
5662
5663 v8::Persistent<Context> context1 = Context::New();
5664 context1->Enter();
5665
5666 v8::Handle<v8::Object> global1 = context1->Global();
5667 global1->Set(v8_str("other"), global0);
5668
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005669 // Access blocked property.
5670 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005671
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005672 ExpectUndefined("other.blocked_prop");
5673 ExpectUndefined(
5674 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5675 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005676
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005677 // Enable ACCESS_HAS
5678 allowed_access_type[v8::ACCESS_HAS] = true;
5679 ExpectUndefined("other.blocked_prop");
5680 // ... and now we can get the descriptor...
5681 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005682 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005683 // ... and enumerate the property.
5684 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
5685 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005686
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005687 // Access blocked element.
5688 CompileRun("other[239] = 1");
5689
5690 ExpectUndefined("other[239]");
5691 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
5692 ExpectFalse("propertyIsEnumerable.call(other, '239')");
5693
5694 // Enable ACCESS_HAS
5695 allowed_access_type[v8::ACCESS_HAS] = true;
5696 ExpectUndefined("other[239]");
5697 // ... and now we can get the descriptor...
5698 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
5699 // ... and enumerate the property.
5700 ExpectTrue("propertyIsEnumerable.call(other, '239')");
5701 allowed_access_type[v8::ACCESS_HAS] = false;
5702
5703 // Access a property with JS accessor.
5704 CompileRun("other.js_accessor_p = 2");
5705
5706 ExpectUndefined("other.js_accessor_p");
5707 ExpectUndefined(
5708 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
5709
5710 // Enable ACCESS_HAS.
5711 allowed_access_type[v8::ACCESS_HAS] = true;
5712 ExpectUndefined("other.js_accessor_p");
5713 ExpectUndefined(
5714 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5715 ExpectUndefined(
5716 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5717 ExpectUndefined(
5718 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5719 allowed_access_type[v8::ACCESS_HAS] = false;
5720
5721 // Enable both ACCESS_HAS and ACCESS_GET.
5722 allowed_access_type[v8::ACCESS_HAS] = true;
5723 allowed_access_type[v8::ACCESS_GET] = true;
5724
5725 ExpectString("other.js_accessor_p", "getter");
5726 ExpectObject(
5727 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5728 ExpectUndefined(
5729 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5730 ExpectUndefined(
5731 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5732
5733 allowed_access_type[v8::ACCESS_GET] = false;
5734 allowed_access_type[v8::ACCESS_HAS] = false;
5735
5736 // Enable both ACCESS_HAS and ACCESS_SET.
5737 allowed_access_type[v8::ACCESS_HAS] = true;
5738 allowed_access_type[v8::ACCESS_SET] = true;
5739
5740 ExpectUndefined("other.js_accessor_p");
5741 ExpectUndefined(
5742 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5743 ExpectObject(
5744 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5745 ExpectUndefined(
5746 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5747
5748 allowed_access_type[v8::ACCESS_SET] = false;
5749 allowed_access_type[v8::ACCESS_HAS] = false;
5750
5751 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5752 allowed_access_type[v8::ACCESS_HAS] = true;
5753 allowed_access_type[v8::ACCESS_GET] = true;
5754 allowed_access_type[v8::ACCESS_SET] = true;
5755
5756 ExpectString("other.js_accessor_p", "getter");
5757 ExpectObject(
5758 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5759 ExpectObject(
5760 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5761 ExpectUndefined(
5762 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5763
5764 allowed_access_type[v8::ACCESS_SET] = false;
5765 allowed_access_type[v8::ACCESS_GET] = false;
5766 allowed_access_type[v8::ACCESS_HAS] = false;
5767
5768 // Access an element with JS accessor.
5769 CompileRun("other[42] = 2");
5770
5771 ExpectUndefined("other[42]");
5772 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
5773
5774 // Enable ACCESS_HAS.
5775 allowed_access_type[v8::ACCESS_HAS] = true;
5776 ExpectUndefined("other[42]");
5777 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5778 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5779 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5780 allowed_access_type[v8::ACCESS_HAS] = false;
5781
5782 // Enable both ACCESS_HAS and ACCESS_GET.
5783 allowed_access_type[v8::ACCESS_HAS] = true;
5784 allowed_access_type[v8::ACCESS_GET] = true;
5785
5786 ExpectString("other[42]", "el_getter");
5787 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5788 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5789 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5790
5791 allowed_access_type[v8::ACCESS_GET] = false;
5792 allowed_access_type[v8::ACCESS_HAS] = false;
5793
5794 // Enable both ACCESS_HAS and ACCESS_SET.
5795 allowed_access_type[v8::ACCESS_HAS] = true;
5796 allowed_access_type[v8::ACCESS_SET] = true;
5797
5798 ExpectUndefined("other[42]");
5799 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5800 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5801 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5802
5803 allowed_access_type[v8::ACCESS_SET] = false;
5804 allowed_access_type[v8::ACCESS_HAS] = false;
5805
5806 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5807 allowed_access_type[v8::ACCESS_HAS] = true;
5808 allowed_access_type[v8::ACCESS_GET] = true;
5809 allowed_access_type[v8::ACCESS_SET] = true;
5810
5811 ExpectString("other[42]", "el_getter");
5812 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5813 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5814 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5815
5816 allowed_access_type[v8::ACCESS_SET] = false;
5817 allowed_access_type[v8::ACCESS_GET] = false;
5818 allowed_access_type[v8::ACCESS_HAS] = false;
5819
5820 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005821
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005822 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005823 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005824 CHECK(value->IsNumber());
5825 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005826 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005827
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005828 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005829 CHECK(value->IsNumber());
5830 CHECK_EQ(3, value->Int32Value());
5831
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005832 value = CompileRun(
5833 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5834 CHECK(value->IsNumber());
5835 CHECK_EQ(3, value->Int32Value());
5836
5837 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00005838 CHECK(value->IsTrue());
5839
5840 // Enumeration doesn't enumerate accessors from inaccessible objects in
5841 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005842 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00005843 CompileRun("(function(){var obj = {'__proto__':other};"
5844 "for (var p in obj)"
5845 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5846 " return false;"
5847 " }"
5848 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005849 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00005850
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005851 context1->Exit();
5852 context0->Exit();
5853 context1.Dispose();
5854 context0.Dispose();
5855}
5856
5857
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005858TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005859 v8::HandleScope handle_scope;
5860 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5861
5862 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5863 IndexedAccessBlocker);
5864
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00005865 // Add accessible accessor.
5866 global_template->SetAccessor(
5867 v8_str("accessible_prop"),
5868 EchoGetter, EchoSetter,
5869 v8::Handle<Value>(),
5870 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5871
5872
ricow@chromium.org65001782011-02-15 13:36:41 +00005873 // Add an accessor that is not accessible by cross-domain JS code.
5874 global_template->SetAccessor(v8_str("blocked_prop"),
5875 UnreachableGetter, UnreachableSetter,
5876 v8::Handle<Value>(),
5877 v8::DEFAULT);
5878
5879 // Create an environment
5880 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5881 context0->Enter();
5882
5883 v8::Handle<v8::Object> global0 = context0->Global();
5884
5885 v8::Persistent<Context> context1 = Context::New();
5886 context1->Enter();
5887 v8::Handle<v8::Object> global1 = context1->Global();
5888 global1->Set(v8_str("other"), global0);
5889
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005890 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00005891 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005892
5893 ExpectUndefined("other.blocked_prop");
5894
5895 // Regression test for issue 1027.
5896 CompileRun("Object.defineProperty(\n"
5897 " other, 'blocked_prop', {configurable: false})");
5898 ExpectUndefined("other.blocked_prop");
5899 ExpectUndefined(
5900 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5901
5902 // Regression test for issue 1171.
5903 ExpectTrue("Object.isExtensible(other)");
5904 CompileRun("Object.preventExtensions(other)");
5905 ExpectTrue("Object.isExtensible(other)");
5906
5907 // Object.seal and Object.freeze.
5908 CompileRun("Object.freeze(other)");
5909 ExpectTrue("Object.isExtensible(other)");
5910
5911 CompileRun("Object.seal(other)");
5912 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00005913
5914 // Regression test for issue 1250.
5915 // Make sure that we can set the accessible accessors value using normal
5916 // assignment.
5917 CompileRun("other.accessible_prop = 42");
5918 CHECK_EQ(42, g_echo_value);
5919
5920 v8::Handle<Value> value;
5921 // We follow Safari in ignoring assignments to host object accessors.
5922 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
5923 value = CompileRun("other.accessible_prop == 42");
5924 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00005925}
5926
5927
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005928static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5929 Local<Value> name,
5930 v8::AccessType type,
5931 Local<Value> data) {
5932 return false;
5933}
5934
5935
5936static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5937 uint32_t key,
5938 v8::AccessType type,
5939 Local<Value> data) {
5940 return false;
5941}
5942
5943
5944THREADED_TEST(AccessControlGetOwnPropertyNames) {
5945 v8::HandleScope handle_scope;
5946 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5947
5948 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5949 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5950 GetOwnPropertyNamesIndexedBlocker);
5951
5952 // Create an environment
5953 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5954 context0->Enter();
5955
5956 v8::Handle<v8::Object> global0 = context0->Global();
5957
5958 v8::HandleScope scope1;
5959
5960 v8::Persistent<Context> context1 = Context::New();
5961 context1->Enter();
5962
5963 v8::Handle<v8::Object> global1 = context1->Global();
5964 global1->Set(v8_str("other"), global0);
5965 global1->Set(v8_str("object"), obj_template->NewInstance());
5966
5967 v8::Handle<Value> value;
5968
5969 // Attempt to get the property names of the other global object and
5970 // of an object that requires access checks. Accessing the other
5971 // global object should be blocked by access checks on the global
5972 // proxy object. Accessing the object that requires access checks
5973 // is blocked by the access checks on the object itself.
5974 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5975 CHECK(value->IsTrue());
5976
5977 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5978 CHECK(value->IsTrue());
5979
5980 context1->Exit();
5981 context0->Exit();
5982 context1.Dispose();
5983 context0.Dispose();
5984}
5985
5986
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00005987static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5988 v8::Handle<v8::Array> result = v8::Array::New(1);
5989 result->Set(0, v8_str("x"));
5990 return result;
5991}
5992
5993
5994THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5995 v8::HandleScope handle_scope;
5996 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5997
5998 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5999 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6000 NamedPropertyEnumerator);
6001
6002 LocalContext context;
6003 v8::Handle<v8::Object> global = context->Global();
6004 global->Set(v8_str("object"), obj_template->NewInstance());
6005
6006 v8::Handle<Value> value =
6007 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6008 CHECK_EQ(v8_str("x"), value);
6009}
6010
6011
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006012static v8::Handle<Value> ConstTenGetter(Local<String> name,
6013 const AccessorInfo& info) {
6014 return v8_num(10);
6015}
6016
6017
6018THREADED_TEST(CrossDomainAccessors) {
6019 v8::HandleScope handle_scope;
6020
6021 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6022
6023 v8::Handle<v8::ObjectTemplate> global_template =
6024 func_template->InstanceTemplate();
6025
6026 v8::Handle<v8::ObjectTemplate> proto_template =
6027 func_template->PrototypeTemplate();
6028
6029 // Add an accessor to proto that's accessible by cross-domain JS code.
6030 proto_template->SetAccessor(v8_str("accessible"),
6031 ConstTenGetter, 0,
6032 v8::Handle<Value>(),
6033 v8::ALL_CAN_READ);
6034
6035 // Add an accessor that is not accessible by cross-domain JS code.
6036 global_template->SetAccessor(v8_str("unreachable"),
6037 UnreachableGetter, 0,
6038 v8::Handle<Value>(),
6039 v8::DEFAULT);
6040
6041 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6042 context0->Enter();
6043
6044 Local<v8::Object> global = context0->Global();
6045 // Add a normal property that shadows 'accessible'
6046 global->Set(v8_str("accessible"), v8_num(11));
6047
6048 // Enter a new context.
6049 v8::HandleScope scope1;
6050 v8::Persistent<Context> context1 = Context::New();
6051 context1->Enter();
6052
6053 v8::Handle<v8::Object> global1 = context1->Global();
6054 global1->Set(v8_str("other"), global);
6055
6056 // Should return 10, instead of 11
6057 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6058 CHECK(value->IsNumber());
6059 CHECK_EQ(10, value->Int32Value());
6060
6061 value = v8_compile("other.unreachable")->Run();
6062 CHECK(value->IsUndefined());
6063
6064 context1->Exit();
6065 context0->Exit();
6066 context1.Dispose();
6067 context0.Dispose();
6068}
6069
6070
6071static int named_access_count = 0;
6072static int indexed_access_count = 0;
6073
6074static bool NamedAccessCounter(Local<v8::Object> global,
6075 Local<Value> name,
6076 v8::AccessType type,
6077 Local<Value> data) {
6078 named_access_count++;
6079 return true;
6080}
6081
6082
6083static bool IndexedAccessCounter(Local<v8::Object> global,
6084 uint32_t key,
6085 v8::AccessType type,
6086 Local<Value> data) {
6087 indexed_access_count++;
6088 return true;
6089}
6090
6091
6092// This one is too easily disturbed by other tests.
6093TEST(AccessControlIC) {
6094 named_access_count = 0;
6095 indexed_access_count = 0;
6096
6097 v8::HandleScope handle_scope;
6098
6099 // Create an environment.
6100 v8::Persistent<Context> context0 = Context::New();
6101 context0->Enter();
6102
6103 // Create an object that requires access-check functions to be
6104 // called for cross-domain access.
6105 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6106 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6107 IndexedAccessCounter);
6108 Local<v8::Object> object = object_template->NewInstance();
6109
6110 v8::HandleScope scope1;
6111
6112 // Create another environment.
6113 v8::Persistent<Context> context1 = Context::New();
6114 context1->Enter();
6115
6116 // Make easy access to the object from the other environment.
6117 v8::Handle<v8::Object> global1 = context1->Global();
6118 global1->Set(v8_str("obj"), object);
6119
6120 v8::Handle<Value> value;
6121
6122 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006123 CompileRun("function testProp(obj) {"
6124 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6125 " for (var j = 0; j < 10; j++) obj.prop;"
6126 " return obj.prop"
6127 "}");
6128 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006129 CHECK(value->IsNumber());
6130 CHECK_EQ(1, value->Int32Value());
6131 CHECK_EQ(21, named_access_count);
6132
6133 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006134 CompileRun("var p = 'prop';"
6135 "function testKeyed(obj) {"
6136 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6137 " for (var j = 0; j < 10; j++) obj[p];"
6138 " return obj[p];"
6139 "}");
6140 // Use obj which requires access checks. No inline caching is used
6141 // in that case.
6142 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006143 CHECK(value->IsNumber());
6144 CHECK_EQ(1, value->Int32Value());
6145 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006146 // Force the inline caches into generic state and try again.
6147 CompileRun("testKeyed({ a: 0 })");
6148 CompileRun("testKeyed({ b: 0 })");
6149 value = CompileRun("testKeyed(obj)");
6150 CHECK(value->IsNumber());
6151 CHECK_EQ(1, value->Int32Value());
6152 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006153
6154 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006155 CompileRun("function testIndexed(obj) {"
6156 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6157 " for (var j = 0; j < 10; j++) obj[0];"
6158 " return obj[0]"
6159 "}");
6160 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006161 CHECK(value->IsNumber());
6162 CHECK_EQ(1, value->Int32Value());
6163 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006164 // Force the inline caches into generic state.
6165 CompileRun("testIndexed(new Array(1))");
6166 // Test that the indexed access check is called.
6167 value = CompileRun("testIndexed(obj)");
6168 CHECK(value->IsNumber());
6169 CHECK_EQ(1, value->Int32Value());
6170 CHECK_EQ(42, indexed_access_count);
6171
6172 // Check that the named access check is called when invoking
6173 // functions on an object that requires access checks.
6174 CompileRun("obj.f = function() {}");
6175 CompileRun("function testCallNormal(obj) {"
6176 " for (var i = 0; i < 10; i++) obj.f();"
6177 "}");
6178 CompileRun("testCallNormal(obj)");
6179 CHECK_EQ(74, named_access_count);
6180
6181 // Force obj into slow case.
6182 value = CompileRun("delete obj.prop");
6183 CHECK(value->BooleanValue());
6184 // Force inline caches into dictionary probing mode.
6185 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6186 // Test that the named access check is called.
6187 value = CompileRun("testProp(obj);");
6188 CHECK(value->IsNumber());
6189 CHECK_EQ(1, value->Int32Value());
6190 CHECK_EQ(96, named_access_count);
6191
6192 // Force the call inline cache into dictionary probing mode.
6193 CompileRun("o.f = function() {}; testCallNormal(o)");
6194 // Test that the named access check is still called for each
6195 // invocation of the function.
6196 value = CompileRun("testCallNormal(obj)");
6197 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006198
6199 context1->Exit();
6200 context0->Exit();
6201 context1.Dispose();
6202 context0.Dispose();
6203}
6204
6205
6206static bool NamedAccessFlatten(Local<v8::Object> global,
6207 Local<Value> name,
6208 v8::AccessType type,
6209 Local<Value> data) {
6210 char buf[100];
6211 int len;
6212
6213 CHECK(name->IsString());
6214
6215 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006217 CHECK_EQ(4, len);
6218
6219 uint16_t buf2[100];
6220
6221 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006222 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006223 CHECK_EQ(4, len);
6224
6225 return true;
6226}
6227
6228
6229static bool IndexedAccessFlatten(Local<v8::Object> global,
6230 uint32_t key,
6231 v8::AccessType type,
6232 Local<Value> data) {
6233 return true;
6234}
6235
6236
6237// Regression test. In access checks, operations that may cause
6238// garbage collection are not allowed. It used to be the case that
6239// using the Write operation on a string could cause a garbage
6240// collection due to flattening of the string. This is no longer the
6241// case.
6242THREADED_TEST(AccessControlFlatten) {
6243 named_access_count = 0;
6244 indexed_access_count = 0;
6245
6246 v8::HandleScope handle_scope;
6247
6248 // Create an environment.
6249 v8::Persistent<Context> context0 = Context::New();
6250 context0->Enter();
6251
6252 // Create an object that requires access-check functions to be
6253 // called for cross-domain access.
6254 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6255 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6256 IndexedAccessFlatten);
6257 Local<v8::Object> object = object_template->NewInstance();
6258
6259 v8::HandleScope scope1;
6260
6261 // Create another environment.
6262 v8::Persistent<Context> context1 = Context::New();
6263 context1->Enter();
6264
6265 // Make easy access to the object from the other environment.
6266 v8::Handle<v8::Object> global1 = context1->Global();
6267 global1->Set(v8_str("obj"), object);
6268
6269 v8::Handle<Value> value;
6270
6271 value = v8_compile("var p = 'as' + 'df';")->Run();
6272 value = v8_compile("obj[p];")->Run();
6273
6274 context1->Exit();
6275 context0->Exit();
6276 context1.Dispose();
6277 context0.Dispose();
6278}
6279
6280
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006281static v8::Handle<Value> AccessControlNamedGetter(
6282 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006283 return v8::Integer::New(42);
6284}
6285
6286
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006287static v8::Handle<Value> AccessControlNamedSetter(
6288 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006289 return value;
6290}
6291
6292
6293static v8::Handle<Value> AccessControlIndexedGetter(
6294 uint32_t index,
6295 const AccessorInfo& info) {
6296 return v8_num(42);
6297}
6298
6299
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006300static v8::Handle<Value> AccessControlIndexedSetter(
6301 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006302 return value;
6303}
6304
6305
6306THREADED_TEST(AccessControlInterceptorIC) {
6307 named_access_count = 0;
6308 indexed_access_count = 0;
6309
6310 v8::HandleScope handle_scope;
6311
6312 // Create an environment.
6313 v8::Persistent<Context> context0 = Context::New();
6314 context0->Enter();
6315
6316 // Create an object that requires access-check functions to be
6317 // called for cross-domain access. The object also has interceptors
6318 // interceptor.
6319 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6320 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6321 IndexedAccessCounter);
6322 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6323 AccessControlNamedSetter);
6324 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6325 AccessControlIndexedSetter);
6326 Local<v8::Object> object = object_template->NewInstance();
6327
6328 v8::HandleScope scope1;
6329
6330 // Create another environment.
6331 v8::Persistent<Context> context1 = Context::New();
6332 context1->Enter();
6333
6334 // Make easy access to the object from the other environment.
6335 v8::Handle<v8::Object> global1 = context1->Global();
6336 global1->Set(v8_str("obj"), object);
6337
6338 v8::Handle<Value> value;
6339
6340 // Check that the named access-control function is called every time
6341 // eventhough there is an interceptor on the object.
6342 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6343 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6344 "obj.x")->Run();
6345 CHECK(value->IsNumber());
6346 CHECK_EQ(42, value->Int32Value());
6347 CHECK_EQ(21, named_access_count);
6348
6349 value = v8_compile("var p = 'x';")->Run();
6350 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6351 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6352 "obj[p]")->Run();
6353 CHECK(value->IsNumber());
6354 CHECK_EQ(42, value->Int32Value());
6355 CHECK_EQ(42, named_access_count);
6356
6357 // Check that the indexed access-control function is called every
6358 // time eventhough there is an interceptor on the object.
6359 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6360 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6361 "obj[0]")->Run();
6362 CHECK(value->IsNumber());
6363 CHECK_EQ(42, value->Int32Value());
6364 CHECK_EQ(21, indexed_access_count);
6365
6366 context1->Exit();
6367 context0->Exit();
6368 context1.Dispose();
6369 context0.Dispose();
6370}
6371
6372
6373THREADED_TEST(Version) {
6374 v8::V8::GetVersion();
6375}
6376
6377
6378static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6379 ApiTestFuzzer::Fuzz();
6380 return v8_num(12);
6381}
6382
6383
6384THREADED_TEST(InstanceProperties) {
6385 v8::HandleScope handle_scope;
6386 LocalContext context;
6387
6388 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6389 Local<ObjectTemplate> instance = t->InstanceTemplate();
6390
6391 instance->Set(v8_str("x"), v8_num(42));
6392 instance->Set(v8_str("f"),
6393 v8::FunctionTemplate::New(InstanceFunctionCallback));
6394
6395 Local<Value> o = t->GetFunction()->NewInstance();
6396
6397 context->Global()->Set(v8_str("i"), o);
6398 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6399 CHECK_EQ(42, value->Int32Value());
6400
6401 value = Script::Compile(v8_str("i.f()"))->Run();
6402 CHECK_EQ(12, value->Int32Value());
6403}
6404
6405
6406static v8::Handle<Value>
6407GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6408 ApiTestFuzzer::Fuzz();
6409 return v8::Handle<Value>();
6410}
6411
6412
6413THREADED_TEST(GlobalObjectInstanceProperties) {
6414 v8::HandleScope handle_scope;
6415
6416 Local<Value> global_object;
6417
6418 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6419 t->InstanceTemplate()->SetNamedPropertyHandler(
6420 GlobalObjectInstancePropertiesGet);
6421 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6422 instance_template->Set(v8_str("x"), v8_num(42));
6423 instance_template->Set(v8_str("f"),
6424 v8::FunctionTemplate::New(InstanceFunctionCallback));
6425
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006426 // The script to check how Crankshaft compiles missing global function
6427 // invocations. function g is not defined and should throw on call.
6428 const char* script =
6429 "function wrapper(call) {"
6430 " var x = 0, y = 1;"
6431 " for (var i = 0; i < 1000; i++) {"
6432 " x += i * 100;"
6433 " y += i * 100;"
6434 " }"
6435 " if (call) g();"
6436 "}"
6437 "for (var i = 0; i < 17; i++) wrapper(false);"
6438 "var thrown = 0;"
6439 "try { wrapper(true); } catch (e) { thrown = 1; };"
6440 "thrown";
6441
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006442 {
6443 LocalContext env(NULL, instance_template);
6444 // Hold on to the global object so it can be used again in another
6445 // environment initialization.
6446 global_object = env->Global();
6447
6448 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6449 CHECK_EQ(42, value->Int32Value());
6450 value = Script::Compile(v8_str("f()"))->Run();
6451 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006452 value = Script::Compile(v8_str(script))->Run();
6453 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006454 }
6455
6456 {
6457 // Create new environment reusing the global object.
6458 LocalContext env(NULL, instance_template, global_object);
6459 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6460 CHECK_EQ(42, value->Int32Value());
6461 value = Script::Compile(v8_str("f()"))->Run();
6462 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006463 value = Script::Compile(v8_str(script))->Run();
6464 CHECK_EQ(1, value->Int32Value());
6465 }
6466}
6467
6468
6469THREADED_TEST(CallKnownGlobalReceiver) {
6470 v8::HandleScope handle_scope;
6471
6472 Local<Value> global_object;
6473
6474 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6475 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6476
6477 // The script to check that we leave global object not
6478 // global object proxy on stack when we deoptimize from inside
6479 // arguments evaluation.
6480 // To provoke error we need to both force deoptimization
6481 // from arguments evaluation and to force CallIC to take
6482 // CallIC_Miss code path that can't cope with global proxy.
6483 const char* script =
6484 "function bar(x, y) { try { } finally { } }"
6485 "function baz(x) { try { } finally { } }"
6486 "function bom(x) { try { } finally { } }"
6487 "function foo(x) { bar([x], bom(2)); }"
6488 "for (var i = 0; i < 10000; i++) foo(1);"
6489 "foo";
6490
6491 Local<Value> foo;
6492 {
6493 LocalContext env(NULL, instance_template);
6494 // Hold on to the global object so it can be used again in another
6495 // environment initialization.
6496 global_object = env->Global();
6497 foo = Script::Compile(v8_str(script))->Run();
6498 }
6499
6500 {
6501 // Create new environment reusing the global object.
6502 LocalContext env(NULL, instance_template, global_object);
6503 env->Global()->Set(v8_str("foo"), foo);
6504 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006505 }
6506}
6507
6508
6509static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6510 ApiTestFuzzer::Fuzz();
6511 return v8_num(42);
6512}
6513
6514
6515static int shadow_y;
6516static int shadow_y_setter_call_count;
6517static int shadow_y_getter_call_count;
6518
6519
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006520static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006521 shadow_y_setter_call_count++;
6522 shadow_y = 42;
6523}
6524
6525
6526static v8::Handle<Value> ShadowYGetter(Local<String> name,
6527 const AccessorInfo& info) {
6528 ApiTestFuzzer::Fuzz();
6529 shadow_y_getter_call_count++;
6530 return v8_num(shadow_y);
6531}
6532
6533
6534static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6535 const AccessorInfo& info) {
6536 return v8::Handle<Value>();
6537}
6538
6539
6540static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6541 const AccessorInfo&) {
6542 return v8::Handle<Value>();
6543}
6544
6545
6546THREADED_TEST(ShadowObject) {
6547 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6548 v8::HandleScope handle_scope;
6549
6550 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6551 LocalContext context(NULL, global_template);
6552
6553 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6554 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6555 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6556 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6557 Local<ObjectTemplate> instance = t->InstanceTemplate();
6558
6559 // Only allow calls of f on instances of t.
6560 Local<v8::Signature> signature = v8::Signature::New(t);
6561 proto->Set(v8_str("f"),
6562 v8::FunctionTemplate::New(ShadowFunctionCallback,
6563 Local<Value>(),
6564 signature));
6565 proto->Set(v8_str("x"), v8_num(12));
6566
6567 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6568
6569 Local<Value> o = t->GetFunction()->NewInstance();
6570 context->Global()->Set(v8_str("__proto__"), o);
6571
6572 Local<Value> value =
6573 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
6574 CHECK(value->IsBoolean());
6575 CHECK(!value->BooleanValue());
6576
6577 value = Script::Compile(v8_str("x"))->Run();
6578 CHECK_EQ(12, value->Int32Value());
6579
6580 value = Script::Compile(v8_str("f()"))->Run();
6581 CHECK_EQ(42, value->Int32Value());
6582
6583 Script::Compile(v8_str("y = 42"))->Run();
6584 CHECK_EQ(1, shadow_y_setter_call_count);
6585 value = Script::Compile(v8_str("y"))->Run();
6586 CHECK_EQ(1, shadow_y_getter_call_count);
6587 CHECK_EQ(42, value->Int32Value());
6588}
6589
6590
6591THREADED_TEST(HiddenPrototype) {
6592 v8::HandleScope handle_scope;
6593 LocalContext context;
6594
6595 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6596 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6597 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6598 t1->SetHiddenPrototype(true);
6599 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6600 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6601 t2->SetHiddenPrototype(true);
6602 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6603 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6604 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6605
6606 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6607 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6608 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6609 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6610
6611 // Setting the prototype on an object skips hidden prototypes.
6612 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6613 o0->Set(v8_str("__proto__"), o1);
6614 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6615 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6616 o0->Set(v8_str("__proto__"), o2);
6617 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6618 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6619 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6620 o0->Set(v8_str("__proto__"), o3);
6621 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6622 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6623 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6624 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6625
6626 // Getting the prototype of o0 should get the first visible one
6627 // which is o3. Therefore, z should not be defined on the prototype
6628 // object.
6629 Local<Value> proto = o0->Get(v8_str("__proto__"));
6630 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006631 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006632}
6633
6634
ager@chromium.org5c838252010-02-19 08:53:10 +00006635THREADED_TEST(SetPrototype) {
6636 v8::HandleScope handle_scope;
6637 LocalContext context;
6638
6639 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6640 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6641 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6642 t1->SetHiddenPrototype(true);
6643 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6644 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6645 t2->SetHiddenPrototype(true);
6646 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6647 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6648 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6649
6650 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6651 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6652 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6653 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6654
6655 // Setting the prototype on an object does not skip hidden prototypes.
6656 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6657 CHECK(o0->SetPrototype(o1));
6658 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6659 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6660 CHECK(o1->SetPrototype(o2));
6661 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6662 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6663 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6664 CHECK(o2->SetPrototype(o3));
6665 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6666 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6667 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6668 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6669
6670 // Getting the prototype of o0 should get the first visible one
6671 // which is o3. Therefore, z should not be defined on the prototype
6672 // object.
6673 Local<Value> proto = o0->Get(v8_str("__proto__"));
6674 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006675 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006676
6677 // However, Object::GetPrototype ignores hidden prototype.
6678 Local<Value> proto0 = o0->GetPrototype();
6679 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006680 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006681
6682 Local<Value> proto1 = o1->GetPrototype();
6683 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006684 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006685
6686 Local<Value> proto2 = o2->GetPrototype();
6687 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006688 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006689}
6690
6691
6692THREADED_TEST(SetPrototypeThrows) {
6693 v8::HandleScope handle_scope;
6694 LocalContext context;
6695
6696 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6697
6698 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6699 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6700
6701 CHECK(o0->SetPrototype(o1));
6702 // If setting the prototype leads to the cycle, SetPrototype should
6703 // return false and keep VM in sane state.
6704 v8::TryCatch try_catch;
6705 CHECK(!o1->SetPrototype(o0));
6706 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00006708
6709 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6710}
6711
6712
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006713THREADED_TEST(GetterSetterExceptions) {
6714 v8::HandleScope handle_scope;
6715 LocalContext context;
6716 CompileRun(
6717 "function Foo() { };"
6718 "function Throw() { throw 5; };"
6719 "var x = { };"
6720 "x.__defineSetter__('set', Throw);"
6721 "x.__defineGetter__('get', Throw);");
6722 Local<v8::Object> x =
6723 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6724 v8::TryCatch try_catch;
6725 x->Set(v8_str("set"), v8::Integer::New(8));
6726 x->Get(v8_str("get"));
6727 x->Set(v8_str("set"), v8::Integer::New(8));
6728 x->Get(v8_str("get"));
6729 x->Set(v8_str("set"), v8::Integer::New(8));
6730 x->Get(v8_str("get"));
6731 x->Set(v8_str("set"), v8::Integer::New(8));
6732 x->Get(v8_str("get"));
6733}
6734
6735
6736THREADED_TEST(Constructor) {
6737 v8::HandleScope handle_scope;
6738 LocalContext context;
6739 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6740 templ->SetClassName(v8_str("Fun"));
6741 Local<Function> cons = templ->GetFunction();
6742 context->Global()->Set(v8_str("Fun"), cons);
6743 Local<v8::Object> inst = cons->NewInstance();
6744 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6745 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6746 CHECK(value->BooleanValue());
6747}
6748
6749THREADED_TEST(FunctionDescriptorException) {
6750 v8::HandleScope handle_scope;
6751 LocalContext context;
6752 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6753 templ->SetClassName(v8_str("Fun"));
6754 Local<Function> cons = templ->GetFunction();
6755 context->Global()->Set(v8_str("Fun"), cons);
6756 Local<Value> value = CompileRun(
6757 "function test() {"
6758 " try {"
6759 " (new Fun()).blah()"
6760 " } catch (e) {"
6761 " var str = String(e);"
6762 " if (str.indexOf('TypeError') == -1) return 1;"
6763 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00006764 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006765 " return 0;"
6766 " }"
6767 " return 4;"
6768 "}"
6769 "test();");
6770 CHECK_EQ(0, value->Int32Value());
6771}
6772
6773
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006774THREADED_TEST(EvalAliasedDynamic) {
6775 v8::HandleScope scope;
6776 LocalContext current;
6777
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006778 // Tests where aliased eval can only be resolved dynamically.
6779 Local<Script> script =
6780 Script::Compile(v8_str("function f(x) { "
6781 " var foo = 2;"
6782 " with (x) { return eval('foo'); }"
6783 "}"
6784 "foo = 0;"
6785 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006786 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006787 "var x = new Object();"
6788 "x.eval = function(x) { return 1; };"
6789 "result3 = f(x);"));
6790 script->Run();
6791 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6792 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6793 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6794
6795 v8::TryCatch try_catch;
6796 script =
6797 Script::Compile(v8_str("function f(x) { "
6798 " var bar = 2;"
6799 " with (x) { return eval('bar'); }"
6800 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00006801 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006802 script->Run();
6803 CHECK(try_catch.HasCaught());
6804 try_catch.Reset();
6805}
6806
6807
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006808THREADED_TEST(CrossEval) {
6809 v8::HandleScope scope;
6810 LocalContext other;
6811 LocalContext current;
6812
6813 Local<String> token = v8_str("<security token>");
6814 other->SetSecurityToken(token);
6815 current->SetSecurityToken(token);
6816
6817 // Setup reference from current to other.
6818 current->Global()->Set(v8_str("other"), other->Global());
6819
6820 // Check that new variables are introduced in other context.
6821 Local<Script> script =
6822 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6823 script->Run();
6824 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6825 CHECK_EQ(1234, foo->Int32Value());
6826 CHECK(!current->Global()->Has(v8_str("foo")));
6827
6828 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006829 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006830 script =
6831 Script::Compile(v8_str("other.eval('na = 1234')"));
6832 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006833 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6834 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006835
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006836 // Check that global variables in current context are not visible in other
6837 // context.
6838 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006839 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006840 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006841 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006842 CHECK(try_catch.HasCaught());
6843 try_catch.Reset();
6844
6845 // Check that local variables in current context are not visible in other
6846 // context.
6847 script =
6848 Script::Compile(v8_str("(function() { "
6849 " var baz = 87;"
6850 " return other.eval('baz');"
6851 "})();"));
6852 result = script->Run();
6853 CHECK(try_catch.HasCaught());
6854 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006855
6856 // Check that global variables in the other environment are visible
6857 // when evaluting code.
6858 other->Global()->Set(v8_str("bis"), v8_num(1234));
6859 script = Script::Compile(v8_str("other.eval('bis')"));
6860 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006861 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006862
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006863 // Check that the 'this' pointer points to the global object evaluating
6864 // code.
6865 other->Global()->Set(v8_str("t"), other->Global());
6866 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006867 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006868 CHECK(result->IsTrue());
6869 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006870
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006871 // Check that variables introduced in with-statement are not visible in
6872 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006873 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006874 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006875 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006876 CHECK(try_catch.HasCaught());
6877 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006878
6879 // Check that you cannot use 'eval.call' with another object than the
6880 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006881 script =
6882 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6883 result = script->Run();
6884 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006885}
6886
6887
ager@chromium.orge2902be2009-06-08 12:21:35 +00006888// Test that calling eval in a context which has been detached from
6889// its global throws an exception. This behavior is consistent with
6890// other JavaScript implementations.
6891THREADED_TEST(EvalInDetachedGlobal) {
6892 v8::HandleScope scope;
6893
6894 v8::Persistent<Context> context0 = Context::New();
6895 v8::Persistent<Context> context1 = Context::New();
6896
6897 // Setup function in context0 that uses eval from context0.
6898 context0->Enter();
6899 v8::Handle<v8::Value> fun =
6900 CompileRun("var x = 42;"
6901 "(function() {"
6902 " var e = eval;"
6903 " return function(s) { return e(s); }"
6904 "})()");
6905 context0->Exit();
6906
6907 // Put the function into context1 and call it before and after
6908 // detaching the global. Before detaching, the call succeeds and
6909 // after detaching and exception is thrown.
6910 context1->Enter();
6911 context1->Global()->Set(v8_str("fun"), fun);
6912 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6913 CHECK_EQ(42, x_value->Int32Value());
6914 context0->DetachGlobal();
6915 v8::TryCatch catcher;
6916 x_value = CompileRun("fun('x')");
6917 CHECK(x_value.IsEmpty());
6918 CHECK(catcher.HasCaught());
6919 context1->Exit();
6920
6921 context1.Dispose();
6922 context0.Dispose();
6923}
6924
6925
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006926THREADED_TEST(CrossLazyLoad) {
6927 v8::HandleScope scope;
6928 LocalContext other;
6929 LocalContext current;
6930
6931 Local<String> token = v8_str("<security token>");
6932 other->SetSecurityToken(token);
6933 current->SetSecurityToken(token);
6934
6935 // Setup reference from current to other.
6936 current->Global()->Set(v8_str("other"), other->Global());
6937
6938 // Trigger lazy loading in other context.
6939 Local<Script> script =
6940 Script::Compile(v8_str("other.eval('new Date(42)')"));
6941 Local<Value> value = script->Run();
6942 CHECK_EQ(42.0, value->NumberValue());
6943}
6944
6945
6946static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
6947 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006948 if (args.IsConstructCall()) {
6949 if (args[0]->IsInt32()) {
6950 return v8_num(-args[0]->Int32Value());
6951 }
6952 }
6953
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006954 return args[0];
6955}
6956
6957
6958// Test that a call handler can be set for objects which will allow
6959// non-function objects created through the API to be called as
6960// functions.
6961THREADED_TEST(CallAsFunction) {
6962 v8::HandleScope scope;
6963 LocalContext context;
6964
6965 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6966 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6967 instance_template->SetCallAsFunctionHandler(call_as_function);
6968 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6969 context->Global()->Set(v8_str("obj"), instance);
6970 v8::TryCatch try_catch;
6971 Local<Value> value;
6972 CHECK(!try_catch.HasCaught());
6973
ager@chromium.org9085a012009-05-11 19:22:57 +00006974 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006975 CHECK(!try_catch.HasCaught());
6976 CHECK_EQ(42, value->Int32Value());
6977
ager@chromium.org9085a012009-05-11 19:22:57 +00006978 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006979 CHECK(!try_catch.HasCaught());
6980 CHECK_EQ(49, value->Int32Value());
6981
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006982 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00006983 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006984 CHECK(!try_catch.HasCaught());
6985 CHECK_EQ(45, value->Int32Value());
6986
ager@chromium.org9085a012009-05-11 19:22:57 +00006987 value = CompileRun("obj.call = Function.prototype.call;"
6988 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006989 CHECK(!try_catch.HasCaught());
6990 CHECK_EQ(87, value->Int32Value());
6991
6992 // Regression tests for bug #1116356: Calling call through call/apply
6993 // must work for non-function receivers.
6994 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00006995 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006996 CHECK(!try_catch.HasCaught());
6997 CHECK_EQ(99, value->Int32Value());
6998
6999 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00007000 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007001 CHECK(!try_catch.HasCaught());
7002 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007003
7004 // Check that the call-as-function handler can be called through
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007005 // new.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007006 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00007007 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007008 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007009}
7010
7011
7012static int CountHandles() {
7013 return v8::HandleScope::NumberOfHandles();
7014}
7015
7016
7017static int Recurse(int depth, int iterations) {
7018 v8::HandleScope scope;
7019 if (depth == 0) return CountHandles();
7020 for (int i = 0; i < iterations; i++) {
7021 Local<v8::Number> n = v8::Integer::New(42);
7022 }
7023 return Recurse(depth - 1, iterations);
7024}
7025
7026
7027THREADED_TEST(HandleIteration) {
7028 static const int kIterations = 500;
7029 static const int kNesting = 200;
7030 CHECK_EQ(0, CountHandles());
7031 {
7032 v8::HandleScope scope1;
7033 CHECK_EQ(0, CountHandles());
7034 for (int i = 0; i < kIterations; i++) {
7035 Local<v8::Number> n = v8::Integer::New(42);
7036 CHECK_EQ(i + 1, CountHandles());
7037 }
7038
7039 CHECK_EQ(kIterations, CountHandles());
7040 {
7041 v8::HandleScope scope2;
7042 for (int j = 0; j < kIterations; j++) {
7043 Local<v8::Number> n = v8::Integer::New(42);
7044 CHECK_EQ(j + 1 + kIterations, CountHandles());
7045 }
7046 }
7047 CHECK_EQ(kIterations, CountHandles());
7048 }
7049 CHECK_EQ(0, CountHandles());
7050 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7051}
7052
7053
7054static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7055 Local<String> name,
7056 const AccessorInfo& info) {
7057 ApiTestFuzzer::Fuzz();
7058 return v8::Handle<Value>();
7059}
7060
7061
7062THREADED_TEST(InterceptorHasOwnProperty) {
7063 v8::HandleScope scope;
7064 LocalContext context;
7065 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7066 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7067 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7068 Local<Function> function = fun_templ->GetFunction();
7069 context->Global()->Set(v8_str("constructor"), function);
7070 v8::Handle<Value> value = CompileRun(
7071 "var o = new constructor();"
7072 "o.hasOwnProperty('ostehaps');");
7073 CHECK_EQ(false, value->BooleanValue());
7074 value = CompileRun(
7075 "o.ostehaps = 42;"
7076 "o.hasOwnProperty('ostehaps');");
7077 CHECK_EQ(true, value->BooleanValue());
7078 value = CompileRun(
7079 "var p = new constructor();"
7080 "p.hasOwnProperty('ostehaps');");
7081 CHECK_EQ(false, value->BooleanValue());
7082}
7083
7084
ager@chromium.org9085a012009-05-11 19:22:57 +00007085static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7086 Local<String> name,
7087 const AccessorInfo& info) {
7088 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007089 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007090 return v8::Handle<Value>();
7091}
7092
7093
7094THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7095 v8::HandleScope scope;
7096 LocalContext context;
7097 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7098 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7099 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7100 Local<Function> function = fun_templ->GetFunction();
7101 context->Global()->Set(v8_str("constructor"), function);
7102 // Let's first make some stuff so we can be sure to get a good GC.
7103 CompileRun(
7104 "function makestr(size) {"
7105 " switch (size) {"
7106 " case 1: return 'f';"
7107 " case 2: return 'fo';"
7108 " case 3: return 'foo';"
7109 " }"
7110 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7111 "}"
7112 "var x = makestr(12345);"
7113 "x = makestr(31415);"
7114 "x = makestr(23456);");
7115 v8::Handle<Value> value = CompileRun(
7116 "var o = new constructor();"
7117 "o.__proto__ = new String(x);"
7118 "o.hasOwnProperty('ostehaps');");
7119 CHECK_EQ(false, value->BooleanValue());
7120}
7121
7122
ager@chromium.orge2902be2009-06-08 12:21:35 +00007123typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7124 const AccessorInfo& info);
7125
7126
7127static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7128 const char* source,
7129 int expected) {
7130 v8::HandleScope scope;
7131 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007132 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007133 LocalContext context;
7134 context->Global()->Set(v8_str("o"), templ->NewInstance());
7135 v8::Handle<Value> value = CompileRun(source);
7136 CHECK_EQ(expected, value->Int32Value());
7137}
7138
7139
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007140static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7141 const AccessorInfo& info) {
7142 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007143 CHECK_EQ(v8_str("data"), info.Data());
7144 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007145 return v8::Integer::New(42);
7146}
7147
7148
7149// This test should hit the load IC for the interceptor case.
7150THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007151 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007152 "var result = 0;"
7153 "for (var i = 0; i < 1000; i++) {"
7154 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007155 "}",
7156 42);
7157}
7158
7159
7160// Below go several tests which verify that JITing for various
7161// configurations of interceptor and explicit fields works fine
7162// (those cases are special cased to get better performance).
7163
7164static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7165 const AccessorInfo& info) {
7166 ApiTestFuzzer::Fuzz();
7167 return v8_str("x")->Equals(name)
7168 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7169}
7170
7171
7172THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7173 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7174 "var result = 0;"
7175 "o.y = 239;"
7176 "for (var i = 0; i < 1000; i++) {"
7177 " result = o.y;"
7178 "}",
7179 239);
7180}
7181
7182
7183THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7184 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7185 "var result = 0;"
7186 "o.__proto__ = { 'y': 239 };"
7187 "for (var i = 0; i < 1000; i++) {"
7188 " result = o.y + o.x;"
7189 "}",
7190 239 + 42);
7191}
7192
7193
7194THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7195 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7196 "var result = 0;"
7197 "o.__proto__.y = 239;"
7198 "for (var i = 0; i < 1000; i++) {"
7199 " result = o.y + o.x;"
7200 "}",
7201 239 + 42);
7202}
7203
7204
7205THREADED_TEST(InterceptorLoadICUndefined) {
7206 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7207 "var result = 0;"
7208 "for (var i = 0; i < 1000; i++) {"
7209 " result = (o.y == undefined) ? 239 : 42;"
7210 "}",
7211 239);
7212}
7213
7214
7215THREADED_TEST(InterceptorLoadICWithOverride) {
7216 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7217 "fst = new Object(); fst.__proto__ = o;"
7218 "snd = new Object(); snd.__proto__ = fst;"
7219 "var result1 = 0;"
7220 "for (var i = 0; i < 1000; i++) {"
7221 " result1 = snd.x;"
7222 "}"
7223 "fst.x = 239;"
7224 "var result = 0;"
7225 "for (var i = 0; i < 1000; i++) {"
7226 " result = snd.x;"
7227 "}"
7228 "result + result1",
7229 239 + 42);
7230}
7231
7232
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007233// Test the case when we stored field into
7234// a stub, but interceptor produced value on its own.
7235THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7236 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7237 "proto = new Object();"
7238 "o.__proto__ = proto;"
7239 "proto.x = 239;"
7240 "for (var i = 0; i < 1000; i++) {"
7241 " o.x;"
7242 // Now it should be ICed and keep a reference to x defined on proto
7243 "}"
7244 "var result = 0;"
7245 "for (var i = 0; i < 1000; i++) {"
7246 " result += o.x;"
7247 "}"
7248 "result;",
7249 42 * 1000);
7250}
7251
7252
7253// Test the case when we stored field into
7254// a stub, but it got invalidated later on.
7255THREADED_TEST(InterceptorLoadICInvalidatedField) {
7256 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7257 "proto1 = new Object();"
7258 "proto2 = new Object();"
7259 "o.__proto__ = proto1;"
7260 "proto1.__proto__ = proto2;"
7261 "proto2.y = 239;"
7262 "for (var i = 0; i < 1000; i++) {"
7263 " o.y;"
7264 // Now it should be ICed and keep a reference to y defined on proto2
7265 "}"
7266 "proto1.y = 42;"
7267 "var result = 0;"
7268 "for (var i = 0; i < 1000; i++) {"
7269 " result += o.y;"
7270 "}"
7271 "result;",
7272 42 * 1000);
7273}
7274
7275
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007276static int interceptor_load_not_handled_calls = 0;
7277static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7278 const AccessorInfo& info) {
7279 ++interceptor_load_not_handled_calls;
7280 return v8::Handle<v8::Value>();
7281}
7282
7283
7284// Test how post-interceptor lookups are done in the non-cacheable
7285// case: the interceptor should not be invoked during this lookup.
7286THREADED_TEST(InterceptorLoadICPostInterceptor) {
7287 interceptor_load_not_handled_calls = 0;
7288 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7289 "receiver = new Object();"
7290 "receiver.__proto__ = o;"
7291 "proto = new Object();"
7292 "/* Make proto a slow-case object. */"
7293 "for (var i = 0; i < 1000; i++) {"
7294 " proto[\"xxxxxxxx\" + i] = [];"
7295 "}"
7296 "proto.x = 17;"
7297 "o.__proto__ = proto;"
7298 "var result = 0;"
7299 "for (var i = 0; i < 1000; i++) {"
7300 " result += receiver.x;"
7301 "}"
7302 "result;",
7303 17 * 1000);
7304 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7305}
7306
7307
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007308// Test the case when we stored field into
7309// a stub, but it got invalidated later on due to override on
7310// global object which is between interceptor and fields' holders.
7311THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7312 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7313 "o.__proto__ = this;" // set a global to be a proto of o.
7314 "this.__proto__.y = 239;"
7315 "for (var i = 0; i < 10; i++) {"
7316 " if (o.y != 239) throw 'oops: ' + o.y;"
7317 // Now it should be ICed and keep a reference to y defined on field_holder.
7318 "}"
7319 "this.y = 42;" // Assign on a global.
7320 "var result = 0;"
7321 "for (var i = 0; i < 10; i++) {"
7322 " result += o.y;"
7323 "}"
7324 "result;",
7325 42 * 10);
7326}
7327
7328
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007329static void SetOnThis(Local<String> name,
7330 Local<Value> value,
7331 const AccessorInfo& info) {
7332 info.This()->ForceSet(name, value);
7333}
7334
7335
7336THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
7337 v8::HandleScope scope;
7338 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7339 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7340 templ->SetAccessor(v8_str("y"), Return239);
7341 LocalContext context;
7342 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007343
7344 // Check the case when receiver and interceptor's holder
7345 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007346 v8::Handle<Value> value = CompileRun(
7347 "var result = 0;"
7348 "for (var i = 0; i < 7; i++) {"
7349 " result = o.y;"
7350 "}");
7351 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007352
7353 // Check the case when interceptor's holder is in proto chain
7354 // of receiver.
7355 value = CompileRun(
7356 "r = { __proto__: o };"
7357 "var result = 0;"
7358 "for (var i = 0; i < 7; i++) {"
7359 " result = r.y;"
7360 "}");
7361 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007362}
7363
7364
7365THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
7366 v8::HandleScope scope;
7367 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7368 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7369 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7370 templ_p->SetAccessor(v8_str("y"), Return239);
7371
7372 LocalContext context;
7373 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7374 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7375
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007376 // Check the case when receiver and interceptor's holder
7377 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007378 v8::Handle<Value> value = CompileRun(
7379 "o.__proto__ = p;"
7380 "var result = 0;"
7381 "for (var i = 0; i < 7; i++) {"
7382 " result = o.x + o.y;"
7383 "}");
7384 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007385
7386 // Check the case when interceptor's holder is in proto chain
7387 // of receiver.
7388 value = CompileRun(
7389 "r = { __proto__: o };"
7390 "var result = 0;"
7391 "for (var i = 0; i < 7; i++) {"
7392 " result = r.x + r.y;"
7393 "}");
7394 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007395}
7396
7397
7398THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
7399 v8::HandleScope scope;
7400 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7401 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7402 templ->SetAccessor(v8_str("y"), Return239);
7403
7404 LocalContext context;
7405 context->Global()->Set(v8_str("o"), templ->NewInstance());
7406
7407 v8::Handle<Value> value = CompileRun(
7408 "fst = new Object(); fst.__proto__ = o;"
7409 "snd = new Object(); snd.__proto__ = fst;"
7410 "var result1 = 0;"
7411 "for (var i = 0; i < 7; i++) {"
7412 " result1 = snd.x;"
7413 "}"
7414 "fst.x = 239;"
7415 "var result = 0;"
7416 "for (var i = 0; i < 7; i++) {"
7417 " result = snd.x;"
7418 "}"
7419 "result + result1");
7420 CHECK_EQ(239 + 42, value->Int32Value());
7421}
7422
7423
7424// Test the case when we stored callback into
7425// a stub, but interceptor produced value on its own.
7426THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
7427 v8::HandleScope scope;
7428 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7429 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7430 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7431 templ_p->SetAccessor(v8_str("y"), Return239);
7432
7433 LocalContext context;
7434 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7435 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7436
7437 v8::Handle<Value> value = CompileRun(
7438 "o.__proto__ = p;"
7439 "for (var i = 0; i < 7; i++) {"
7440 " o.x;"
7441 // Now it should be ICed and keep a reference to x defined on p
7442 "}"
7443 "var result = 0;"
7444 "for (var i = 0; i < 7; i++) {"
7445 " result += o.x;"
7446 "}"
7447 "result");
7448 CHECK_EQ(42 * 7, value->Int32Value());
7449}
7450
7451
7452// Test the case when we stored callback into
7453// a stub, but it got invalidated later on.
7454THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
7455 v8::HandleScope scope;
7456 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7457 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7458 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7459 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7460
7461 LocalContext context;
7462 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7463 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7464
7465 v8::Handle<Value> value = CompileRun(
7466 "inbetween = new Object();"
7467 "o.__proto__ = inbetween;"
7468 "inbetween.__proto__ = p;"
7469 "for (var i = 0; i < 10; i++) {"
7470 " o.y;"
7471 // Now it should be ICed and keep a reference to y defined on p
7472 "}"
7473 "inbetween.y = 42;"
7474 "var result = 0;"
7475 "for (var i = 0; i < 10; i++) {"
7476 " result += o.y;"
7477 "}"
7478 "result");
7479 CHECK_EQ(42 * 10, value->Int32Value());
7480}
7481
7482
7483// Test the case when we stored callback into
7484// a stub, but it got invalidated later on due to override on
7485// global object which is between interceptor and callbacks' holders.
7486THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
7487 v8::HandleScope scope;
7488 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7489 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7490 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7491 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7492
7493 LocalContext context;
7494 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7495 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7496
7497 v8::Handle<Value> value = CompileRun(
7498 "o.__proto__ = this;"
7499 "this.__proto__ = p;"
7500 "for (var i = 0; i < 10; i++) {"
7501 " if (o.y != 239) throw 'oops: ' + o.y;"
7502 // Now it should be ICed and keep a reference to y defined on p
7503 "}"
7504 "this.y = 42;"
7505 "var result = 0;"
7506 "for (var i = 0; i < 10; i++) {"
7507 " result += o.y;"
7508 "}"
7509 "result");
7510 CHECK_EQ(42 * 10, value->Int32Value());
7511}
7512
7513
ager@chromium.orge2902be2009-06-08 12:21:35 +00007514static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7515 const AccessorInfo& info) {
7516 ApiTestFuzzer::Fuzz();
7517 CHECK(v8_str("x")->Equals(name));
7518 return v8::Integer::New(0);
7519}
7520
7521
7522THREADED_TEST(InterceptorReturningZero) {
7523 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7524 "o.x == undefined ? 1 : 0",
7525 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007526}
7527
7528
7529static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007530 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007531 CHECK(v8_str("x")->Equals(key));
7532 CHECK_EQ(42, value->Int32Value());
7533 return value;
7534}
7535
7536
7537// This test should hit the store IC for the interceptor case.
7538THREADED_TEST(InterceptorStoreIC) {
7539 v8::HandleScope scope;
7540 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7541 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007542 InterceptorStoreICSetter,
7543 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007544 LocalContext context;
7545 context->Global()->Set(v8_str("o"), templ->NewInstance());
7546 v8::Handle<Value> value = CompileRun(
7547 "for (var i = 0; i < 1000; i++) {"
7548 " o.x = 42;"
7549 "}");
7550}
7551
7552
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007553THREADED_TEST(InterceptorStoreICWithNoSetter) {
7554 v8::HandleScope scope;
7555 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7556 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7557 LocalContext context;
7558 context->Global()->Set(v8_str("o"), templ->NewInstance());
7559 v8::Handle<Value> value = CompileRun(
7560 "for (var i = 0; i < 1000; i++) {"
7561 " o.y = 239;"
7562 "}"
7563 "42 + o.y");
7564 CHECK_EQ(239 + 42, value->Int32Value());
7565}
7566
7567
7568
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007569
7570v8::Handle<Value> call_ic_function;
7571v8::Handle<Value> call_ic_function2;
7572v8::Handle<Value> call_ic_function3;
7573
7574static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7575 const AccessorInfo& info) {
7576 ApiTestFuzzer::Fuzz();
7577 CHECK(v8_str("x")->Equals(name));
7578 return call_ic_function;
7579}
7580
7581
7582// This test should hit the call IC for the interceptor case.
7583THREADED_TEST(InterceptorCallIC) {
7584 v8::HandleScope scope;
7585 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7586 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7587 LocalContext context;
7588 context->Global()->Set(v8_str("o"), templ->NewInstance());
7589 call_ic_function =
7590 v8_compile("function f(x) { return x + 1; }; f")->Run();
7591 v8::Handle<Value> value = CompileRun(
7592 "var result = 0;"
7593 "for (var i = 0; i < 1000; i++) {"
7594 " result = o.x(41);"
7595 "}");
7596 CHECK_EQ(42, value->Int32Value());
7597}
7598
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007599
7600// This test checks that if interceptor doesn't provide
7601// a value, we can fetch regular value.
7602THREADED_TEST(InterceptorCallICSeesOthers) {
7603 v8::HandleScope scope;
7604 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7605 templ->SetNamedPropertyHandler(NoBlockGetterX);
7606 LocalContext context;
7607 context->Global()->Set(v8_str("o"), templ->NewInstance());
7608 v8::Handle<Value> value = CompileRun(
7609 "o.x = function f(x) { return x + 1; };"
7610 "var result = 0;"
7611 "for (var i = 0; i < 7; i++) {"
7612 " result = o.x(41);"
7613 "}");
7614 CHECK_EQ(42, value->Int32Value());
7615}
7616
7617
7618static v8::Handle<Value> call_ic_function4;
7619static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
7620 const AccessorInfo& info) {
7621 ApiTestFuzzer::Fuzz();
7622 CHECK(v8_str("x")->Equals(name));
7623 return call_ic_function4;
7624}
7625
7626
7627// This test checks that if interceptor provides a function,
7628// even if we cached shadowed variant, interceptor's function
7629// is invoked
7630THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7631 v8::HandleScope scope;
7632 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7633 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7634 LocalContext context;
7635 context->Global()->Set(v8_str("o"), templ->NewInstance());
7636 call_ic_function4 =
7637 v8_compile("function f(x) { return x - 1; }; f")->Run();
7638 v8::Handle<Value> value = CompileRun(
7639 "o.__proto__.x = function(x) { return x + 1; };"
7640 "var result = 0;"
7641 "for (var i = 0; i < 1000; i++) {"
7642 " result = o.x(42);"
7643 "}");
7644 CHECK_EQ(41, value->Int32Value());
7645}
7646
7647
7648// Test the case when we stored cacheable lookup into
7649// a stub, but it got invalidated later on
7650THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7651 v8::HandleScope scope;
7652 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7653 templ->SetNamedPropertyHandler(NoBlockGetterX);
7654 LocalContext context;
7655 context->Global()->Set(v8_str("o"), templ->NewInstance());
7656 v8::Handle<Value> value = CompileRun(
7657 "proto1 = new Object();"
7658 "proto2 = new Object();"
7659 "o.__proto__ = proto1;"
7660 "proto1.__proto__ = proto2;"
7661 "proto2.y = function(x) { return x + 1; };"
7662 // Invoke it many times to compile a stub
7663 "for (var i = 0; i < 7; i++) {"
7664 " o.y(42);"
7665 "}"
7666 "proto1.y = function(x) { return x - 1; };"
7667 "var result = 0;"
7668 "for (var i = 0; i < 7; i++) {"
7669 " result += o.y(42);"
7670 "}");
7671 CHECK_EQ(41 * 7, value->Int32Value());
7672}
7673
7674
7675static v8::Handle<Value> call_ic_function5;
7676static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7677 const AccessorInfo& info) {
7678 ApiTestFuzzer::Fuzz();
7679 if (v8_str("x")->Equals(name))
7680 return call_ic_function5;
7681 else
7682 return Local<Value>();
7683}
7684
7685
7686// This test checks that if interceptor doesn't provide a function,
7687// cached constant function is used
7688THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7689 v8::HandleScope scope;
7690 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7691 templ->SetNamedPropertyHandler(NoBlockGetterX);
7692 LocalContext context;
7693 context->Global()->Set(v8_str("o"), templ->NewInstance());
7694 v8::Handle<Value> value = CompileRun(
7695 "function inc(x) { return x + 1; };"
7696 "inc(1);"
7697 "o.x = inc;"
7698 "var result = 0;"
7699 "for (var i = 0; i < 1000; i++) {"
7700 " result = o.x(42);"
7701 "}");
7702 CHECK_EQ(43, value->Int32Value());
7703}
7704
7705
7706// This test checks that if interceptor provides a function,
7707// even if we cached constant function, interceptor's function
7708// is invoked
7709THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7710 v8::HandleScope scope;
7711 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7712 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7713 LocalContext context;
7714 context->Global()->Set(v8_str("o"), templ->NewInstance());
7715 call_ic_function5 =
7716 v8_compile("function f(x) { return x - 1; }; f")->Run();
7717 v8::Handle<Value> value = CompileRun(
7718 "function inc(x) { return x + 1; };"
7719 "inc(1);"
7720 "o.x = inc;"
7721 "var result = 0;"
7722 "for (var i = 0; i < 1000; i++) {"
7723 " result = o.x(42);"
7724 "}");
7725 CHECK_EQ(41, value->Int32Value());
7726}
7727
7728
7729// Test the case when we stored constant function into
7730// a stub, but it got invalidated later on
7731THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7732 v8::HandleScope scope;
7733 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7734 templ->SetNamedPropertyHandler(NoBlockGetterX);
7735 LocalContext context;
7736 context->Global()->Set(v8_str("o"), templ->NewInstance());
7737 v8::Handle<Value> value = CompileRun(
7738 "function inc(x) { return x + 1; };"
7739 "inc(1);"
7740 "proto1 = new Object();"
7741 "proto2 = new Object();"
7742 "o.__proto__ = proto1;"
7743 "proto1.__proto__ = proto2;"
7744 "proto2.y = inc;"
7745 // Invoke it many times to compile a stub
7746 "for (var i = 0; i < 7; i++) {"
7747 " o.y(42);"
7748 "}"
7749 "proto1.y = function(x) { return x - 1; };"
7750 "var result = 0;"
7751 "for (var i = 0; i < 7; i++) {"
7752 " result += o.y(42);"
7753 "}");
7754 CHECK_EQ(41 * 7, value->Int32Value());
7755}
7756
7757
7758// Test the case when we stored constant function into
7759// a stub, but it got invalidated later on due to override on
7760// global object which is between interceptor and constant function' holders.
7761THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7762 v8::HandleScope scope;
7763 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7764 templ->SetNamedPropertyHandler(NoBlockGetterX);
7765 LocalContext context;
7766 context->Global()->Set(v8_str("o"), templ->NewInstance());
7767 v8::Handle<Value> value = CompileRun(
7768 "function inc(x) { return x + 1; };"
7769 "inc(1);"
7770 "o.__proto__ = this;"
7771 "this.__proto__.y = inc;"
7772 // Invoke it many times to compile a stub
7773 "for (var i = 0; i < 7; i++) {"
7774 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7775 "}"
7776 "this.y = function(x) { return x - 1; };"
7777 "var result = 0;"
7778 "for (var i = 0; i < 7; i++) {"
7779 " result += o.y(42);"
7780 "}");
7781 CHECK_EQ(41 * 7, value->Int32Value());
7782}
7783
7784
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007785// Test the case when actual function to call sits on global object.
7786THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7787 v8::HandleScope scope;
7788 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7789 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7790
7791 LocalContext context;
7792 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7793
7794 v8::Handle<Value> value = CompileRun(
7795 "try {"
7796 " o.__proto__ = this;"
7797 " for (var i = 0; i < 10; i++) {"
7798 " var v = o.parseFloat('239');"
7799 " if (v != 239) throw v;"
7800 // Now it should be ICed and keep a reference to parseFloat.
7801 " }"
7802 " var result = 0;"
7803 " for (var i = 0; i < 10; i++) {"
7804 " result += o.parseFloat('239');"
7805 " }"
7806 " result"
7807 "} catch(e) {"
7808 " e"
7809 "};");
7810 CHECK_EQ(239 * 10, value->Int32Value());
7811}
7812
ager@chromium.org5c838252010-02-19 08:53:10 +00007813static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7814 const AccessorInfo& info) {
7815 ApiTestFuzzer::Fuzz();
7816 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7817 ++(*call_count);
7818 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007819 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00007820 }
7821 return v8::Handle<Value>();
7822}
7823
7824static v8::Handle<Value> FastApiCallback_TrivialSignature(
7825 const v8::Arguments& args) {
7826 ApiTestFuzzer::Fuzz();
7827 CHECK_EQ(args.This(), args.Holder());
7828 CHECK(args.Data()->Equals(v8_str("method_data")));
7829 return v8::Integer::New(args[0]->Int32Value() + 1);
7830}
7831
7832static v8::Handle<Value> FastApiCallback_SimpleSignature(
7833 const v8::Arguments& args) {
7834 ApiTestFuzzer::Fuzz();
7835 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7836 CHECK(args.Data()->Equals(v8_str("method_data")));
7837 // Note, we're using HasRealNamedProperty instead of Has to avoid
7838 // invoking the interceptor again.
7839 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7840 return v8::Integer::New(args[0]->Int32Value() + 1);
7841}
7842
7843// Helper to maximize the odds of object moving.
7844static void GenerateSomeGarbage() {
7845 CompileRun(
7846 "var garbage;"
7847 "for (var i = 0; i < 1000; i++) {"
7848 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7849 "}"
7850 "garbage = undefined;");
7851}
7852
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007853
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007854v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
7855 static int count = 0;
7856 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007858 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
7859 }
7860 return v8::Handle<v8::Value>();
7861}
7862
7863
7864THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
7865 v8::HandleScope scope;
7866 LocalContext context;
7867 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7868 nativeobject_templ->Set("callback",
7869 v8::FunctionTemplate::New(DirectApiCallback));
7870 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7871 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7872 // call the api function multiple times to ensure direct call stub creation.
7873 CompileRun(
7874 "function f() {"
7875 " for (var i = 1; i <= 30; i++) {"
7876 " nativeobject.callback();"
7877 " }"
7878 "}"
7879 "f();");
7880}
7881
7882
7883v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
7884 return v8::ThrowException(v8_str("g"));
7885}
7886
7887
7888THREADED_TEST(CallICFastApi_DirectCall_Throw) {
7889 v8::HandleScope scope;
7890 LocalContext context;
7891 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
7892 nativeobject_templ->Set("callback",
7893 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
7894 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
7895 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
7896 // call the api function multiple times to ensure direct call stub creation.
7897 v8::Handle<Value> result = CompileRun(
7898 "var result = '';"
7899 "function f() {"
7900 " for (var i = 1; i <= 5; i++) {"
7901 " try { nativeobject.callback(); } catch (e) { result += e; }"
7902 " }"
7903 "}"
7904 "f(); result;");
7905 CHECK_EQ(v8_str("ggggg"), result);
7906}
7907
7908
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007909v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
7910 const v8::AccessorInfo& info) {
7911 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007913 GenerateSomeGarbage();
7914 }
7915 return v8::Handle<v8::Value>();
7916}
7917
7918
7919THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
7920 v8::HandleScope scope;
7921 LocalContext context;
7922 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7923 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
7924 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7925 p_getter_count = 0;
7926 CompileRun(
7927 "function f() {"
7928 " for (var i = 0; i < 30; i++) o1.p1;"
7929 "}"
7930 "f();");
7931 CHECK_EQ(30, p_getter_count);
7932}
7933
7934
7935v8::Handle<v8::Value> ThrowingDirectGetterCallback(
7936 Local<String> name, const v8::AccessorInfo& info) {
7937 return v8::ThrowException(v8_str("g"));
7938}
7939
7940
7941THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
7942 v8::HandleScope scope;
7943 LocalContext context;
7944 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
7945 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
7946 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7947 v8::Handle<Value> result = CompileRun(
7948 "var result = '';"
7949 "for (var i = 0; i < 5; i++) {"
7950 " try { o1.p1; } catch (e) { result += e; }"
7951 "}"
7952 "result;");
7953 CHECK_EQ(v8_str("ggggg"), result);
7954}
7955
7956
ager@chromium.org5c838252010-02-19 08:53:10 +00007957THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7958 int interceptor_call_count = 0;
7959 v8::HandleScope scope;
7960 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7961 v8::Handle<v8::FunctionTemplate> method_templ =
7962 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7963 v8_str("method_data"),
7964 v8::Handle<v8::Signature>());
7965 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7966 proto_templ->Set(v8_str("method"), method_templ);
7967 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7968 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7969 NULL, NULL, NULL, NULL,
7970 v8::External::Wrap(&interceptor_call_count));
7971 LocalContext context;
7972 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7973 GenerateSomeGarbage();
7974 context->Global()->Set(v8_str("o"), fun->NewInstance());
7975 v8::Handle<Value> value = CompileRun(
7976 "var result = 0;"
7977 "for (var i = 0; i < 100; i++) {"
7978 " result = o.method(41);"
7979 "}");
7980 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7981 CHECK_EQ(100, interceptor_call_count);
7982}
7983
7984THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7985 int interceptor_call_count = 0;
7986 v8::HandleScope scope;
7987 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7988 v8::Handle<v8::FunctionTemplate> method_templ =
7989 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7990 v8_str("method_data"),
7991 v8::Signature::New(fun_templ));
7992 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7993 proto_templ->Set(v8_str("method"), method_templ);
7994 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7995 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7996 NULL, NULL, NULL, NULL,
7997 v8::External::Wrap(&interceptor_call_count));
7998 LocalContext context;
7999 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8000 GenerateSomeGarbage();
8001 context->Global()->Set(v8_str("o"), fun->NewInstance());
8002 v8::Handle<Value> value = CompileRun(
8003 "o.foo = 17;"
8004 "var receiver = {};"
8005 "receiver.__proto__ = o;"
8006 "var result = 0;"
8007 "for (var i = 0; i < 100; i++) {"
8008 " result = receiver.method(41);"
8009 "}");
8010 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8011 CHECK_EQ(100, interceptor_call_count);
8012}
8013
8014THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8015 int interceptor_call_count = 0;
8016 v8::HandleScope scope;
8017 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8018 v8::Handle<v8::FunctionTemplate> method_templ =
8019 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8020 v8_str("method_data"),
8021 v8::Signature::New(fun_templ));
8022 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8023 proto_templ->Set(v8_str("method"), method_templ);
8024 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8025 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8026 NULL, NULL, NULL, NULL,
8027 v8::External::Wrap(&interceptor_call_count));
8028 LocalContext context;
8029 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8030 GenerateSomeGarbage();
8031 context->Global()->Set(v8_str("o"), fun->NewInstance());
8032 v8::Handle<Value> value = CompileRun(
8033 "o.foo = 17;"
8034 "var receiver = {};"
8035 "receiver.__proto__ = o;"
8036 "var result = 0;"
8037 "var saved_result = 0;"
8038 "for (var i = 0; i < 100; i++) {"
8039 " result = receiver.method(41);"
8040 " if (i == 50) {"
8041 " saved_result = result;"
8042 " receiver = {method: function(x) { return x - 1 }};"
8043 " }"
8044 "}");
8045 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8046 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8047 CHECK_GE(interceptor_call_count, 50);
8048}
8049
8050THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8051 int interceptor_call_count = 0;
8052 v8::HandleScope scope;
8053 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8054 v8::Handle<v8::FunctionTemplate> method_templ =
8055 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8056 v8_str("method_data"),
8057 v8::Signature::New(fun_templ));
8058 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8059 proto_templ->Set(v8_str("method"), method_templ);
8060 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8061 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8062 NULL, NULL, NULL, NULL,
8063 v8::External::Wrap(&interceptor_call_count));
8064 LocalContext context;
8065 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8066 GenerateSomeGarbage();
8067 context->Global()->Set(v8_str("o"), fun->NewInstance());
8068 v8::Handle<Value> value = CompileRun(
8069 "o.foo = 17;"
8070 "var receiver = {};"
8071 "receiver.__proto__ = o;"
8072 "var result = 0;"
8073 "var saved_result = 0;"
8074 "for (var i = 0; i < 100; i++) {"
8075 " result = receiver.method(41);"
8076 " if (i == 50) {"
8077 " saved_result = result;"
8078 " o.method = function(x) { return x - 1 };"
8079 " }"
8080 "}");
8081 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8082 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8083 CHECK_GE(interceptor_call_count, 50);
8084}
8085
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008086THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8087 int interceptor_call_count = 0;
8088 v8::HandleScope scope;
8089 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8090 v8::Handle<v8::FunctionTemplate> method_templ =
8091 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8092 v8_str("method_data"),
8093 v8::Signature::New(fun_templ));
8094 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8095 proto_templ->Set(v8_str("method"), method_templ);
8096 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8097 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8098 NULL, NULL, NULL, NULL,
8099 v8::External::Wrap(&interceptor_call_count));
8100 LocalContext context;
8101 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8102 GenerateSomeGarbage();
8103 context->Global()->Set(v8_str("o"), fun->NewInstance());
8104 v8::TryCatch try_catch;
8105 v8::Handle<Value> value = CompileRun(
8106 "o.foo = 17;"
8107 "var receiver = {};"
8108 "receiver.__proto__ = o;"
8109 "var result = 0;"
8110 "var saved_result = 0;"
8111 "for (var i = 0; i < 100; i++) {"
8112 " result = receiver.method(41);"
8113 " if (i == 50) {"
8114 " saved_result = result;"
8115 " receiver = 333;"
8116 " }"
8117 "}");
8118 CHECK(try_catch.HasCaught());
8119 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8120 try_catch.Exception()->ToString());
8121 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8122 CHECK_GE(interceptor_call_count, 50);
8123}
8124
ager@chromium.org5c838252010-02-19 08:53:10 +00008125THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8126 int interceptor_call_count = 0;
8127 v8::HandleScope scope;
8128 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8129 v8::Handle<v8::FunctionTemplate> method_templ =
8130 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8131 v8_str("method_data"),
8132 v8::Signature::New(fun_templ));
8133 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8134 proto_templ->Set(v8_str("method"), method_templ);
8135 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8136 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8137 NULL, NULL, NULL, NULL,
8138 v8::External::Wrap(&interceptor_call_count));
8139 LocalContext context;
8140 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8141 GenerateSomeGarbage();
8142 context->Global()->Set(v8_str("o"), fun->NewInstance());
8143 v8::TryCatch try_catch;
8144 v8::Handle<Value> value = CompileRun(
8145 "o.foo = 17;"
8146 "var receiver = {};"
8147 "receiver.__proto__ = o;"
8148 "var result = 0;"
8149 "var saved_result = 0;"
8150 "for (var i = 0; i < 100; i++) {"
8151 " result = receiver.method(41);"
8152 " if (i == 50) {"
8153 " saved_result = result;"
8154 " receiver = {method: receiver.method};"
8155 " }"
8156 "}");
8157 CHECK(try_catch.HasCaught());
8158 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8159 try_catch.Exception()->ToString());
8160 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8161 CHECK_GE(interceptor_call_count, 50);
8162}
8163
8164THREADED_TEST(CallICFastApi_TrivialSignature) {
8165 v8::HandleScope scope;
8166 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8167 v8::Handle<v8::FunctionTemplate> method_templ =
8168 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8169 v8_str("method_data"),
8170 v8::Handle<v8::Signature>());
8171 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8172 proto_templ->Set(v8_str("method"), method_templ);
8173 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8174 LocalContext context;
8175 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8176 GenerateSomeGarbage();
8177 context->Global()->Set(v8_str("o"), fun->NewInstance());
8178 v8::Handle<Value> value = CompileRun(
8179 "var result = 0;"
8180 "for (var i = 0; i < 100; i++) {"
8181 " result = o.method(41);"
8182 "}");
8183
8184 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8185}
8186
8187THREADED_TEST(CallICFastApi_SimpleSignature) {
8188 v8::HandleScope scope;
8189 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8190 v8::Handle<v8::FunctionTemplate> method_templ =
8191 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8192 v8_str("method_data"),
8193 v8::Signature::New(fun_templ));
8194 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8195 proto_templ->Set(v8_str("method"), method_templ);
8196 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8197 LocalContext context;
8198 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8199 GenerateSomeGarbage();
8200 context->Global()->Set(v8_str("o"), fun->NewInstance());
8201 v8::Handle<Value> value = CompileRun(
8202 "o.foo = 17;"
8203 "var receiver = {};"
8204 "receiver.__proto__ = o;"
8205 "var result = 0;"
8206 "for (var i = 0; i < 100; i++) {"
8207 " result = receiver.method(41);"
8208 "}");
8209
8210 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8211}
8212
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008213THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008214 v8::HandleScope scope;
8215 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8216 v8::Handle<v8::FunctionTemplate> method_templ =
8217 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8218 v8_str("method_data"),
8219 v8::Signature::New(fun_templ));
8220 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8221 proto_templ->Set(v8_str("method"), method_templ);
8222 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8223 LocalContext context;
8224 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8225 GenerateSomeGarbage();
8226 context->Global()->Set(v8_str("o"), fun->NewInstance());
8227 v8::Handle<Value> value = CompileRun(
8228 "o.foo = 17;"
8229 "var receiver = {};"
8230 "receiver.__proto__ = o;"
8231 "var result = 0;"
8232 "var saved_result = 0;"
8233 "for (var i = 0; i < 100; i++) {"
8234 " result = receiver.method(41);"
8235 " if (i == 50) {"
8236 " saved_result = result;"
8237 " receiver = {method: function(x) { return x - 1 }};"
8238 " }"
8239 "}");
8240 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8241 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8242}
8243
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008244THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8245 v8::HandleScope scope;
8246 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8247 v8::Handle<v8::FunctionTemplate> method_templ =
8248 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8249 v8_str("method_data"),
8250 v8::Signature::New(fun_templ));
8251 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8252 proto_templ->Set(v8_str("method"), method_templ);
8253 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8254 LocalContext context;
8255 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8256 GenerateSomeGarbage();
8257 context->Global()->Set(v8_str("o"), fun->NewInstance());
8258 v8::TryCatch try_catch;
8259 v8::Handle<Value> value = CompileRun(
8260 "o.foo = 17;"
8261 "var receiver = {};"
8262 "receiver.__proto__ = o;"
8263 "var result = 0;"
8264 "var saved_result = 0;"
8265 "for (var i = 0; i < 100; i++) {"
8266 " result = receiver.method(41);"
8267 " if (i == 50) {"
8268 " saved_result = result;"
8269 " receiver = 333;"
8270 " }"
8271 "}");
8272 CHECK(try_catch.HasCaught());
8273 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8274 try_catch.Exception()->ToString());
8275 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8276}
8277
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008278
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008279v8::Handle<Value> keyed_call_ic_function;
8280
8281static v8::Handle<Value> InterceptorKeyedCallICGetter(
8282 Local<String> name, const AccessorInfo& info) {
8283 ApiTestFuzzer::Fuzz();
8284 if (v8_str("x")->Equals(name)) {
8285 return keyed_call_ic_function;
8286 }
8287 return v8::Handle<Value>();
8288}
8289
8290
8291// Test the case when we stored cacheable lookup into
8292// a stub, but the function name changed (to another cacheable function).
8293THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8294 v8::HandleScope scope;
8295 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8296 templ->SetNamedPropertyHandler(NoBlockGetterX);
8297 LocalContext context;
8298 context->Global()->Set(v8_str("o"), templ->NewInstance());
8299 v8::Handle<Value> value = CompileRun(
8300 "proto = new Object();"
8301 "proto.y = function(x) { return x + 1; };"
8302 "proto.z = function(x) { return x - 1; };"
8303 "o.__proto__ = proto;"
8304 "var result = 0;"
8305 "var method = 'y';"
8306 "for (var i = 0; i < 10; i++) {"
8307 " if (i == 5) { method = 'z'; };"
8308 " result += o[method](41);"
8309 "}");
8310 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8311}
8312
8313
8314// Test the case when we stored cacheable lookup into
8315// a stub, but the function name changed (and the new function is present
8316// both before and after the interceptor in the prototype chain).
8317THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8318 v8::HandleScope scope;
8319 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8320 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
8321 LocalContext context;
8322 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
8323 keyed_call_ic_function =
8324 v8_compile("function f(x) { return x - 1; }; f")->Run();
8325 v8::Handle<Value> value = CompileRun(
8326 "o = new Object();"
8327 "proto2 = new Object();"
8328 "o.y = function(x) { return x + 1; };"
8329 "proto2.y = function(x) { return x + 2; };"
8330 "o.__proto__ = proto1;"
8331 "proto1.__proto__ = proto2;"
8332 "var result = 0;"
8333 "var method = 'x';"
8334 "for (var i = 0; i < 10; i++) {"
8335 " if (i == 5) { method = 'y'; };"
8336 " result += o[method](41);"
8337 "}");
8338 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8339}
8340
8341
8342// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
8343// on the global object.
8344THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
8345 v8::HandleScope scope;
8346 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8347 templ->SetNamedPropertyHandler(NoBlockGetterX);
8348 LocalContext context;
8349 context->Global()->Set(v8_str("o"), templ->NewInstance());
8350 v8::Handle<Value> value = CompileRun(
8351 "function inc(x) { return x + 1; };"
8352 "inc(1);"
8353 "function dec(x) { return x - 1; };"
8354 "dec(1);"
8355 "o.__proto__ = this;"
8356 "this.__proto__.x = inc;"
8357 "this.__proto__.y = dec;"
8358 "var result = 0;"
8359 "var method = 'x';"
8360 "for (var i = 0; i < 10; i++) {"
8361 " if (i == 5) { method = 'y'; };"
8362 " result += o[method](41);"
8363 "}");
8364 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8365}
8366
8367
8368// Test the case when actual function to call sits on global object.
8369THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
8370 v8::HandleScope scope;
8371 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8372 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8373 LocalContext context;
8374 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8375
8376 v8::Handle<Value> value = CompileRun(
8377 "function len(x) { return x.length; };"
8378 "o.__proto__ = this;"
8379 "var m = 'parseFloat';"
8380 "var result = 0;"
8381 "for (var i = 0; i < 10; i++) {"
8382 " if (i == 5) {"
8383 " m = 'len';"
8384 " saved_result = result;"
8385 " };"
8386 " result = o[m]('239');"
8387 "}");
8388 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
8389 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8390}
8391
8392// Test the map transition before the interceptor.
8393THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
8394 v8::HandleScope scope;
8395 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8396 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8397 LocalContext context;
8398 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
8399
8400 v8::Handle<Value> value = CompileRun(
8401 "var o = new Object();"
8402 "o.__proto__ = proto;"
8403 "o.method = function(x) { return x + 1; };"
8404 "var m = 'method';"
8405 "var result = 0;"
8406 "for (var i = 0; i < 10; i++) {"
8407 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
8408 " result += o[m](41);"
8409 "}");
8410 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8411}
8412
8413
8414// Test the map transition after the interceptor.
8415THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
8416 v8::HandleScope scope;
8417 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8418 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8419 LocalContext context;
8420 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8421
8422 v8::Handle<Value> value = CompileRun(
8423 "var proto = new Object();"
8424 "o.__proto__ = proto;"
8425 "proto.method = function(x) { return x + 1; };"
8426 "var m = 'method';"
8427 "var result = 0;"
8428 "for (var i = 0; i < 10; i++) {"
8429 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
8430 " result += o[m](41);"
8431 "}");
8432 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8433}
8434
8435
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008436static int interceptor_call_count = 0;
8437
8438static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
8439 const AccessorInfo& info) {
8440 ApiTestFuzzer::Fuzz();
8441 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
8442 return call_ic_function2;
8443 }
8444 return v8::Handle<Value>();
8445}
8446
8447
8448// This test should hit load and call ICs for the interceptor case.
8449// Once in a while, the interceptor will reply that a property was not
8450// found in which case we should get a reference error.
8451THREADED_TEST(InterceptorICReferenceErrors) {
8452 v8::HandleScope scope;
8453 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8454 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
8455 LocalContext context(0, templ, v8::Handle<Value>());
8456 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
8457 v8::Handle<Value> value = CompileRun(
8458 "function f() {"
8459 " for (var i = 0; i < 1000; i++) {"
8460 " try { x; } catch(e) { return true; }"
8461 " }"
8462 " return false;"
8463 "};"
8464 "f();");
8465 CHECK_EQ(true, value->BooleanValue());
8466 interceptor_call_count = 0;
8467 value = CompileRun(
8468 "function g() {"
8469 " for (var i = 0; i < 1000; i++) {"
8470 " try { x(42); } catch(e) { return true; }"
8471 " }"
8472 " return false;"
8473 "};"
8474 "g();");
8475 CHECK_EQ(true, value->BooleanValue());
8476}
8477
8478
8479static int interceptor_ic_exception_get_count = 0;
8480
8481static v8::Handle<Value> InterceptorICExceptionGetter(
8482 Local<String> name,
8483 const AccessorInfo& info) {
8484 ApiTestFuzzer::Fuzz();
8485 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
8486 return call_ic_function3;
8487 }
8488 if (interceptor_ic_exception_get_count == 20) {
8489 return v8::ThrowException(v8_num(42));
8490 }
8491 // Do not handle get for properties other than x.
8492 return v8::Handle<Value>();
8493}
8494
8495// Test interceptor load/call IC where the interceptor throws an
8496// exception once in a while.
8497THREADED_TEST(InterceptorICGetterExceptions) {
8498 interceptor_ic_exception_get_count = 0;
8499 v8::HandleScope scope;
8500 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8501 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
8502 LocalContext context(0, templ, v8::Handle<Value>());
8503 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
8504 v8::Handle<Value> value = CompileRun(
8505 "function f() {"
8506 " for (var i = 0; i < 100; i++) {"
8507 " try { x; } catch(e) { return true; }"
8508 " }"
8509 " return false;"
8510 "};"
8511 "f();");
8512 CHECK_EQ(true, value->BooleanValue());
8513 interceptor_ic_exception_get_count = 0;
8514 value = CompileRun(
8515 "function f() {"
8516 " for (var i = 0; i < 100; i++) {"
8517 " try { x(42); } catch(e) { return true; }"
8518 " }"
8519 " return false;"
8520 "};"
8521 "f();");
8522 CHECK_EQ(true, value->BooleanValue());
8523}
8524
8525
8526static int interceptor_ic_exception_set_count = 0;
8527
8528static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008529 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008530 ApiTestFuzzer::Fuzz();
8531 if (++interceptor_ic_exception_set_count > 20) {
8532 return v8::ThrowException(v8_num(42));
8533 }
8534 // Do not actually handle setting.
8535 return v8::Handle<Value>();
8536}
8537
8538// Test interceptor store IC where the interceptor throws an exception
8539// once in a while.
8540THREADED_TEST(InterceptorICSetterExceptions) {
8541 interceptor_ic_exception_set_count = 0;
8542 v8::HandleScope scope;
8543 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8544 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
8545 LocalContext context(0, templ, v8::Handle<Value>());
8546 v8::Handle<Value> value = CompileRun(
8547 "function f() {"
8548 " for (var i = 0; i < 100; i++) {"
8549 " try { x = 42; } catch(e) { return true; }"
8550 " }"
8551 " return false;"
8552 "};"
8553 "f();");
8554 CHECK_EQ(true, value->BooleanValue());
8555}
8556
8557
8558// Test that we ignore null interceptors.
8559THREADED_TEST(NullNamedInterceptor) {
8560 v8::HandleScope scope;
8561 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8562 templ->SetNamedPropertyHandler(0);
8563 LocalContext context;
8564 templ->Set("x", v8_num(42));
8565 v8::Handle<v8::Object> obj = templ->NewInstance();
8566 context->Global()->Set(v8_str("obj"), obj);
8567 v8::Handle<Value> value = CompileRun("obj.x");
8568 CHECK(value->IsInt32());
8569 CHECK_EQ(42, value->Int32Value());
8570}
8571
8572
8573// Test that we ignore null interceptors.
8574THREADED_TEST(NullIndexedInterceptor) {
8575 v8::HandleScope scope;
8576 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8577 templ->SetIndexedPropertyHandler(0);
8578 LocalContext context;
8579 templ->Set("42", v8_num(42));
8580 v8::Handle<v8::Object> obj = templ->NewInstance();
8581 context->Global()->Set(v8_str("obj"), obj);
8582 v8::Handle<Value> value = CompileRun("obj[42]");
8583 CHECK(value->IsInt32());
8584 CHECK_EQ(42, value->Int32Value());
8585}
8586
8587
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008588THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
8589 v8::HandleScope scope;
8590 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8591 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8592 LocalContext env;
8593 env->Global()->Set(v8_str("obj"),
8594 templ->GetFunction()->NewInstance());
8595 ExpectTrue("obj.x === 42");
8596 ExpectTrue("!obj.propertyIsEnumerable('x')");
8597}
8598
8599
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008600static Handle<Value> ThrowingGetter(Local<String> name,
8601 const AccessorInfo& info) {
8602 ApiTestFuzzer::Fuzz();
8603 ThrowException(Handle<Value>());
8604 return Undefined();
8605}
8606
8607
8608THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
8609 HandleScope scope;
8610 LocalContext context;
8611
8612 Local<FunctionTemplate> templ = FunctionTemplate::New();
8613 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
8614 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
8615
8616 Local<Object> instance = templ->GetFunction()->NewInstance();
8617
8618 Local<Object> another = Object::New();
8619 another->SetPrototype(instance);
8620
8621 Local<Object> with_js_getter = CompileRun(
8622 "o = {};\n"
8623 "o.__defineGetter__('f', function() { throw undefined; });\n"
8624 "o\n").As<Object>();
8625 CHECK(!with_js_getter.IsEmpty());
8626
8627 TryCatch try_catch;
8628
8629 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
8630 CHECK(try_catch.HasCaught());
8631 try_catch.Reset();
8632 CHECK(result.IsEmpty());
8633
8634 result = another->GetRealNamedProperty(v8_str("f"));
8635 CHECK(try_catch.HasCaught());
8636 try_catch.Reset();
8637 CHECK(result.IsEmpty());
8638
8639 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
8640 CHECK(try_catch.HasCaught());
8641 try_catch.Reset();
8642 CHECK(result.IsEmpty());
8643
8644 result = another->Get(v8_str("f"));
8645 CHECK(try_catch.HasCaught());
8646 try_catch.Reset();
8647 CHECK(result.IsEmpty());
8648
8649 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
8650 CHECK(try_catch.HasCaught());
8651 try_catch.Reset();
8652 CHECK(result.IsEmpty());
8653
8654 result = with_js_getter->Get(v8_str("f"));
8655 CHECK(try_catch.HasCaught());
8656 try_catch.Reset();
8657 CHECK(result.IsEmpty());
8658}
8659
8660
8661static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
8662 TryCatch try_catch;
8663 // Verboseness is important: it triggers message delivery which can call into
8664 // external code.
8665 try_catch.SetVerbose(true);
8666 CompileRun("throw 'from JS';");
8667 CHECK(try_catch.HasCaught());
8668 CHECK(!i::Isolate::Current()->has_pending_exception());
8669 CHECK(!i::Isolate::Current()->has_scheduled_exception());
8670 return Undefined();
8671}
8672
8673
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008674static int call_depth;
8675
8676
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008677static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
8678 TryCatch try_catch;
8679}
8680
8681
8682static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008683 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008684}
8685
8686
8687static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008688 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008689}
8690
8691
8692static void WebKitLike(Handle<Message> message, Handle<Value> data) {
8693 Handle<String> errorMessageString = message->Get();
8694 CHECK(!errorMessageString.IsEmpty());
8695 message->GetStackTrace();
8696 message->GetScriptResourceName();
8697}
8698
8699THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
8700 HandleScope scope;
8701 LocalContext context;
8702
8703 Local<Function> func =
8704 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
8705 context->Global()->Set(v8_str("func"), func);
8706
8707 MessageCallback callbacks[] =
8708 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
8709 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
8710 MessageCallback callback = callbacks[i];
8711 if (callback != NULL) {
8712 V8::AddMessageListener(callback);
8713 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00008714 // Some small number to control number of times message handler should
8715 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008716 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008717 ExpectFalse(
8718 "var thrown = false;\n"
8719 "try { func(); } catch(e) { thrown = true; }\n"
8720 "thrown\n");
8721 if (callback != NULL) {
8722 V8::RemoveMessageListeners(callback);
8723 }
8724 }
8725}
8726
8727
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008728static v8::Handle<Value> ParentGetter(Local<String> name,
8729 const AccessorInfo& info) {
8730 ApiTestFuzzer::Fuzz();
8731 return v8_num(1);
8732}
8733
8734
8735static v8::Handle<Value> ChildGetter(Local<String> name,
8736 const AccessorInfo& info) {
8737 ApiTestFuzzer::Fuzz();
8738 return v8_num(42);
8739}
8740
8741
8742THREADED_TEST(Overriding) {
8743 v8::HandleScope scope;
8744 LocalContext context;
8745
8746 // Parent template.
8747 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
8748 Local<ObjectTemplate> parent_instance_templ =
8749 parent_templ->InstanceTemplate();
8750 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
8751
8752 // Template that inherits from the parent template.
8753 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
8754 Local<ObjectTemplate> child_instance_templ =
8755 child_templ->InstanceTemplate();
8756 child_templ->Inherit(parent_templ);
8757 // Override 'f'. The child version of 'f' should get called for child
8758 // instances.
8759 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
8760 // Add 'g' twice. The 'g' added last should get called for instances.
8761 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
8762 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
8763
8764 // Add 'h' as an accessor to the proto template with ReadOnly attributes
8765 // so 'h' can be shadowed on the instance object.
8766 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
8767 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
8768 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8769
8770 // Add 'i' as an accessor to the instance template with ReadOnly attributes
8771 // but the attribute does not have effect because it is duplicated with
8772 // NULL setter.
8773 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
8774 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
8775
8776
8777
8778 // Instantiate the child template.
8779 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
8780
8781 // Check that the child function overrides the parent one.
8782 context->Global()->Set(v8_str("o"), instance);
8783 Local<Value> value = v8_compile("o.f")->Run();
8784 // Check that the 'g' that was added last is hit.
8785 CHECK_EQ(42, value->Int32Value());
8786 value = v8_compile("o.g")->Run();
8787 CHECK_EQ(42, value->Int32Value());
8788
8789 // Check 'h' can be shadowed.
8790 value = v8_compile("o.h = 3; o.h")->Run();
8791 CHECK_EQ(3, value->Int32Value());
8792
8793 // Check 'i' is cannot be shadowed or changed.
8794 value = v8_compile("o.i = 3; o.i")->Run();
8795 CHECK_EQ(42, value->Int32Value());
8796}
8797
8798
8799static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
8800 ApiTestFuzzer::Fuzz();
8801 if (args.IsConstructCall()) {
8802 return v8::Boolean::New(true);
8803 }
8804 return v8::Boolean::New(false);
8805}
8806
8807
8808THREADED_TEST(IsConstructCall) {
8809 v8::HandleScope scope;
8810
8811 // Function template with call handler.
8812 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8813 templ->SetCallHandler(IsConstructHandler);
8814
8815 LocalContext context;
8816
8817 context->Global()->Set(v8_str("f"), templ->GetFunction());
8818 Local<Value> value = v8_compile("f()")->Run();
8819 CHECK(!value->BooleanValue());
8820 value = v8_compile("new f()")->Run();
8821 CHECK(value->BooleanValue());
8822}
8823
8824
8825THREADED_TEST(ObjectProtoToString) {
8826 v8::HandleScope scope;
8827 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8828 templ->SetClassName(v8_str("MyClass"));
8829
8830 LocalContext context;
8831
8832 Local<String> customized_tostring = v8_str("customized toString");
8833
8834 // Replace Object.prototype.toString
8835 v8_compile("Object.prototype.toString = function() {"
8836 " return 'customized toString';"
8837 "}")->Run();
8838
8839 // Normal ToString call should call replaced Object.prototype.toString
8840 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
8841 Local<String> value = instance->ToString();
8842 CHECK(value->IsString() && value->Equals(customized_tostring));
8843
8844 // ObjectProtoToString should not call replace toString function.
8845 value = instance->ObjectProtoToString();
8846 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
8847
8848 // Check global
8849 value = context->Global()->ObjectProtoToString();
8850 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
8851
8852 // Check ordinary object
8853 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008854 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008855 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
8856}
8857
8858
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008859THREADED_TEST(ObjectGetConstructorName) {
8860 v8::HandleScope scope;
8861 LocalContext context;
8862 v8_compile("function Parent() {};"
8863 "function Child() {};"
8864 "Child.prototype = new Parent();"
8865 "var outer = { inner: function() { } };"
8866 "var p = new Parent();"
8867 "var c = new Child();"
8868 "var x = new outer.inner();")->Run();
8869
8870 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8871 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8872 v8_str("Parent")));
8873
8874 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8875 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8876 v8_str("Child")));
8877
8878 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8879 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8880 v8_str("outer.inner")));
8881}
8882
8883
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008884bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00008885i::Semaphore* ApiTestFuzzer::all_tests_done_=
8886 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008887int ApiTestFuzzer::active_tests_;
8888int ApiTestFuzzer::tests_being_run_;
8889int ApiTestFuzzer::current_;
8890
8891
8892// We are in a callback and want to switch to another thread (if we
8893// are currently running the thread fuzzing test).
8894void ApiTestFuzzer::Fuzz() {
8895 if (!fuzzing_) return;
8896 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8897 test->ContextSwitch();
8898}
8899
8900
8901// Let the next thread go. Since it is also waiting on the V8 lock it may
8902// not start immediately.
8903bool ApiTestFuzzer::NextThread() {
8904 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008905 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008906 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008907 if (kLogThreading)
8908 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008909 return false;
8910 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008911 if (kLogThreading) {
8912 printf("Switch from %s to %s\n",
8913 test_name,
8914 RegisterThreadedTest::nth(test_position)->name());
8915 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008916 current_ = test_position;
8917 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8918 return true;
8919}
8920
8921
8922void ApiTestFuzzer::Run() {
8923 // When it is our turn...
8924 gate_->Wait();
8925 {
8926 // ... get the V8 lock and start running the test.
8927 v8::Locker locker;
8928 CallTest();
8929 }
8930 // This test finished.
8931 active_ = false;
8932 active_tests_--;
8933 // If it was the last then signal that fact.
8934 if (active_tests_ == 0) {
8935 all_tests_done_->Signal();
8936 } else {
8937 // Otherwise select a new test and start that.
8938 NextThread();
8939 }
8940}
8941
8942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008943static unsigned linear_congruential_generator;
8944
8945
8946void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008947 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008948 fuzzing_ = true;
8949 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8950 int end = (part == FIRST_PART)
8951 ? (RegisterThreadedTest::count() >> 1)
8952 : RegisterThreadedTest::count();
8953 active_tests_ = tests_being_run_ = end - start;
8954 for (int i = 0; i < tests_being_run_; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008955 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
8956 i::Isolate::Current(), i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008957 }
8958 for (int i = 0; i < active_tests_; i++) {
8959 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8960 }
8961}
8962
8963
8964static void CallTestNumber(int test_number) {
8965 (RegisterThreadedTest::nth(test_number)->callback())();
8966}
8967
8968
8969void ApiTestFuzzer::RunAllTests() {
8970 // Set off the first test.
8971 current_ = -1;
8972 NextThread();
8973 // Wait till they are all done.
8974 all_tests_done_->Wait();
8975}
8976
8977
8978int ApiTestFuzzer::GetNextTestNumber() {
8979 int next_test;
8980 do {
8981 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8982 linear_congruential_generator *= 1664525u;
8983 linear_congruential_generator += 1013904223u;
8984 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8985 return next_test;
8986}
8987
8988
8989void ApiTestFuzzer::ContextSwitch() {
8990 // If the new thread is the same as the current thread there is nothing to do.
8991 if (NextThread()) {
8992 // Now it can start.
8993 v8::Unlocker unlocker;
8994 // Wait till someone starts us again.
8995 gate_->Wait();
8996 // And we're off.
8997 }
8998}
8999
9000
9001void ApiTestFuzzer::TearDown() {
9002 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009003 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9004 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9005 if (fuzzer != NULL) fuzzer->Join();
9006 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009007}
9008
9009
9010// Lets not be needlessly self-referential.
9011TEST(Threading) {
9012 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9013 ApiTestFuzzer::RunAllTests();
9014 ApiTestFuzzer::TearDown();
9015}
9016
9017TEST(Threading2) {
9018 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9019 ApiTestFuzzer::RunAllTests();
9020 ApiTestFuzzer::TearDown();
9021}
9022
9023
9024void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009025 if (kLogThreading)
9026 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009027 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009028 if (kLogThreading)
9029 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009030}
9031
9032
9033static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009034 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009035 ApiTestFuzzer::Fuzz();
9036 v8::Unlocker unlocker;
9037 const char* code = "throw 7;";
9038 {
9039 v8::Locker nested_locker;
9040 v8::HandleScope scope;
9041 v8::Handle<Value> exception;
9042 { v8::TryCatch try_catch;
9043 v8::Handle<Value> value = CompileRun(code);
9044 CHECK(value.IsEmpty());
9045 CHECK(try_catch.HasCaught());
9046 // Make sure to wrap the exception in a new handle because
9047 // the handle returned from the TryCatch is destroyed
9048 // when the TryCatch is destroyed.
9049 exception = Local<Value>::New(try_catch.Exception());
9050 }
9051 return v8::ThrowException(exception);
9052 }
9053}
9054
9055
9056static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009057 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009058 ApiTestFuzzer::Fuzz();
9059 v8::Unlocker unlocker;
9060 const char* code = "throw 7;";
9061 {
9062 v8::Locker nested_locker;
9063 v8::HandleScope scope;
9064 v8::Handle<Value> value = CompileRun(code);
9065 CHECK(value.IsEmpty());
9066 return v8_str("foo");
9067 }
9068}
9069
9070
9071// These are locking tests that don't need to be run again
9072// as part of the locking aggregation tests.
9073TEST(NestedLockers) {
9074 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009075 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009076 v8::HandleScope scope;
9077 LocalContext env;
9078 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9079 Local<Function> fun = fun_templ->GetFunction();
9080 env->Global()->Set(v8_str("throw_in_js"), fun);
9081 Local<Script> script = v8_compile("(function () {"
9082 " try {"
9083 " throw_in_js();"
9084 " return 42;"
9085 " } catch (e) {"
9086 " return e * 13;"
9087 " }"
9088 "})();");
9089 CHECK_EQ(91, script->Run()->Int32Value());
9090}
9091
9092
9093// These are locking tests that don't need to be run again
9094// as part of the locking aggregation tests.
9095TEST(NestedLockersNoTryCatch) {
9096 v8::Locker locker;
9097 v8::HandleScope scope;
9098 LocalContext env;
9099 Local<v8::FunctionTemplate> fun_templ =
9100 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9101 Local<Function> fun = fun_templ->GetFunction();
9102 env->Global()->Set(v8_str("throw_in_js"), fun);
9103 Local<Script> script = v8_compile("(function () {"
9104 " try {"
9105 " throw_in_js();"
9106 " return 42;"
9107 " } catch (e) {"
9108 " return e * 13;"
9109 " }"
9110 "})();");
9111 CHECK_EQ(91, script->Run()->Int32Value());
9112}
9113
9114
9115THREADED_TEST(RecursiveLocking) {
9116 v8::Locker locker;
9117 {
9118 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009119 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009120 }
9121}
9122
9123
9124static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9125 ApiTestFuzzer::Fuzz();
9126 v8::Unlocker unlocker;
9127 return v8::Undefined();
9128}
9129
9130
9131THREADED_TEST(LockUnlockLock) {
9132 {
9133 v8::Locker locker;
9134 v8::HandleScope scope;
9135 LocalContext env;
9136 Local<v8::FunctionTemplate> fun_templ =
9137 v8::FunctionTemplate::New(UnlockForAMoment);
9138 Local<Function> fun = fun_templ->GetFunction();
9139 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9140 Local<Script> script = v8_compile("(function () {"
9141 " unlock_for_a_moment();"
9142 " return 42;"
9143 "})();");
9144 CHECK_EQ(42, script->Run()->Int32Value());
9145 }
9146 {
9147 v8::Locker locker;
9148 v8::HandleScope scope;
9149 LocalContext env;
9150 Local<v8::FunctionTemplate> fun_templ =
9151 v8::FunctionTemplate::New(UnlockForAMoment);
9152 Local<Function> fun = fun_templ->GetFunction();
9153 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9154 Local<Script> script = v8_compile("(function () {"
9155 " unlock_for_a_moment();"
9156 " return 42;"
9157 "})();");
9158 CHECK_EQ(42, script->Run()->Int32Value());
9159 }
9160}
9161
9162
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009163static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009164 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009165 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009166 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9167 if (object->IsJSGlobalObject()) count++;
9168 return count;
9169}
9170
9171
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009172static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009173 // We need to collect all garbage twice to be sure that everything
9174 // has been collected. This is because inline caches are cleared in
9175 // the first garbage collection but some of the maps have already
9176 // been marked at that point. Therefore some of the maps are not
9177 // collected until the second garbage collection.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 HEAP->CollectAllGarbage(false);
9179 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009180 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009181#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009183#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009184 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009185}
9186
9187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009188TEST(DontLeakGlobalObjects) {
9189 // Regression test for issues 1139850 and 1174891.
9190
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009191 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009192
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009193 for (int i = 0; i < 5; i++) {
9194 { v8::HandleScope scope;
9195 LocalContext context;
9196 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009197 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009198
9199 { v8::HandleScope scope;
9200 LocalContext context;
9201 v8_compile("Date")->Run();
9202 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009203 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009204
9205 { v8::HandleScope scope;
9206 LocalContext context;
9207 v8_compile("/aaa/")->Run();
9208 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009209 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009210
9211 { v8::HandleScope scope;
9212 const char* extension_list[] = { "v8/gc" };
9213 v8::ExtensionConfiguration extensions(1, extension_list);
9214 LocalContext context(&extensions);
9215 v8_compile("gc();")->Run();
9216 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009217 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009218 }
9219}
9220
9221
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009222v8::Persistent<v8::Object> some_object;
9223v8::Persistent<v8::Object> bad_handle;
9224
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009225void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009226 v8::HandleScope scope;
9227 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009228 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009229}
9230
9231
9232THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9233 LocalContext context;
9234
9235 v8::Persistent<v8::Object> handle1, handle2;
9236 {
9237 v8::HandleScope scope;
9238 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9239 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9240 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9241 }
9242 // Note: order is implementation dependent alas: currently
9243 // global handle nodes are processed by PostGarbageCollectionProcessing
9244 // in reverse allocation order, so if second allocated handle is deleted,
9245 // weak callback of the first handle would be able to 'reallocate' it.
9246 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9247 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009249}
9250
9251
9252v8::Persistent<v8::Object> to_be_disposed;
9253
9254void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9255 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009256 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009257 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009258}
9259
9260
9261THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9262 LocalContext context;
9263
9264 v8::Persistent<v8::Object> handle1, handle2;
9265 {
9266 v8::HandleScope scope;
9267 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9268 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9269 }
9270 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9271 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009272 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009273}
9274
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009275void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9276 handle.Dispose();
9277}
9278
9279void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9280 v8::HandleScope scope;
9281 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009282 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009283}
9284
9285
9286THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9287 LocalContext context;
9288
9289 v8::Persistent<v8::Object> handle1, handle2, handle3;
9290 {
9291 v8::HandleScope scope;
9292 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9293 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9294 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9295 }
9296 handle2.MakeWeak(NULL, DisposingCallback);
9297 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009298 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009299}
9300
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009301
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009302THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009303 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009304
9305 const int nof = 2;
9306 const char* sources[nof] = {
9307 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9308 "Object()"
9309 };
9310
9311 for (int i = 0; i < nof; i++) {
9312 const char* source = sources[i];
9313 { v8::HandleScope scope;
9314 LocalContext context;
9315 CompileRun(source);
9316 }
9317 { v8::HandleScope scope;
9318 LocalContext context;
9319 CompileRun(source);
9320 }
9321 }
9322}
9323
9324
9325static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
9326 v8::HandleScope inner;
9327 env->Enter();
9328 v8::Handle<Value> three = v8_num(3);
9329 v8::Handle<Value> value = inner.Close(three);
9330 env->Exit();
9331 return value;
9332}
9333
9334
9335THREADED_TEST(NestedHandleScopeAndContexts) {
9336 v8::HandleScope outer;
9337 v8::Persistent<Context> env = Context::New();
9338 env->Enter();
9339 v8::Handle<Value> value = NestedScope(env);
9340 v8::Handle<String> str = value->ToString();
9341 env->Exit();
9342 env.Dispose();
9343}
9344
9345
9346THREADED_TEST(ExternalAllocatedMemory) {
9347 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009348 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009349 const int kSize = 1024*1024;
9350 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
9351 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
9352}
9353
9354
9355THREADED_TEST(DisposeEnteredContext) {
9356 v8::HandleScope scope;
9357 LocalContext outer;
9358 { v8::Persistent<v8::Context> inner = v8::Context::New();
9359 inner->Enter();
9360 inner.Dispose();
9361 inner.Clear();
9362 inner->Exit();
9363 }
9364}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009365
9366
9367// Regression test for issue 54, object templates with internal fields
9368// but no accessors or interceptors did not get their internal field
9369// count set on instances.
9370THREADED_TEST(Regress54) {
9371 v8::HandleScope outer;
9372 LocalContext context;
9373 static v8::Persistent<v8::ObjectTemplate> templ;
9374 if (templ.IsEmpty()) {
9375 v8::HandleScope inner;
9376 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
9377 local->SetInternalFieldCount(1);
9378 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
9379 }
9380 v8::Handle<v8::Object> result = templ->NewInstance();
9381 CHECK_EQ(1, result->InternalFieldCount());
9382}
9383
9384
9385// If part of the threaded tests, this test makes ThreadingTest fail
9386// on mac.
9387TEST(CatchStackOverflow) {
9388 v8::HandleScope scope;
9389 LocalContext context;
9390 v8::TryCatch try_catch;
9391 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
9392 "function f() {"
9393 " return f();"
9394 "}"
9395 ""
9396 "f();"));
9397 v8::Handle<v8::Value> result = script->Run();
9398 CHECK(result.IsEmpty());
9399}
9400
9401
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009402static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
9403 const char* resource_name,
9404 int line_offset) {
9405 v8::HandleScope scope;
9406 v8::TryCatch try_catch;
9407 v8::Handle<v8::Value> result = script->Run();
9408 CHECK(result.IsEmpty());
9409 CHECK(try_catch.HasCaught());
9410 v8::Handle<v8::Message> message = try_catch.Message();
9411 CHECK(!message.IsEmpty());
9412 CHECK_EQ(10 + line_offset, message->GetLineNumber());
9413 CHECK_EQ(91, message->GetStartPosition());
9414 CHECK_EQ(92, message->GetEndPosition());
9415 CHECK_EQ(2, message->GetStartColumn());
9416 CHECK_EQ(3, message->GetEndColumn());
9417 v8::String::AsciiValue line(message->GetSourceLine());
9418 CHECK_EQ(" throw 'nirk';", *line);
9419 v8::String::AsciiValue name(message->GetScriptResourceName());
9420 CHECK_EQ(resource_name, *name);
9421}
9422
9423
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009424THREADED_TEST(TryCatchSourceInfo) {
9425 v8::HandleScope scope;
9426 LocalContext context;
9427 v8::Handle<v8::String> source = v8::String::New(
9428 "function Foo() {\n"
9429 " return Bar();\n"
9430 "}\n"
9431 "\n"
9432 "function Bar() {\n"
9433 " return Baz();\n"
9434 "}\n"
9435 "\n"
9436 "function Baz() {\n"
9437 " throw 'nirk';\n"
9438 "}\n"
9439 "\n"
9440 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009441
9442 const char* resource_name;
9443 v8::Handle<v8::Script> script;
9444 resource_name = "test.js";
9445 script = v8::Script::Compile(source, v8::String::New(resource_name));
9446 CheckTryCatchSourceInfo(script, resource_name, 0);
9447
9448 resource_name = "test1.js";
9449 v8::ScriptOrigin origin1(v8::String::New(resource_name));
9450 script = v8::Script::Compile(source, &origin1);
9451 CheckTryCatchSourceInfo(script, resource_name, 0);
9452
9453 resource_name = "test2.js";
9454 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
9455 script = v8::Script::Compile(source, &origin2);
9456 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009457}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009458
9459
9460THREADED_TEST(CompilationCache) {
9461 v8::HandleScope scope;
9462 LocalContext context;
9463 v8::Handle<v8::String> source0 = v8::String::New("1234");
9464 v8::Handle<v8::String> source1 = v8::String::New("1234");
9465 v8::Handle<v8::Script> script0 =
9466 v8::Script::Compile(source0, v8::String::New("test.js"));
9467 v8::Handle<v8::Script> script1 =
9468 v8::Script::Compile(source1, v8::String::New("test.js"));
9469 v8::Handle<v8::Script> script2 =
9470 v8::Script::Compile(source0); // different origin
9471 CHECK_EQ(1234, script0->Run()->Int32Value());
9472 CHECK_EQ(1234, script1->Run()->Int32Value());
9473 CHECK_EQ(1234, script2->Run()->Int32Value());
9474}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00009475
9476
9477static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
9478 ApiTestFuzzer::Fuzz();
9479 return v8_num(42);
9480}
9481
9482
9483THREADED_TEST(CallbackFunctionName) {
9484 v8::HandleScope scope;
9485 LocalContext context;
9486 Local<ObjectTemplate> t = ObjectTemplate::New();
9487 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
9488 context->Global()->Set(v8_str("obj"), t->NewInstance());
9489 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
9490 CHECK(value->IsString());
9491 v8::String::AsciiValue name(value);
9492 CHECK_EQ("asdf", *name);
9493}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009494
9495
9496THREADED_TEST(DateAccess) {
9497 v8::HandleScope scope;
9498 LocalContext context;
9499 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
9500 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009501 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009502}
9503
9504
9505void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009506 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009507 v8::Handle<v8::Array> props = obj->GetPropertyNames();
9508 CHECK_EQ(elmc, props->Length());
9509 for (int i = 0; i < elmc; i++) {
9510 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
9511 CHECK_EQ(elmv[i], *elm);
9512 }
9513}
9514
9515
9516THREADED_TEST(PropertyEnumeration) {
9517 v8::HandleScope scope;
9518 LocalContext context;
9519 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9520 "var result = [];"
9521 "result[0] = {};"
9522 "result[1] = {a: 1, b: 2};"
9523 "result[2] = [1, 2, 3];"
9524 "var proto = {x: 1, y: 2, z: 3};"
9525 "var x = { __proto__: proto, w: 0, z: 1 };"
9526 "result[3] = x;"
9527 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009528 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009529 CHECK_EQ(4, elms->Length());
9530 int elmc0 = 0;
9531 const char** elmv0 = NULL;
9532 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9533 int elmc1 = 2;
9534 const char* elmv1[] = {"a", "b"};
9535 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
9536 int elmc2 = 3;
9537 const char* elmv2[] = {"0", "1", "2"};
9538 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
9539 int elmc3 = 4;
9540 const char* elmv3[] = {"w", "z", "x", "y"};
9541 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
9542}
ager@chromium.org870a0b62008-11-04 11:43:05 +00009543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544THREADED_TEST(PropertyEnumeration2) {
9545 v8::HandleScope scope;
9546 LocalContext context;
9547 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9548 "var result = [];"
9549 "result[0] = {};"
9550 "result[1] = {a: 1, b: 2};"
9551 "result[2] = [1, 2, 3];"
9552 "var proto = {x: 1, y: 2, z: 3};"
9553 "var x = { __proto__: proto, w: 0, z: 1 };"
9554 "result[3] = x;"
9555 "result;"))->Run();
9556 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9557 CHECK_EQ(4, elms->Length());
9558 int elmc0 = 0;
9559 const char** elmv0 = NULL;
9560 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9561
9562 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
9563 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
9564 CHECK_EQ(0, props->Length());
9565 for (uint32_t i = 0; i < props->Length(); i++) {
9566 printf("p[%d]\n", i);
9567 }
9568}
ager@chromium.org870a0b62008-11-04 11:43:05 +00009569
ager@chromium.org870a0b62008-11-04 11:43:05 +00009570static bool NamedSetAccessBlocker(Local<v8::Object> obj,
9571 Local<Value> name,
9572 v8::AccessType type,
9573 Local<Value> data) {
9574 return type != v8::ACCESS_SET;
9575}
9576
9577
9578static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
9579 uint32_t key,
9580 v8::AccessType type,
9581 Local<Value> data) {
9582 return type != v8::ACCESS_SET;
9583}
9584
9585
9586THREADED_TEST(DisableAccessChecksWhileConfiguring) {
9587 v8::HandleScope scope;
9588 LocalContext context;
9589 Local<ObjectTemplate> templ = ObjectTemplate::New();
9590 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9591 IndexedSetAccessBlocker);
9592 templ->Set(v8_str("x"), v8::True());
9593 Local<v8::Object> instance = templ->NewInstance();
9594 context->Global()->Set(v8_str("obj"), instance);
9595 Local<Value> value = CompileRun("obj.x");
9596 CHECK(value->BooleanValue());
9597}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009598
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009599
ager@chromium.org32912102009-01-16 10:38:43 +00009600static bool NamedGetAccessBlocker(Local<v8::Object> obj,
9601 Local<Value> name,
9602 v8::AccessType type,
9603 Local<Value> data) {
9604 return false;
9605}
9606
9607
9608static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
9609 uint32_t key,
9610 v8::AccessType type,
9611 Local<Value> data) {
9612 return false;
9613}
9614
9615
9616
9617THREADED_TEST(AccessChecksReenabledCorrectly) {
9618 v8::HandleScope scope;
9619 LocalContext context;
9620 Local<ObjectTemplate> templ = ObjectTemplate::New();
9621 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9622 IndexedGetAccessBlocker);
9623 templ->Set(v8_str("a"), v8_str("a"));
9624 // Add more than 8 (see kMaxFastProperties) properties
9625 // so that the constructor will force copying map.
9626 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009627 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00009628 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009629 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00009630 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009631 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00009632 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009633 buf[2] = k;
9634 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00009635 templ->Set(v8_str(buf), v8::Number::New(k));
9636 }
9637 }
9638 }
9639
9640 Local<v8::Object> instance_1 = templ->NewInstance();
9641 context->Global()->Set(v8_str("obj_1"), instance_1);
9642
9643 Local<Value> value_1 = CompileRun("obj_1.a");
9644 CHECK(value_1->IsUndefined());
9645
9646 Local<v8::Object> instance_2 = templ->NewInstance();
9647 context->Global()->Set(v8_str("obj_2"), instance_2);
9648
9649 Local<Value> value_2 = CompileRun("obj_2.a");
9650 CHECK(value_2->IsUndefined());
9651}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009652
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009653
ager@chromium.org8bb60582008-12-11 12:02:20 +00009654// This tests that access check information remains on the global
9655// object template when creating contexts.
9656THREADED_TEST(AccessControlRepeatedContextCreation) {
9657 v8::HandleScope handle_scope;
9658 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9659 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9660 IndexedSetAccessBlocker);
9661 i::Handle<i::ObjectTemplateInfo> internal_template =
9662 v8::Utils::OpenHandle(*global_template);
9663 CHECK(!internal_template->constructor()->IsUndefined());
9664 i::Handle<i::FunctionTemplateInfo> constructor(
9665 i::FunctionTemplateInfo::cast(internal_template->constructor()));
9666 CHECK(!constructor->access_check_info()->IsUndefined());
9667 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
9668 CHECK(!constructor->access_check_info()->IsUndefined());
9669}
9670
9671
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009672THREADED_TEST(TurnOnAccessCheck) {
9673 v8::HandleScope handle_scope;
9674
9675 // Create an environment with access check to the global object disabled by
9676 // default.
9677 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9678 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
9679 IndexedGetAccessBlocker,
9680 v8::Handle<v8::Value>(),
9681 false);
9682 v8::Persistent<Context> context = Context::New(NULL, global_template);
9683 Context::Scope context_scope(context);
9684
9685 // Set up a property and a number of functions.
9686 context->Global()->Set(v8_str("a"), v8_num(1));
9687 CompileRun("function f1() {return a;}"
9688 "function f2() {return a;}"
9689 "function g1() {return h();}"
9690 "function g2() {return h();}"
9691 "function h() {return 1;}");
9692 Local<Function> f1 =
9693 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9694 Local<Function> f2 =
9695 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9696 Local<Function> g1 =
9697 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9698 Local<Function> g2 =
9699 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9700 Local<Function> h =
9701 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9702
9703 // Get the global object.
9704 v8::Handle<v8::Object> global = context->Global();
9705
9706 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9707 // uses the runtime system to retreive property a whereas f2 uses global load
9708 // inline cache.
9709 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9710 for (int i = 0; i < 4; i++) {
9711 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9712 }
9713
9714 // Same for g1 and g2.
9715 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9716 for (int i = 0; i < 4; i++) {
9717 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9718 }
9719
9720 // Detach the global and turn on access check.
9721 context->DetachGlobal();
9722 context->Global()->TurnOnAccessCheck();
9723
9724 // Failing access check to property get results in undefined.
9725 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9726 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9727
9728 // Failing access check to function call results in exception.
9729 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9730 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9731
9732 // No failing access check when just returning a constant.
9733 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9734}
9735
9736
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009737v8::Handle<v8::String> a;
9738v8::Handle<v8::String> h;
9739
9740static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
9741 Local<Value> name,
9742 v8::AccessType type,
9743 Local<Value> data) {
9744 return !(name->Equals(a) || name->Equals(h));
9745}
9746
9747
9748THREADED_TEST(TurnOnAccessCheckAndRecompile) {
9749 v8::HandleScope handle_scope;
9750
9751 // Create an environment with access check to the global object disabled by
9752 // default. When the registered access checker will block access to properties
9753 // a and h
9754 a = v8_str("a");
9755 h = v8_str("h");
9756 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
9757 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
9758 IndexedGetAccessBlocker,
9759 v8::Handle<v8::Value>(),
9760 false);
9761 v8::Persistent<Context> context = Context::New(NULL, global_template);
9762 Context::Scope context_scope(context);
9763
9764 // Set up a property and a number of functions.
9765 context->Global()->Set(v8_str("a"), v8_num(1));
9766 static const char* source = "function f1() {return a;}"
9767 "function f2() {return a;}"
9768 "function g1() {return h();}"
9769 "function g2() {return h();}"
9770 "function h() {return 1;}";
9771
9772 CompileRun(source);
9773 Local<Function> f1;
9774 Local<Function> f2;
9775 Local<Function> g1;
9776 Local<Function> g2;
9777 Local<Function> h;
9778 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9779 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9780 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9781 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9782 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
9783
9784 // Get the global object.
9785 v8::Handle<v8::Object> global = context->Global();
9786
9787 // Call f1 one time and f2 a number of times. This will ensure that f1 still
9788 // uses the runtime system to retreive property a whereas f2 uses global load
9789 // inline cache.
9790 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
9791 for (int i = 0; i < 4; i++) {
9792 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
9793 }
9794
9795 // Same for g1 and g2.
9796 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
9797 for (int i = 0; i < 4; i++) {
9798 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
9799 }
9800
9801 // Detach the global and turn on access check now blocking access to property
9802 // a and function h.
9803 context->DetachGlobal();
9804 context->Global()->TurnOnAccessCheck();
9805
9806 // Failing access check to property get results in undefined.
9807 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9808 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9809
9810 // Failing access check to function call results in exception.
9811 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9812 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9813
9814 // No failing access check when just returning a constant.
9815 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
9816
9817 // Now compile the source again. And get the newly compiled functions, except
9818 // for h for which access is blocked.
9819 CompileRun(source);
9820 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
9821 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
9822 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
9823 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
9824 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
9825
9826 // Failing access check to property get results in undefined.
9827 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
9828 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
9829
9830 // Failing access check to function call results in exception.
9831 CHECK(g1->Call(global, 0, NULL).IsEmpty());
9832 CHECK(g2->Call(global, 0, NULL).IsEmpty());
9833}
9834
9835
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009836// This test verifies that pre-compilation (aka preparsing) can be called
9837// without initializing the whole VM. Thus we cannot run this test in a
9838// multi-threaded setup.
9839TEST(PreCompile) {
9840 // TODO(155): This test would break without the initialization of V8. This is
9841 // a workaround for now to make this test not fail.
9842 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009843 const char* script = "function foo(a) { return a+1; }";
9844 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009845 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009846 CHECK_NE(sd->Length(), 0);
9847 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009848 CHECK(!sd->HasError());
9849 delete sd;
9850}
9851
9852
9853TEST(PreCompileWithError) {
9854 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009855 const char* script = "function foo(a) { return 1 * * 2; }";
9856 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009857 v8::ScriptData::PreCompile(script, i::StrLength(script));
9858 CHECK(sd->HasError());
9859 delete sd;
9860}
9861
9862
9863TEST(Regress31661) {
9864 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009865 const char* script = " The Definintive Guide";
9866 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009867 v8::ScriptData::PreCompile(script, i::StrLength(script));
9868 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009869 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009870}
9871
9872
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009873// Tests that ScriptData can be serialized and deserialized.
9874TEST(PreCompileSerialization) {
9875 v8::V8::Initialize();
9876 const char* script = "function foo(a) { return a+1; }";
9877 v8::ScriptData* sd =
9878 v8::ScriptData::PreCompile(script, i::StrLength(script));
9879
9880 // Serialize.
9881 int serialized_data_length = sd->Length();
9882 char* serialized_data = i::NewArray<char>(serialized_data_length);
9883 memcpy(serialized_data, sd->Data(), serialized_data_length);
9884
9885 // Deserialize.
9886 v8::ScriptData* deserialized_sd =
9887 v8::ScriptData::New(serialized_data, serialized_data_length);
9888
9889 // Verify that the original is the same as the deserialized.
9890 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9891 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9892 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9893
9894 delete sd;
9895 delete deserialized_sd;
9896}
9897
9898
9899// Attempts to deserialize bad data.
9900TEST(PreCompileDeserializationError) {
9901 v8::V8::Initialize();
9902 const char* data = "DONT CARE";
9903 int invalid_size = 3;
9904 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9905
9906 CHECK_EQ(0, sd->Length());
9907
9908 delete sd;
9909}
9910
9911
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009912// Attempts to deserialize bad data.
9913TEST(PreCompileInvalidPreparseDataError) {
9914 v8::V8::Initialize();
9915 v8::HandleScope scope;
9916 LocalContext context;
9917
9918 const char* script = "function foo(){ return 5;}\n"
9919 "function bar(){ return 6 + 7;} foo();";
9920 v8::ScriptData* sd =
9921 v8::ScriptData::PreCompile(script, i::StrLength(script));
9922 CHECK(!sd->HasError());
9923 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009924 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009925 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009926 const int kFunctionEntryStartOffset = 0;
9927 const int kFunctionEntryEndOffset = 1;
9928 unsigned* sd_data =
9929 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009930
9931 // Overwrite function bar's end position with 0.
9932 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9933 v8::TryCatch try_catch;
9934
9935 Local<String> source = String::New(script);
9936 Local<Script> compiled_script = Script::New(source, NULL, sd);
9937 CHECK(try_catch.HasCaught());
9938 String::AsciiValue exception_value(try_catch.Message()->Get());
9939 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9940 *exception_value);
9941
9942 try_catch.Reset();
9943 // Overwrite function bar's start position with 200. The function entry
9944 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009945 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9946 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00009947 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9948 200;
9949 compiled_script = Script::New(source, NULL, sd);
9950 CHECK(try_catch.HasCaught());
9951 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9952 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9953 *second_exception_value);
9954
9955 delete sd;
9956}
9957
9958
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009959// Verifies that the Handle<String> and const char* versions of the API produce
9960// the same results (at least for one trivial case).
9961TEST(PreCompileAPIVariationsAreSame) {
9962 v8::V8::Initialize();
9963 v8::HandleScope scope;
9964
9965 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009966
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009967 v8::ScriptData* sd_from_cstring =
9968 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9969
9970 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009971 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009972 v8::String::NewExternal(resource));
9973
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009974 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9975 v8::String::New(cstring));
9976
9977 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009978 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009979 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009980 sd_from_cstring->Length()));
9981
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009982 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9983 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9984 sd_from_string->Data(),
9985 sd_from_cstring->Length()));
9986
9987
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009988 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009989 delete sd_from_external_string;
9990 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009991}
9992
9993
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009994// This tests that we do not allow dictionary load/call inline caches
9995// to use functions that have not yet been compiled. The potential
9996// problem of loading a function that has not yet been compiled can
9997// arise because we share code between contexts via the compilation
9998// cache.
9999THREADED_TEST(DictionaryICLoadedFunction) {
10000 v8::HandleScope scope;
10001 // Test LoadIC.
10002 for (int i = 0; i < 2; i++) {
10003 LocalContext context;
10004 context->Global()->Set(v8_str("tmp"), v8::True());
10005 context->Global()->Delete(v8_str("tmp"));
10006 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10007 }
10008 // Test CallIC.
10009 for (int i = 0; i < 2; i++) {
10010 LocalContext context;
10011 context->Global()->Set(v8_str("tmp"), v8::True());
10012 context->Global()->Delete(v8_str("tmp"));
10013 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10014 }
10015}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010016
10017
10018// Test that cross-context new calls use the context of the callee to
10019// create the new JavaScript object.
10020THREADED_TEST(CrossContextNew) {
10021 v8::HandleScope scope;
10022 v8::Persistent<Context> context0 = Context::New();
10023 v8::Persistent<Context> context1 = Context::New();
10024
10025 // Allow cross-domain access.
10026 Local<String> token = v8_str("<security token>");
10027 context0->SetSecurityToken(token);
10028 context1->SetSecurityToken(token);
10029
10030 // Set an 'x' property on the Object prototype and define a
10031 // constructor function in context0.
10032 context0->Enter();
10033 CompileRun("Object.prototype.x = 42; function C() {};");
10034 context0->Exit();
10035
10036 // Call the constructor function from context0 and check that the
10037 // result has the 'x' property.
10038 context1->Enter();
10039 context1->Global()->Set(v8_str("other"), context0->Global());
10040 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10041 CHECK(value->IsInt32());
10042 CHECK_EQ(42, value->Int32Value());
10043 context1->Exit();
10044
10045 // Dispose the contexts to allow them to be garbage collected.
10046 context0.Dispose();
10047 context1.Dispose();
10048}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010049
10050
10051class RegExpInterruptTest {
10052 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010053 RegExpInterruptTest() : block_(NULL) {}
10054 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010055 void RunTest() {
10056 block_ = i::OS::CreateSemaphore(0);
10057 gc_count_ = 0;
10058 gc_during_regexp_ = 0;
10059 regexp_success_ = false;
10060 gc_success_ = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 GCThread gc_thread(i::Isolate::Current(), this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010062 gc_thread.Start();
10063 v8::Locker::StartPreemption(1);
10064
10065 LongRunningRegExp();
10066 {
10067 v8::Unlocker unlock;
10068 gc_thread.Join();
10069 }
10070 v8::Locker::StopPreemption();
10071 CHECK(regexp_success_);
10072 CHECK(gc_success_);
10073 }
10074 private:
10075 // Number of garbage collections required.
10076 static const int kRequiredGCs = 5;
10077
10078 class GCThread : public i::Thread {
10079 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010080 explicit GCThread(i::Isolate* isolate, RegExpInterruptTest* test)
10081 : Thread(isolate, "GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010082 virtual void Run() {
10083 test_->CollectGarbage();
10084 }
10085 private:
10086 RegExpInterruptTest* test_;
10087 };
10088
10089 void CollectGarbage() {
10090 block_->Wait();
10091 while (gc_during_regexp_ < kRequiredGCs) {
10092 {
10093 v8::Locker lock;
10094 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010096 gc_count_++;
10097 }
10098 i::OS::Sleep(1);
10099 }
10100 gc_success_ = true;
10101 }
10102
10103 void LongRunningRegExp() {
10104 block_->Signal(); // Enable garbage collection thread on next preemption.
10105 int rounds = 0;
10106 while (gc_during_regexp_ < kRequiredGCs) {
10107 int gc_before = gc_count_;
10108 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010109 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010110 const char* c_source =
10111 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10112 ".exec('aaaaaaaaaaaaaaab') === null";
10113 Local<String> source = String::New(c_source);
10114 Local<Script> script = Script::Compile(source);
10115 Local<Value> result = script->Run();
10116 if (!result->BooleanValue()) {
10117 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10118 return;
10119 }
10120 }
10121 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010122 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010123 const char* c_source =
10124 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10125 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10126 Local<String> source = String::New(c_source);
10127 Local<Script> script = Script::Compile(source);
10128 Local<Value> result = script->Run();
10129 if (!result->BooleanValue()) {
10130 gc_during_regexp_ = kRequiredGCs;
10131 return;
10132 }
10133 }
10134 int gc_after = gc_count_;
10135 gc_during_regexp_ += gc_after - gc_before;
10136 rounds++;
10137 i::OS::Sleep(1);
10138 }
10139 regexp_success_ = true;
10140 }
10141
10142 i::Semaphore* block_;
10143 int gc_count_;
10144 int gc_during_regexp_;
10145 bool regexp_success_;
10146 bool gc_success_;
10147};
10148
10149
10150// Test that a regular expression execution can be interrupted and
10151// survive a garbage collection.
10152TEST(RegExpInterruption) {
10153 v8::Locker lock;
10154 v8::V8::Initialize();
10155 v8::HandleScope scope;
10156 Local<Context> local_env;
10157 {
10158 LocalContext env;
10159 local_env = env.local();
10160 }
10161
10162 // Local context should still be live.
10163 CHECK(!local_env.IsEmpty());
10164 local_env->Enter();
10165
10166 // Should complete without problems.
10167 RegExpInterruptTest().RunTest();
10168
10169 local_env->Exit();
10170}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010171
10172
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010173class ApplyInterruptTest {
10174 public:
10175 ApplyInterruptTest() : block_(NULL) {}
10176 ~ApplyInterruptTest() { delete block_; }
10177 void RunTest() {
10178 block_ = i::OS::CreateSemaphore(0);
10179 gc_count_ = 0;
10180 gc_during_apply_ = 0;
10181 apply_success_ = false;
10182 gc_success_ = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010183 GCThread gc_thread(i::Isolate::Current(), this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010184 gc_thread.Start();
10185 v8::Locker::StartPreemption(1);
10186
10187 LongRunningApply();
10188 {
10189 v8::Unlocker unlock;
10190 gc_thread.Join();
10191 }
10192 v8::Locker::StopPreemption();
10193 CHECK(apply_success_);
10194 CHECK(gc_success_);
10195 }
10196 private:
10197 // Number of garbage collections required.
10198 static const int kRequiredGCs = 2;
10199
10200 class GCThread : public i::Thread {
10201 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 explicit GCThread(i::Isolate* isolate, ApplyInterruptTest* test)
10203 : Thread(isolate, "GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010204 virtual void Run() {
10205 test_->CollectGarbage();
10206 }
10207 private:
10208 ApplyInterruptTest* test_;
10209 };
10210
10211 void CollectGarbage() {
10212 block_->Wait();
10213 while (gc_during_apply_ < kRequiredGCs) {
10214 {
10215 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010217 gc_count_++;
10218 }
10219 i::OS::Sleep(1);
10220 }
10221 gc_success_ = true;
10222 }
10223
10224 void LongRunningApply() {
10225 block_->Signal();
10226 int rounds = 0;
10227 while (gc_during_apply_ < kRequiredGCs) {
10228 int gc_before = gc_count_;
10229 {
10230 const char* c_source =
10231 "function do_very_little(bar) {"
10232 " this.foo = bar;"
10233 "}"
10234 "for (var i = 0; i < 100000; i++) {"
10235 " do_very_little.apply(this, ['bar']);"
10236 "}";
10237 Local<String> source = String::New(c_source);
10238 Local<Script> script = Script::Compile(source);
10239 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010240 // Check that no exception was thrown.
10241 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010242 }
10243 int gc_after = gc_count_;
10244 gc_during_apply_ += gc_after - gc_before;
10245 rounds++;
10246 }
10247 apply_success_ = true;
10248 }
10249
10250 i::Semaphore* block_;
10251 int gc_count_;
10252 int gc_during_apply_;
10253 bool apply_success_;
10254 bool gc_success_;
10255};
10256
10257
10258// Test that nothing bad happens if we get a preemption just when we were
10259// about to do an apply().
10260TEST(ApplyInterruption) {
10261 v8::Locker lock;
10262 v8::V8::Initialize();
10263 v8::HandleScope scope;
10264 Local<Context> local_env;
10265 {
10266 LocalContext env;
10267 local_env = env.local();
10268 }
10269
10270 // Local context should still be live.
10271 CHECK(!local_env.IsEmpty());
10272 local_env->Enter();
10273
10274 // Should complete without problems.
10275 ApplyInterruptTest().RunTest();
10276
10277 local_env->Exit();
10278}
10279
10280
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010281// Verify that we can clone an object
10282TEST(ObjectClone) {
10283 v8::HandleScope scope;
10284 LocalContext env;
10285
10286 const char* sample =
10287 "var rv = {};" \
10288 "rv.alpha = 'hello';" \
10289 "rv.beta = 123;" \
10290 "rv;";
10291
10292 // Create an object, verify basics.
10293 Local<Value> val = CompileRun(sample);
10294 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010295 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010296 obj->Set(v8_str("gamma"), v8_str("cloneme"));
10297
10298 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
10299 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10300 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
10301
10302 // Clone it.
10303 Local<v8::Object> clone = obj->Clone();
10304 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
10305 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
10306 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
10307
10308 // Set a property on the clone, verify each object.
10309 clone->Set(v8_str("beta"), v8::Integer::New(456));
10310 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10311 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
10312}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010313
10314
ager@chromium.org5ec48922009-05-05 07:25:34 +000010315class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
10316 public:
10317 explicit AsciiVectorResource(i::Vector<const char> vector)
10318 : data_(vector) {}
10319 virtual ~AsciiVectorResource() {}
10320 virtual size_t length() const { return data_.length(); }
10321 virtual const char* data() const { return data_.start(); }
10322 private:
10323 i::Vector<const char> data_;
10324};
10325
10326
10327class UC16VectorResource : public v8::String::ExternalStringResource {
10328 public:
10329 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
10330 : data_(vector) {}
10331 virtual ~UC16VectorResource() {}
10332 virtual size_t length() const { return data_.length(); }
10333 virtual const i::uc16* data() const { return data_.start(); }
10334 private:
10335 i::Vector<const i::uc16> data_;
10336};
10337
10338
10339static void MorphAString(i::String* string,
10340 AsciiVectorResource* ascii_resource,
10341 UC16VectorResource* uc16_resource) {
10342 CHECK(i::StringShape(string).IsExternal());
10343 if (string->IsAsciiRepresentation()) {
10344 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010346 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010348 i::ExternalTwoByteString* morphed =
10349 i::ExternalTwoByteString::cast(string);
10350 morphed->set_resource(uc16_resource);
10351 } else {
10352 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010353 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010354 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010356 i::ExternalAsciiString* morphed =
10357 i::ExternalAsciiString::cast(string);
10358 morphed->set_resource(ascii_resource);
10359 }
10360}
10361
10362
10363// Test that we can still flatten a string if the components it is built up
10364// from have been turned into 16 bit strings in the mean time.
10365THREADED_TEST(MorphCompositeStringTest) {
10366 const char* c_string = "Now is the time for all good men"
10367 " to come to the aid of the party";
10368 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
10369 {
10370 v8::HandleScope scope;
10371 LocalContext env;
10372 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010373 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010374 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010375 i::Vector<const uint16_t>(two_byte_string,
10376 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010377
10378 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010379 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010380 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010382
10383 env->Global()->Set(v8_str("lhs"), lhs);
10384 env->Global()->Set(v8_str("rhs"), rhs);
10385
10386 CompileRun(
10387 "var cons = lhs + rhs;"
10388 "var slice = lhs.substring(1, lhs.length - 1);"
10389 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
10390
10391 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
10392 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
10393
10394 // Now do some stuff to make sure the strings are flattened, etc.
10395 CompileRun(
10396 "/[^a-z]/.test(cons);"
10397 "/[^a-z]/.test(slice);"
10398 "/[^a-z]/.test(slice_on_cons);");
10399 const char* expected_cons =
10400 "Now is the time for all good men to come to the aid of the party"
10401 "Now is the time for all good men to come to the aid of the party";
10402 const char* expected_slice =
10403 "ow is the time for all good men to come to the aid of the part";
10404 const char* expected_slice_on_cons =
10405 "ow is the time for all good men to come to the aid of the party"
10406 "Now is the time for all good men to come to the aid of the part";
10407 CHECK_EQ(String::New(expected_cons),
10408 env->Global()->Get(v8_str("cons")));
10409 CHECK_EQ(String::New(expected_slice),
10410 env->Global()->Get(v8_str("slice")));
10411 CHECK_EQ(String::New(expected_slice_on_cons),
10412 env->Global()->Get(v8_str("slice_on_cons")));
10413 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010414 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010415}
10416
10417
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010418TEST(CompileExternalTwoByteSource) {
10419 v8::HandleScope scope;
10420 LocalContext context;
10421
10422 // This is a very short list of sources, which currently is to check for a
10423 // regression caused by r2703.
10424 const char* ascii_sources[] = {
10425 "0.5",
10426 "-0.5", // This mainly testes PushBack in the Scanner.
10427 "--0.5", // This mainly testes PushBack in the Scanner.
10428 NULL
10429 };
10430
10431 // Compile the sources as external two byte strings.
10432 for (int i = 0; ascii_sources[i] != NULL; i++) {
10433 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
10434 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010435 i::Vector<const uint16_t>(two_byte_string,
10436 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010437 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
10438 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010439 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010440 }
10441}
10442
10443
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010444class RegExpStringModificationTest {
10445 public:
10446 RegExpStringModificationTest()
10447 : block_(i::OS::CreateSemaphore(0)),
10448 morphs_(0),
10449 morphs_during_regexp_(0),
10450 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
10451 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
10452 ~RegExpStringModificationTest() { delete block_; }
10453 void RunTest() {
10454 regexp_success_ = false;
10455 morph_success_ = false;
10456
10457 // Initialize the contents of two_byte_content_ to be a uc16 representation
10458 // of "aaaaaaaaaaaaaab".
10459 for (int i = 0; i < 14; i++) {
10460 two_byte_content_[i] = 'a';
10461 }
10462 two_byte_content_[14] = 'b';
10463
10464 // Create the input string for the regexp - the one we are going to change
10465 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010466 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010467
10468 // Inject the input as a global variable.
10469 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
10471 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010472 *input_name,
10473 *input_,
10474 NONE,
10475 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 MorphThread morph_thread(i::Isolate::Current(), this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010478 morph_thread.Start();
10479 v8::Locker::StartPreemption(1);
10480 LongRunningRegExp();
10481 {
10482 v8::Unlocker unlock;
10483 morph_thread.Join();
10484 }
10485 v8::Locker::StopPreemption();
10486 CHECK(regexp_success_);
10487 CHECK(morph_success_);
10488 }
10489 private:
10490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010491 // Number of string modifications required.
10492 static const int kRequiredModifications = 5;
10493 static const int kMaxModifications = 100;
10494
10495 class MorphThread : public i::Thread {
10496 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 explicit MorphThread(i::Isolate* isolate,
10498 RegExpStringModificationTest* test)
10499 : Thread(isolate, "MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010500 virtual void Run() {
10501 test_->MorphString();
10502 }
10503 private:
10504 RegExpStringModificationTest* test_;
10505 };
10506
10507 void MorphString() {
10508 block_->Wait();
10509 while (morphs_during_regexp_ < kRequiredModifications &&
10510 morphs_ < kMaxModifications) {
10511 {
10512 v8::Locker lock;
10513 // Swap string between ascii and two-byte representation.
10514 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000010515 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010516 morphs_++;
10517 }
10518 i::OS::Sleep(1);
10519 }
10520 morph_success_ = true;
10521 }
10522
10523 void LongRunningRegExp() {
10524 block_->Signal(); // Enable morphing thread on next preemption.
10525 while (morphs_during_regexp_ < kRequiredModifications &&
10526 morphs_ < kMaxModifications) {
10527 int morphs_before = morphs_;
10528 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000010529 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010530 // Match 15-30 "a"'s against 14 and a "b".
10531 const char* c_source =
10532 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10533 ".exec(input) === null";
10534 Local<String> source = String::New(c_source);
10535 Local<Script> script = Script::Compile(source);
10536 Local<Value> result = script->Run();
10537 CHECK(result->IsTrue());
10538 }
10539 int morphs_after = morphs_;
10540 morphs_during_regexp_ += morphs_after - morphs_before;
10541 }
10542 regexp_success_ = true;
10543 }
10544
10545 i::uc16 two_byte_content_[15];
10546 i::Semaphore* block_;
10547 int morphs_;
10548 int morphs_during_regexp_;
10549 bool regexp_success_;
10550 bool morph_success_;
10551 i::Handle<i::String> input_;
10552 AsciiVectorResource ascii_resource_;
10553 UC16VectorResource uc16_resource_;
10554};
10555
10556
10557// Test that a regular expression execution can be interrupted and
10558// the string changed without failing.
10559TEST(RegExpStringModification) {
10560 v8::Locker lock;
10561 v8::V8::Initialize();
10562 v8::HandleScope scope;
10563 Local<Context> local_env;
10564 {
10565 LocalContext env;
10566 local_env = env.local();
10567 }
10568
10569 // Local context should still be live.
10570 CHECK(!local_env.IsEmpty());
10571 local_env->Enter();
10572
10573 // Should complete without problems.
10574 RegExpStringModificationTest().RunTest();
10575
10576 local_env->Exit();
10577}
10578
10579
10580// Test that we can set a property on the global object even if there
10581// is a read-only property in the prototype chain.
10582TEST(ReadOnlyPropertyInGlobalProto) {
10583 v8::HandleScope scope;
10584 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10585 LocalContext context(0, templ);
10586 v8::Handle<v8::Object> global = context->Global();
10587 v8::Handle<v8::Object> global_proto =
10588 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
10589 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
10590 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
10591 // Check without 'eval' or 'with'.
10592 v8::Handle<v8::Value> res =
10593 CompileRun("function f() { x = 42; return x; }; f()");
10594 // Check with 'eval'.
10595 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
10596 CHECK_EQ(v8::Integer::New(42), res);
10597 // Check with 'with'.
10598 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
10599 CHECK_EQ(v8::Integer::New(42), res);
10600}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010601
10602static int force_set_set_count = 0;
10603static int force_set_get_count = 0;
10604bool pass_on_get = false;
10605
10606static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
10607 const v8::AccessorInfo& info) {
10608 force_set_get_count++;
10609 if (pass_on_get) {
10610 return v8::Handle<v8::Value>();
10611 } else {
10612 return v8::Int32::New(3);
10613 }
10614}
10615
10616static void ForceSetSetter(v8::Local<v8::String> name,
10617 v8::Local<v8::Value> value,
10618 const v8::AccessorInfo& info) {
10619 force_set_set_count++;
10620}
10621
10622static v8::Handle<v8::Value> ForceSetInterceptSetter(
10623 v8::Local<v8::String> name,
10624 v8::Local<v8::Value> value,
10625 const v8::AccessorInfo& info) {
10626 force_set_set_count++;
10627 return v8::Undefined();
10628}
10629
10630TEST(ForceSet) {
10631 force_set_get_count = 0;
10632 force_set_set_count = 0;
10633 pass_on_get = false;
10634
10635 v8::HandleScope scope;
10636 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10637 v8::Handle<v8::String> access_property = v8::String::New("a");
10638 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
10639 LocalContext context(NULL, templ);
10640 v8::Handle<v8::Object> global = context->Global();
10641
10642 // Ordinary properties
10643 v8::Handle<v8::String> simple_property = v8::String::New("p");
10644 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
10645 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10646 // This should fail because the property is read-only
10647 global->Set(simple_property, v8::Int32::New(5));
10648 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10649 // This should succeed even though the property is read-only
10650 global->ForceSet(simple_property, v8::Int32::New(6));
10651 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
10652
10653 // Accessors
10654 CHECK_EQ(0, force_set_set_count);
10655 CHECK_EQ(0, force_set_get_count);
10656 CHECK_EQ(3, global->Get(access_property)->Int32Value());
10657 // CHECK_EQ the property shouldn't override it, just call the setter
10658 // which in this case does nothing.
10659 global->Set(access_property, v8::Int32::New(7));
10660 CHECK_EQ(3, global->Get(access_property)->Int32Value());
10661 CHECK_EQ(1, force_set_set_count);
10662 CHECK_EQ(2, force_set_get_count);
10663 // Forcing the property to be set should override the accessor without
10664 // calling it
10665 global->ForceSet(access_property, v8::Int32::New(8));
10666 CHECK_EQ(8, global->Get(access_property)->Int32Value());
10667 CHECK_EQ(1, force_set_set_count);
10668 CHECK_EQ(2, force_set_get_count);
10669}
10670
10671TEST(ForceSetWithInterceptor) {
10672 force_set_get_count = 0;
10673 force_set_set_count = 0;
10674 pass_on_get = false;
10675
10676 v8::HandleScope scope;
10677 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10678 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
10679 LocalContext context(NULL, templ);
10680 v8::Handle<v8::Object> global = context->Global();
10681
10682 v8::Handle<v8::String> some_property = v8::String::New("a");
10683 CHECK_EQ(0, force_set_set_count);
10684 CHECK_EQ(0, force_set_get_count);
10685 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10686 // Setting the property shouldn't override it, just call the setter
10687 // which in this case does nothing.
10688 global->Set(some_property, v8::Int32::New(7));
10689 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10690 CHECK_EQ(1, force_set_set_count);
10691 CHECK_EQ(2, force_set_get_count);
10692 // Getting the property when the interceptor returns an empty handle
10693 // should yield undefined, since the property isn't present on the
10694 // object itself yet.
10695 pass_on_get = true;
10696 CHECK(global->Get(some_property)->IsUndefined());
10697 CHECK_EQ(1, force_set_set_count);
10698 CHECK_EQ(3, force_set_get_count);
10699 // Forcing the property to be set should cause the value to be
10700 // set locally without calling the interceptor.
10701 global->ForceSet(some_property, v8::Int32::New(8));
10702 CHECK_EQ(8, global->Get(some_property)->Int32Value());
10703 CHECK_EQ(1, force_set_set_count);
10704 CHECK_EQ(4, force_set_get_count);
10705 // Reenabling the interceptor should cause it to take precedence over
10706 // the property
10707 pass_on_get = false;
10708 CHECK_EQ(3, global->Get(some_property)->Int32Value());
10709 CHECK_EQ(1, force_set_set_count);
10710 CHECK_EQ(5, force_set_get_count);
10711 // The interceptor should also work for other properties
10712 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
10713 CHECK_EQ(1, force_set_set_count);
10714 CHECK_EQ(6, force_set_get_count);
10715}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010716
10717
ager@chromium.orge2902be2009-06-08 12:21:35 +000010718THREADED_TEST(ForceDelete) {
10719 v8::HandleScope scope;
10720 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10721 LocalContext context(NULL, templ);
10722 v8::Handle<v8::Object> global = context->Global();
10723
10724 // Ordinary properties
10725 v8::Handle<v8::String> simple_property = v8::String::New("p");
10726 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
10727 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10728 // This should fail because the property is dont-delete.
10729 CHECK(!global->Delete(simple_property));
10730 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
10731 // This should succeed even though the property is dont-delete.
10732 CHECK(global->ForceDelete(simple_property));
10733 CHECK(global->Get(simple_property)->IsUndefined());
10734}
10735
10736
10737static int force_delete_interceptor_count = 0;
10738static bool pass_on_delete = false;
10739
10740
10741static v8::Handle<v8::Boolean> ForceDeleteDeleter(
10742 v8::Local<v8::String> name,
10743 const v8::AccessorInfo& info) {
10744 force_delete_interceptor_count++;
10745 if (pass_on_delete) {
10746 return v8::Handle<v8::Boolean>();
10747 } else {
10748 return v8::True();
10749 }
10750}
10751
10752
10753THREADED_TEST(ForceDeleteWithInterceptor) {
10754 force_delete_interceptor_count = 0;
10755 pass_on_delete = false;
10756
10757 v8::HandleScope scope;
10758 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10759 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
10760 LocalContext context(NULL, templ);
10761 v8::Handle<v8::Object> global = context->Global();
10762
10763 v8::Handle<v8::String> some_property = v8::String::New("a");
10764 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
10765
10766 // Deleting a property should get intercepted and nothing should
10767 // happen.
10768 CHECK_EQ(0, force_delete_interceptor_count);
10769 CHECK(global->Delete(some_property));
10770 CHECK_EQ(1, force_delete_interceptor_count);
10771 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10772 // Deleting the property when the interceptor returns an empty
10773 // handle should not delete the property since it is DontDelete.
10774 pass_on_delete = true;
10775 CHECK(!global->Delete(some_property));
10776 CHECK_EQ(2, force_delete_interceptor_count);
10777 CHECK_EQ(42, global->Get(some_property)->Int32Value());
10778 // Forcing the property to be deleted should delete the value
10779 // without calling the interceptor.
10780 CHECK(global->ForceDelete(some_property));
10781 CHECK(global->Get(some_property)->IsUndefined());
10782 CHECK_EQ(2, force_delete_interceptor_count);
10783}
10784
10785
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010786// Make sure that forcing a delete invalidates any IC stubs, so we
10787// don't read the hole value.
10788THREADED_TEST(ForceDeleteIC) {
10789 v8::HandleScope scope;
10790 LocalContext context;
10791 // Create a DontDelete variable on the global object.
10792 CompileRun("this.__proto__ = { foo: 'horse' };"
10793 "var foo = 'fish';"
10794 "function f() { return foo.length; }");
10795 // Initialize the IC for foo in f.
10796 CompileRun("for (var i = 0; i < 4; i++) f();");
10797 // Make sure the value of foo is correct before the deletion.
10798 CHECK_EQ(4, CompileRun("f()")->Int32Value());
10799 // Force the deletion of foo.
10800 CHECK(context->Global()->ForceDelete(v8_str("foo")));
10801 // Make sure the value for foo is read from the prototype, and that
10802 // we don't get in trouble with reading the deleted cell value
10803 // sentinel.
10804 CHECK_EQ(5, CompileRun("f()")->Int32Value());
10805}
10806
10807
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000010808v8::Persistent<Context> calling_context0;
10809v8::Persistent<Context> calling_context1;
10810v8::Persistent<Context> calling_context2;
10811
10812
10813// Check that the call to the callback is initiated in
10814// calling_context2, the directly calling context is calling_context1
10815// and the callback itself is in calling_context0.
10816static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
10817 ApiTestFuzzer::Fuzz();
10818 CHECK(Context::GetCurrent() == calling_context0);
10819 CHECK(Context::GetCalling() == calling_context1);
10820 CHECK(Context::GetEntered() == calling_context2);
10821 return v8::Integer::New(42);
10822}
10823
10824
10825THREADED_TEST(GetCallingContext) {
10826 v8::HandleScope scope;
10827
10828 calling_context0 = Context::New();
10829 calling_context1 = Context::New();
10830 calling_context2 = Context::New();
10831
10832 // Allow cross-domain access.
10833 Local<String> token = v8_str("<security token>");
10834 calling_context0->SetSecurityToken(token);
10835 calling_context1->SetSecurityToken(token);
10836 calling_context2->SetSecurityToken(token);
10837
10838 // Create an object with a C++ callback in context0.
10839 calling_context0->Enter();
10840 Local<v8::FunctionTemplate> callback_templ =
10841 v8::FunctionTemplate::New(GetCallingContextCallback);
10842 calling_context0->Global()->Set(v8_str("callback"),
10843 callback_templ->GetFunction());
10844 calling_context0->Exit();
10845
10846 // Expose context0 in context1 and setup a function that calls the
10847 // callback function.
10848 calling_context1->Enter();
10849 calling_context1->Global()->Set(v8_str("context0"),
10850 calling_context0->Global());
10851 CompileRun("function f() { context0.callback() }");
10852 calling_context1->Exit();
10853
10854 // Expose context1 in context2 and call the callback function in
10855 // context0 indirectly through f in context1.
10856 calling_context2->Enter();
10857 calling_context2->Global()->Set(v8_str("context1"),
10858 calling_context1->Global());
10859 CompileRun("context1.f()");
10860 calling_context2->Exit();
10861
10862 // Dispose the contexts to allow them to be garbage collected.
10863 calling_context0.Dispose();
10864 calling_context1.Dispose();
10865 calling_context2.Dispose();
10866 calling_context0.Clear();
10867 calling_context1.Clear();
10868 calling_context2.Clear();
10869}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010870
10871
10872// Check that a variable declaration with no explicit initialization
10873// value does not shadow an existing property in the prototype chain.
10874//
10875// This is consistent with Firefox and Safari.
10876//
10877// See http://crbug.com/12548.
10878THREADED_TEST(InitGlobalVarInProtoChain) {
10879 v8::HandleScope scope;
10880 LocalContext context;
10881 // Introduce a variable in the prototype chain.
10882 CompileRun("__proto__.x = 42");
10883 v8::Handle<v8::Value> result = CompileRun("var x; x");
10884 CHECK(!result->IsUndefined());
10885 CHECK_EQ(42, result->Int32Value());
10886}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010887
10888
10889// Regression test for issue 398.
10890// If a function is added to an object, creating a constant function
10891// field, and the result is cloned, replacing the constant function on the
10892// original should not affect the clone.
10893// See http://code.google.com/p/v8/issues/detail?id=398
10894THREADED_TEST(ReplaceConstantFunction) {
10895 v8::HandleScope scope;
10896 LocalContext context;
10897 v8::Handle<v8::Object> obj = v8::Object::New();
10898 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10899 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10900 obj->Set(foo_string, func_templ->GetFunction());
10901 v8::Handle<v8::Object> obj_clone = obj->Clone();
10902 obj_clone->Set(foo_string, v8::String::New("Hello"));
10903 CHECK(!obj->Get(foo_string)->IsUndefined());
10904}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010905
10906
10907// Regression test for http://crbug.com/16276.
10908THREADED_TEST(Regress16276) {
10909 v8::HandleScope scope;
10910 LocalContext context;
10911 // Force the IC in f to be a dictionary load IC.
10912 CompileRun("function f(obj) { return obj.x; }\n"
10913 "var obj = { x: { foo: 42 }, y: 87 };\n"
10914 "var x = obj.x;\n"
10915 "delete obj.y;\n"
10916 "for (var i = 0; i < 5; i++) f(obj);");
10917 // Detach the global object to make 'this' refer directly to the
10918 // global object (not the proxy), and make sure that the dictionary
10919 // load IC doesn't mess up loading directly from the global object.
10920 context->DetachGlobal();
10921 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10922}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010923
10924
10925THREADED_TEST(PixelArray) {
10926 v8::HandleScope scope;
10927 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010928 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010929 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010930 i::Handle<i::ExternalPixelArray> pixels =
10931 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010933 v8::kExternalPixelArray,
10934 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010936 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010937 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010938 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010940 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010941 CHECK_EQ(i % 256, pixels->get(i));
10942 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010943 }
10944
10945 v8::Handle<v8::Object> obj = v8::Object::New();
10946 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10947 // Set the elements to be the pixels.
10948 // jsobj->set_elements(*pixels);
10949 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010950 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010951 obj->Set(v8_str("field"), v8::Int32::New(1503));
10952 context->Global()->Set(v8_str("pixels"), obj);
10953 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10954 CHECK_EQ(1503, result->Int32Value());
10955 result = CompileRun("pixels[1]");
10956 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000010957
10958 result = CompileRun("var sum = 0;"
10959 "for (var i = 0; i < 8; i++) {"
10960 " sum += pixels[i] = pixels[i] = -i;"
10961 "}"
10962 "sum;");
10963 CHECK_EQ(-28, result->Int32Value());
10964
10965 result = CompileRun("var sum = 0;"
10966 "for (var i = 0; i < 8; i++) {"
10967 " sum += pixels[i] = pixels[i] = 0;"
10968 "}"
10969 "sum;");
10970 CHECK_EQ(0, result->Int32Value());
10971
10972 result = CompileRun("var sum = 0;"
10973 "for (var i = 0; i < 8; i++) {"
10974 " sum += pixels[i] = pixels[i] = 255;"
10975 "}"
10976 "sum;");
10977 CHECK_EQ(8 * 255, result->Int32Value());
10978
10979 result = CompileRun("var sum = 0;"
10980 "for (var i = 0; i < 8; i++) {"
10981 " sum += pixels[i] = pixels[i] = 256 + i;"
10982 "}"
10983 "sum;");
10984 CHECK_EQ(2076, result->Int32Value());
10985
10986 result = CompileRun("var sum = 0;"
10987 "for (var i = 0; i < 8; i++) {"
10988 " sum += pixels[i] = pixels[i] = i;"
10989 "}"
10990 "sum;");
10991 CHECK_EQ(28, result->Int32Value());
10992
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010993 result = CompileRun("var sum = 0;"
10994 "for (var i = 0; i < 8; i++) {"
10995 " sum += pixels[i];"
10996 "}"
10997 "sum;");
10998 CHECK_EQ(28, result->Int32Value());
10999
11000 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011001 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011002 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011003 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011004 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011005 CHECK_EQ(255,
11006 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011007 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011008 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011009 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011010
11011 result = CompileRun("for (var i = 0; i < 8; i++) {"
11012 " pixels[i] = (i * 65) - 109;"
11013 "}"
11014 "pixels[1] + pixels[6];");
11015 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011016 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11017 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11018 CHECK_EQ(21,
11019 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11020 CHECK_EQ(86,
11021 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11022 CHECK_EQ(151,
11023 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11024 CHECK_EQ(216,
11025 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11026 CHECK_EQ(255,
11027 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11028 CHECK_EQ(255,
11029 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011030 result = CompileRun("var sum = 0;"
11031 "for (var i = 0; i < 8; i++) {"
11032 " sum += pixels[i];"
11033 "}"
11034 "sum;");
11035 CHECK_EQ(984, result->Int32Value());
11036
11037 result = CompileRun("for (var i = 0; i < 8; i++) {"
11038 " pixels[i] = (i * 1.1);"
11039 "}"
11040 "pixels[1] + pixels[6];");
11041 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011042 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11043 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11044 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11045 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11046 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11047 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11048 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11049 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011050
11051 result = CompileRun("for (var i = 0; i < 8; i++) {"
11052 " pixels[7] = undefined;"
11053 "}"
11054 "pixels[7];");
11055 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011056 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011057
11058 result = CompileRun("for (var i = 0; i < 8; i++) {"
11059 " pixels[6] = '2.3';"
11060 "}"
11061 "pixels[6];");
11062 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011063 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011064
11065 result = CompileRun("for (var i = 0; i < 8; i++) {"
11066 " pixels[5] = NaN;"
11067 "}"
11068 "pixels[5];");
11069 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011070 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011071
11072 result = CompileRun("for (var i = 0; i < 8; i++) {"
11073 " pixels[8] = Infinity;"
11074 "}"
11075 "pixels[8];");
11076 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011077 CHECK_EQ(255,
11078 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011079
11080 result = CompileRun("for (var i = 0; i < 8; i++) {"
11081 " pixels[9] = -Infinity;"
11082 "}"
11083 "pixels[9];");
11084 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011085 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011086
11087 result = CompileRun("pixels[3] = 33;"
11088 "delete pixels[3];"
11089 "pixels[3];");
11090 CHECK_EQ(33, result->Int32Value());
11091
11092 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11093 "pixels[2] = 12; pixels[3] = 13;"
11094 "pixels.__defineGetter__('2',"
11095 "function() { return 120; });"
11096 "pixels[2];");
11097 CHECK_EQ(12, result->Int32Value());
11098
11099 result = CompileRun("var js_array = new Array(40);"
11100 "js_array[0] = 77;"
11101 "js_array;");
11102 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11103
11104 result = CompileRun("pixels[1] = 23;"
11105 "pixels.__proto__ = [];"
11106 "js_array.__proto__ = pixels;"
11107 "js_array.concat(pixels);");
11108 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11109 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11110
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011111 result = CompileRun("pixels[1] = 23;");
11112 CHECK_EQ(23, result->Int32Value());
11113
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011114 // Test for index greater than 255. Regression test for:
11115 // http://code.google.com/p/chromium/issues/detail?id=26337.
11116 result = CompileRun("pixels[256] = 255;");
11117 CHECK_EQ(255, result->Int32Value());
11118 result = CompileRun("var i = 0;"
11119 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11120 "i");
11121 CHECK_EQ(255, result->Int32Value());
11122
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011123 // Make sure that pixel array ICs recognize when a non-pixel array
11124 // is passed to it.
11125 result = CompileRun("function pa_load(p) {"
11126 " var sum = 0;"
11127 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11128 " return sum;"
11129 "}"
11130 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11131 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11132 "just_ints = new Object();"
11133 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11134 "for (var i = 0; i < 10; ++i) {"
11135 " result = pa_load(just_ints);"
11136 "}"
11137 "result");
11138 CHECK_EQ(32640, result->Int32Value());
11139
11140 // Make sure that pixel array ICs recognize out-of-bound accesses.
11141 result = CompileRun("function pa_load(p, start) {"
11142 " var sum = 0;"
11143 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11144 " return sum;"
11145 "}"
11146 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11147 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11148 "for (var i = 0; i < 10; ++i) {"
11149 " result = pa_load(pixels,-10);"
11150 "}"
11151 "result");
11152 CHECK_EQ(0, result->Int32Value());
11153
11154 // Make sure that generic ICs properly handles a pixel array.
11155 result = CompileRun("function pa_load(p) {"
11156 " var sum = 0;"
11157 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11158 " return sum;"
11159 "}"
11160 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11161 "just_ints = new Object();"
11162 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11163 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11164 "for (var i = 0; i < 10; ++i) {"
11165 " result = pa_load(pixels);"
11166 "}"
11167 "result");
11168 CHECK_EQ(32640, result->Int32Value());
11169
11170 // Make sure that generic load ICs recognize out-of-bound accesses in
11171 // pixel arrays.
11172 result = CompileRun("function pa_load(p, start) {"
11173 " var sum = 0;"
11174 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11175 " return sum;"
11176 "}"
11177 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11178 "just_ints = new Object();"
11179 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11180 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11181 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11182 "for (var i = 0; i < 10; ++i) {"
11183 " result = pa_load(pixels,-10);"
11184 "}"
11185 "result");
11186 CHECK_EQ(0, result->Int32Value());
11187
11188 // Make sure that generic ICs properly handles other types than pixel
11189 // arrays (that the inlined fast pixel array test leaves the right information
11190 // in the right registers).
11191 result = CompileRun("function pa_load(p) {"
11192 " var sum = 0;"
11193 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11194 " return sum;"
11195 "}"
11196 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11197 "just_ints = new Object();"
11198 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11199 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11200 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11201 "sparse_array = new Object();"
11202 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11203 "sparse_array[1000000] = 3;"
11204 "for (var i = 0; i < 10; ++i) {"
11205 " result = pa_load(sparse_array);"
11206 "}"
11207 "result");
11208 CHECK_EQ(32640, result->Int32Value());
11209
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011210 // Make sure that pixel array store ICs clamp values correctly.
11211 result = CompileRun("function pa_store(p) {"
11212 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11213 "}"
11214 "pa_store(pixels);"
11215 "var sum = 0;"
11216 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11217 "sum");
11218 CHECK_EQ(48896, result->Int32Value());
11219
11220 // Make sure that pixel array stores correctly handle accesses outside
11221 // of the pixel array..
11222 result = CompileRun("function pa_store(p,start) {"
11223 " for (var j = 0; j < 256; j++) {"
11224 " p[j+start] = j * 2;"
11225 " }"
11226 "}"
11227 "pa_store(pixels,0);"
11228 "pa_store(pixels,-128);"
11229 "var sum = 0;"
11230 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11231 "sum");
11232 CHECK_EQ(65280, result->Int32Value());
11233
11234 // Make sure that the generic store stub correctly handle accesses outside
11235 // of the pixel array..
11236 result = CompileRun("function pa_store(p,start) {"
11237 " for (var j = 0; j < 256; j++) {"
11238 " p[j+start] = j * 2;"
11239 " }"
11240 "}"
11241 "pa_store(pixels,0);"
11242 "just_ints = new Object();"
11243 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11244 "pa_store(just_ints, 0);"
11245 "pa_store(pixels,-128);"
11246 "var sum = 0;"
11247 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11248 "sum");
11249 CHECK_EQ(65280, result->Int32Value());
11250
11251 // Make sure that the generic keyed store stub clamps pixel array values
11252 // correctly.
11253 result = CompileRun("function pa_store(p) {"
11254 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11255 "}"
11256 "pa_store(pixels);"
11257 "just_ints = new Object();"
11258 "pa_store(just_ints);"
11259 "pa_store(pixels);"
11260 "var sum = 0;"
11261 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11262 "sum");
11263 CHECK_EQ(48896, result->Int32Value());
11264
11265 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011266 result = CompileRun("function pa_load(p) {"
11267 " var sum = 0;"
11268 " for (var i=0; i<256; ++i) {"
11269 " sum += p[i];"
11270 " }"
11271 " return sum; "
11272 "}"
11273 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011274 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011275 " result = pa_load(pixels);"
11276 "}"
11277 "result");
11278 CHECK_EQ(32640, result->Int32Value());
11279
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011280 // Make sure that pixel array stores are optimized by crankshaft.
11281 result = CompileRun("function pa_init(p) {"
11282 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11283 "}"
11284 "function pa_load(p) {"
11285 " var sum = 0;"
11286 " for (var i=0; i<256; ++i) {"
11287 " sum += p[i];"
11288 " }"
11289 " return sum; "
11290 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011291 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011292 " pa_init(pixels);"
11293 "}"
11294 "result = pa_load(pixels);"
11295 "result");
11296 CHECK_EQ(32640, result->Int32Value());
11297
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011298 free(pixel_data);
11299}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000011300
ager@chromium.org96c75b52009-08-26 09:13:16 +000011301
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011302THREADED_TEST(PixelArrayInfo) {
11303 v8::HandleScope scope;
11304 LocalContext context;
11305 for (int size = 0; size < 100; size += 10) {
11306 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
11307 v8::Handle<v8::Object> obj = v8::Object::New();
11308 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
11309 CHECK(obj->HasIndexedPropertiesInPixelData());
11310 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
11311 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
11312 free(pixel_data);
11313 }
11314}
11315
11316
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011317static v8::Handle<Value> NotHandledIndexedPropertyGetter(
11318 uint32_t index,
11319 const AccessorInfo& info) {
11320 ApiTestFuzzer::Fuzz();
11321 return v8::Handle<Value>();
11322}
11323
11324
11325static v8::Handle<Value> NotHandledIndexedPropertySetter(
11326 uint32_t index,
11327 Local<Value> value,
11328 const AccessorInfo& info) {
11329 ApiTestFuzzer::Fuzz();
11330 return v8::Handle<Value>();
11331}
11332
11333
11334THREADED_TEST(PixelArrayWithInterceptor) {
11335 v8::HandleScope scope;
11336 LocalContext context;
11337 const int kElementCount = 260;
11338 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011339 i::Handle<i::ExternalPixelArray> pixels =
11340 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 FACTORY->NewExternalArray(kElementCount,
11342 v8::kExternalPixelArray,
11343 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011344 for (int i = 0; i < kElementCount; i++) {
11345 pixels->set(i, i % 256);
11346 }
11347 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11348 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
11349 NotHandledIndexedPropertySetter);
11350 v8::Handle<v8::Object> obj = templ->NewInstance();
11351 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
11352 context->Global()->Set(v8_str("pixels"), obj);
11353 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
11354 CHECK_EQ(1, result->Int32Value());
11355 result = CompileRun("var sum = 0;"
11356 "for (var i = 0; i < 8; i++) {"
11357 " sum += pixels[i] = pixels[i] = -i;"
11358 "}"
11359 "sum;");
11360 CHECK_EQ(-28, result->Int32Value());
11361 result = CompileRun("pixels.hasOwnProperty('1')");
11362 CHECK(result->BooleanValue());
11363 free(pixel_data);
11364}
11365
11366
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011367static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
11368 switch (array_type) {
11369 case v8::kExternalByteArray:
11370 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011371 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011372 return 1;
11373 break;
11374 case v8::kExternalShortArray:
11375 case v8::kExternalUnsignedShortArray:
11376 return 2;
11377 break;
11378 case v8::kExternalIntArray:
11379 case v8::kExternalUnsignedIntArray:
11380 case v8::kExternalFloatArray:
11381 return 4;
11382 break;
11383 default:
11384 UNREACHABLE();
11385 return -1;
11386 }
11387 UNREACHABLE();
11388 return -1;
11389}
11390
11391
ager@chromium.org3811b432009-10-28 14:53:37 +000011392template <class ExternalArrayClass, class ElementType>
11393static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
11394 int64_t low,
11395 int64_t high) {
11396 v8::HandleScope scope;
11397 LocalContext context;
11398 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011399 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000011400 ElementType* array_data =
11401 static_cast<ElementType*>(malloc(kElementCount * element_size));
11402 i::Handle<ExternalArrayClass> array =
11403 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011404 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
11405 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011406 for (int i = 0; i < kElementCount; i++) {
11407 array->set(i, static_cast<ElementType>(i));
11408 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011410 for (int i = 0; i < kElementCount; i++) {
11411 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
11412 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
11413 }
11414
11415 v8::Handle<v8::Object> obj = v8::Object::New();
11416 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11417 // Set the elements to be the external array.
11418 obj->SetIndexedPropertiesToExternalArrayData(array_data,
11419 array_type,
11420 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011421 CHECK_EQ(
11422 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011423 obj->Set(v8_str("field"), v8::Int32::New(1503));
11424 context->Global()->Set(v8_str("ext_array"), obj);
11425 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
11426 CHECK_EQ(1503, result->Int32Value());
11427 result = CompileRun("ext_array[1]");
11428 CHECK_EQ(1, result->Int32Value());
11429
11430 // Check pass through of assigned smis
11431 result = CompileRun("var sum = 0;"
11432 "for (var i = 0; i < 8; i++) {"
11433 " sum += ext_array[i] = ext_array[i] = -i;"
11434 "}"
11435 "sum;");
11436 CHECK_EQ(-28, result->Int32Value());
11437
11438 // Check assigned smis
11439 result = CompileRun("for (var i = 0; i < 8; i++) {"
11440 " ext_array[i] = i;"
11441 "}"
11442 "var sum = 0;"
11443 "for (var i = 0; i < 8; i++) {"
11444 " sum += ext_array[i];"
11445 "}"
11446 "sum;");
11447 CHECK_EQ(28, result->Int32Value());
11448
11449 // Check assigned smis in reverse order
11450 result = CompileRun("for (var i = 8; --i >= 0; ) {"
11451 " ext_array[i] = i;"
11452 "}"
11453 "var sum = 0;"
11454 "for (var i = 0; i < 8; i++) {"
11455 " sum += ext_array[i];"
11456 "}"
11457 "sum;");
11458 CHECK_EQ(28, result->Int32Value());
11459
11460 // Check pass through of assigned HeapNumbers
11461 result = CompileRun("var sum = 0;"
11462 "for (var i = 0; i < 16; i+=2) {"
11463 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
11464 "}"
11465 "sum;");
11466 CHECK_EQ(-28, result->Int32Value());
11467
11468 // Check assigned HeapNumbers
11469 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
11470 " ext_array[i] = (i * 0.5);"
11471 "}"
11472 "var sum = 0;"
11473 "for (var i = 0; i < 16; i+=2) {"
11474 " sum += ext_array[i];"
11475 "}"
11476 "sum;");
11477 CHECK_EQ(28, result->Int32Value());
11478
11479 // Check assigned HeapNumbers in reverse order
11480 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
11481 " ext_array[i] = (i * 0.5);"
11482 "}"
11483 "var sum = 0;"
11484 "for (var i = 0; i < 16; i+=2) {"
11485 " sum += ext_array[i];"
11486 "}"
11487 "sum;");
11488 CHECK_EQ(28, result->Int32Value());
11489
11490 i::ScopedVector<char> test_buf(1024);
11491
11492 // Check legal boundary conditions.
11493 // The repeated loads and stores ensure the ICs are exercised.
11494 const char* boundary_program =
11495 "var res = 0;"
11496 "for (var i = 0; i < 16; i++) {"
11497 " ext_array[i] = %lld;"
11498 " if (i > 8) {"
11499 " res = ext_array[i];"
11500 " }"
11501 "}"
11502 "res;";
11503 i::OS::SNPrintF(test_buf,
11504 boundary_program,
11505 low);
11506 result = CompileRun(test_buf.start());
11507 CHECK_EQ(low, result->IntegerValue());
11508
11509 i::OS::SNPrintF(test_buf,
11510 boundary_program,
11511 high);
11512 result = CompileRun(test_buf.start());
11513 CHECK_EQ(high, result->IntegerValue());
11514
11515 // Check misprediction of type in IC.
11516 result = CompileRun("var tmp_array = ext_array;"
11517 "var sum = 0;"
11518 "for (var i = 0; i < 8; i++) {"
11519 " tmp_array[i] = i;"
11520 " sum += tmp_array[i];"
11521 " if (i == 4) {"
11522 " tmp_array = {};"
11523 " }"
11524 "}"
11525 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011527 CHECK_EQ(28, result->Int32Value());
11528
11529 // Make sure out-of-range loads do not throw.
11530 i::OS::SNPrintF(test_buf,
11531 "var caught_exception = false;"
11532 "try {"
11533 " ext_array[%d];"
11534 "} catch (e) {"
11535 " caught_exception = true;"
11536 "}"
11537 "caught_exception;",
11538 kElementCount);
11539 result = CompileRun(test_buf.start());
11540 CHECK_EQ(false, result->BooleanValue());
11541
11542 // Make sure out-of-range stores do not throw.
11543 i::OS::SNPrintF(test_buf,
11544 "var caught_exception = false;"
11545 "try {"
11546 " ext_array[%d] = 1;"
11547 "} catch (e) {"
11548 " caught_exception = true;"
11549 "}"
11550 "caught_exception;",
11551 kElementCount);
11552 result = CompileRun(test_buf.start());
11553 CHECK_EQ(false, result->BooleanValue());
11554
11555 // Check other boundary conditions, values and operations.
11556 result = CompileRun("for (var i = 0; i < 8; i++) {"
11557 " ext_array[7] = undefined;"
11558 "}"
11559 "ext_array[7];");
11560 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011561 CHECK_EQ(
11562 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011563
11564 result = CompileRun("for (var i = 0; i < 8; i++) {"
11565 " ext_array[6] = '2.3';"
11566 "}"
11567 "ext_array[6];");
11568 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011569 CHECK_EQ(
11570 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011571
11572 if (array_type != v8::kExternalFloatArray) {
11573 // Though the specification doesn't state it, be explicit about
11574 // converting NaNs and +/-Infinity to zero.
11575 result = CompileRun("for (var i = 0; i < 8; i++) {"
11576 " ext_array[i] = 5;"
11577 "}"
11578 "for (var i = 0; i < 8; i++) {"
11579 " ext_array[i] = NaN;"
11580 "}"
11581 "ext_array[5];");
11582 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011583 CHECK_EQ(0,
11584 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000011585
11586 result = CompileRun("for (var i = 0; i < 8; i++) {"
11587 " ext_array[i] = 5;"
11588 "}"
11589 "for (var i = 0; i < 8; i++) {"
11590 " ext_array[i] = Infinity;"
11591 "}"
11592 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011593 int expected_value =
11594 (array_type == v8::kExternalPixelArray) ? 255 : 0;
11595 CHECK_EQ(expected_value, result->Int32Value());
11596 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000011597 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000011598
11599 result = CompileRun("for (var i = 0; i < 8; i++) {"
11600 " ext_array[i] = 5;"
11601 "}"
11602 "for (var i = 0; i < 8; i++) {"
11603 " ext_array[i] = -Infinity;"
11604 "}"
11605 "ext_array[5];");
11606 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011607 CHECK_EQ(0,
11608 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000011609
11610 // Check truncation behavior of integral arrays.
11611 const char* unsigned_data =
11612 "var source_data = [0.6, 10.6];"
11613 "var expected_results = [0, 10];";
11614 const char* signed_data =
11615 "var source_data = [0.6, 10.6, -0.6, -10.6];"
11616 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011617 const char* pixel_data =
11618 "var source_data = [0.6, 10.6];"
11619 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000011620 bool is_unsigned =
11621 (array_type == v8::kExternalUnsignedByteArray ||
11622 array_type == v8::kExternalUnsignedShortArray ||
11623 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011624 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000011625
11626 i::OS::SNPrintF(test_buf,
11627 "%s"
11628 "var all_passed = true;"
11629 "for (var i = 0; i < source_data.length; i++) {"
11630 " for (var j = 0; j < 8; j++) {"
11631 " ext_array[j] = source_data[i];"
11632 " }"
11633 " all_passed = all_passed &&"
11634 " (ext_array[5] == expected_results[i]);"
11635 "}"
11636 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011637 (is_unsigned ?
11638 unsigned_data :
11639 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000011640 result = CompileRun(test_buf.start());
11641 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000011642 }
11643
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011644 // Test crankshaft external array loads
11645 for (int i = 0; i < kElementCount; i++) {
11646 array->set(i, static_cast<ElementType>(i));
11647 }
11648 result = CompileRun("function ee_load_test_func(sum) {"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011649 " for (var i = 0; i < 40; ++i)"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011650 " sum += ext_array[i];"
11651 " return sum;"
11652 "}"
11653 "sum=0;"
11654 "for (var i=0;i<10000;++i) {"
11655 " sum=ee_load_test_func(sum);"
11656 "}"
11657 "sum;");
11658 CHECK_EQ(7800000, result->Int32Value());
11659
11660 // Test crankshaft external array stores
11661 result = CompileRun("function ee_store_test_func(sum) {"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011662 " for (var i = 0; i < 40; ++i)"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011663 " sum += ext_array[i] = i;"
11664 " return sum;"
11665 "}"
11666 "sum=0;"
11667 "for (var i=0;i<10000;++i) {"
11668 " sum=ee_store_test_func(sum);"
11669 "}"
11670 "sum;");
11671 CHECK_EQ(7800000, result->Int32Value());
11672
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011673 for (int i = 0; i < kElementCount; i++) {
11674 array->set(i, static_cast<ElementType>(i));
11675 }
11676 // Test complex assignments
11677 result = CompileRun("function ee_op_test_complex_func(sum) {"
11678 " for (var i = 0; i < 40; ++i) {"
11679 " sum += (ext_array[i] += 1);"
11680 " sum += (ext_array[i] -= 1);"
11681 " } "
11682 " return sum;"
11683 "}"
11684 "sum=0;"
11685 "for (var i=0;i<10000;++i) {"
11686 " sum=ee_op_test_complex_func(sum);"
11687 "}"
11688 "sum;");
11689 CHECK_EQ(16000000, result->Int32Value());
11690
11691 // Test count operations
11692 result = CompileRun("function ee_op_test_count_func(sum) {"
11693 " for (var i = 0; i < 40; ++i) {"
11694 " sum += (++ext_array[i]);"
11695 " sum += (--ext_array[i]);"
11696 " } "
11697 " return sum;"
11698 "}"
11699 "sum=0;"
11700 "for (var i=0;i<10000;++i) {"
11701 " sum=ee_op_test_count_func(sum);"
11702 "}"
11703 "sum;");
11704 CHECK_EQ(16000000, result->Int32Value());
11705
ager@chromium.org3811b432009-10-28 14:53:37 +000011706 result = CompileRun("ext_array[3] = 33;"
11707 "delete ext_array[3];"
11708 "ext_array[3];");
11709 CHECK_EQ(33, result->Int32Value());
11710
11711 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
11712 "ext_array[2] = 12; ext_array[3] = 13;"
11713 "ext_array.__defineGetter__('2',"
11714 "function() { return 120; });"
11715 "ext_array[2];");
11716 CHECK_EQ(12, result->Int32Value());
11717
11718 result = CompileRun("var js_array = new Array(40);"
11719 "js_array[0] = 77;"
11720 "js_array;");
11721 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11722
11723 result = CompileRun("ext_array[1] = 23;"
11724 "ext_array.__proto__ = [];"
11725 "js_array.__proto__ = ext_array;"
11726 "js_array.concat(ext_array);");
11727 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11728 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11729
11730 result = CompileRun("ext_array[1] = 23;");
11731 CHECK_EQ(23, result->Int32Value());
11732
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011733 // Test more complex manipulations which cause eax to contain values
11734 // that won't be completely overwritten by loads from the arrays.
11735 // This catches bugs in the instructions used for the KeyedLoadIC
11736 // for byte and word types.
11737 {
11738 const int kXSize = 300;
11739 const int kYSize = 300;
11740 const int kLargeElementCount = kXSize * kYSize * 4;
11741 ElementType* large_array_data =
11742 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
11743 i::Handle<ExternalArrayClass> large_array =
11744 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011745 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011746 array_type,
11747 array_data));
11748 v8::Handle<v8::Object> large_obj = v8::Object::New();
11749 // Set the elements to be the external array.
11750 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
11751 array_type,
11752 kLargeElementCount);
11753 context->Global()->Set(v8_str("large_array"), large_obj);
11754 // Initialize contents of a few rows.
11755 for (int x = 0; x < 300; x++) {
11756 int row = 0;
11757 int offset = row * 300 * 4;
11758 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11759 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11760 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11761 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11762 row = 150;
11763 offset = row * 300 * 4;
11764 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11765 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11766 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11767 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11768 row = 298;
11769 offset = row * 300 * 4;
11770 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
11771 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
11772 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
11773 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
11774 }
11775 // The goal of the code below is to make "offset" large enough
11776 // that the computation of the index (which goes into eax) has
11777 // high bits set which will not be overwritten by a byte or short
11778 // load.
11779 result = CompileRun("var failed = false;"
11780 "var offset = 0;"
11781 "for (var i = 0; i < 300; i++) {"
11782 " if (large_array[4 * i] != 127 ||"
11783 " large_array[4 * i + 1] != 0 ||"
11784 " large_array[4 * i + 2] != 0 ||"
11785 " large_array[4 * i + 3] != 127) {"
11786 " failed = true;"
11787 " }"
11788 "}"
11789 "offset = 150 * 300 * 4;"
11790 "for (var i = 0; i < 300; i++) {"
11791 " if (large_array[offset + 4 * i] != 127 ||"
11792 " large_array[offset + 4 * i + 1] != 0 ||"
11793 " large_array[offset + 4 * i + 2] != 0 ||"
11794 " large_array[offset + 4 * i + 3] != 127) {"
11795 " failed = true;"
11796 " }"
11797 "}"
11798 "offset = 298 * 300 * 4;"
11799 "for (var i = 0; i < 300; i++) {"
11800 " if (large_array[offset + 4 * i] != 127 ||"
11801 " large_array[offset + 4 * i + 1] != 0 ||"
11802 " large_array[offset + 4 * i + 2] != 0 ||"
11803 " large_array[offset + 4 * i + 3] != 127) {"
11804 " failed = true;"
11805 " }"
11806 "}"
11807 "!failed;");
11808 CHECK_EQ(true, result->BooleanValue());
11809 free(large_array_data);
11810 }
11811
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011812 // The "" property descriptor is overloaded to store information about
11813 // the external array. Ensure that setting and accessing the "" property
11814 // works (it should overwrite the information cached about the external
11815 // array in the DescriptorArray) in various situations.
11816 result = CompileRun("ext_array[''] = 23; ext_array['']");
11817 CHECK_EQ(23, result->Int32Value());
11818
11819 // Property "" set after the external array is associated with the object.
11820 {
11821 v8::Handle<v8::Object> obj2 = v8::Object::New();
11822 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
11823 obj2->Set(v8_str(""), v8::Int32::New(1503));
11824 // Set the elements to be the external array.
11825 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11826 array_type,
11827 kElementCount);
11828 context->Global()->Set(v8_str("ext_array"), obj2);
11829 result = CompileRun("ext_array['']");
11830 CHECK_EQ(1503, result->Int32Value());
11831 }
11832
11833 // Property "" set after the external array is associated with the object.
11834 {
11835 v8::Handle<v8::Object> obj2 = v8::Object::New();
11836 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11837 // Set the elements to be the external array.
11838 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11839 array_type,
11840 kElementCount);
11841 obj2->Set(v8_str(""), v8::Int32::New(1503));
11842 context->Global()->Set(v8_str("ext_array"), obj2);
11843 result = CompileRun("ext_array['']");
11844 CHECK_EQ(1503, result->Int32Value());
11845 }
11846
11847 // Should reuse the map from previous test.
11848 {
11849 v8::Handle<v8::Object> obj2 = v8::Object::New();
11850 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
11851 // Set the elements to be the external array. Should re-use the map
11852 // from previous test.
11853 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
11854 array_type,
11855 kElementCount);
11856 context->Global()->Set(v8_str("ext_array"), obj2);
11857 result = CompileRun("ext_array['']");
11858 }
11859
11860 // Property "" is a constant function that shouldn't not be interfered with
11861 // when an external array is set.
11862 {
11863 v8::Handle<v8::Object> obj2 = v8::Object::New();
11864 // Start
11865 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11866
11867 // Add a constant function to an object.
11868 context->Global()->Set(v8_str("ext_array"), obj2);
11869 result = CompileRun("ext_array[''] = function() {return 1503;};"
11870 "ext_array['']();");
11871
11872 // Add an external array transition to the same map that
11873 // has the constant transition.
11874 v8::Handle<v8::Object> obj3 = v8::Object::New();
11875 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
11876 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11877 array_type,
11878 kElementCount);
11879 context->Global()->Set(v8_str("ext_array"), obj3);
11880 }
11881
11882 // If a external array transition is in the map, it should get clobbered
11883 // by a constant function.
11884 {
11885 // Add an external array transition.
11886 v8::Handle<v8::Object> obj3 = v8::Object::New();
11887 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11888 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
11889 array_type,
11890 kElementCount);
11891
11892 // Add a constant function to the same map that just got an external array
11893 // transition.
11894 v8::Handle<v8::Object> obj2 = v8::Object::New();
11895 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
11896 context->Global()->Set(v8_str("ext_array"), obj2);
11897 result = CompileRun("ext_array[''] = function() {return 1503;};"
11898 "ext_array['']();");
11899 }
11900
ager@chromium.org3811b432009-10-28 14:53:37 +000011901 free(array_data);
11902}
11903
11904
11905THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011906 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011907 v8::kExternalByteArray,
11908 -128,
11909 127);
11910}
11911
11912
11913THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011914 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011915 v8::kExternalUnsignedByteArray,
11916 0,
11917 255);
11918}
11919
11920
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011921THREADED_TEST(ExternalPixelArray) {
11922 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
11923 v8::kExternalPixelArray,
11924 0,
11925 255);
11926}
11927
11928
ager@chromium.org3811b432009-10-28 14:53:37 +000011929THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011930 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011931 v8::kExternalShortArray,
11932 -32768,
11933 32767);
11934}
11935
11936
11937THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011938 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011939 v8::kExternalUnsignedShortArray,
11940 0,
11941 65535);
11942}
11943
11944
11945THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011946 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011947 v8::kExternalIntArray,
11948 INT_MIN, // -2147483648
11949 INT_MAX); // 2147483647
11950}
11951
11952
11953THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011954 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011955 v8::kExternalUnsignedIntArray,
11956 0,
11957 UINT_MAX); // 4294967295
11958}
11959
11960
11961THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011962 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000011963 v8::kExternalFloatArray,
11964 -500,
11965 500);
11966}
11967
11968
11969THREADED_TEST(ExternalArrays) {
11970 TestExternalByteArray();
11971 TestExternalUnsignedByteArray();
11972 TestExternalShortArray();
11973 TestExternalUnsignedShortArray();
11974 TestExternalIntArray();
11975 TestExternalUnsignedIntArray();
11976 TestExternalFloatArray();
11977}
11978
11979
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011980void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
11981 v8::HandleScope scope;
11982 LocalContext context;
11983 for (int size = 0; size < 100; size += 10) {
11984 int element_size = ExternalArrayElementSize(array_type);
11985 void* external_data = malloc(size * element_size);
11986 v8::Handle<v8::Object> obj = v8::Object::New();
11987 obj->SetIndexedPropertiesToExternalArrayData(
11988 external_data, array_type, size);
11989 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
11990 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
11991 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
11992 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
11993 free(external_data);
11994 }
11995}
11996
11997
11998THREADED_TEST(ExternalArrayInfo) {
11999 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12000 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12001 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12002 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12003 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12004 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12005 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012006 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012007}
12008
12009
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012010THREADED_TEST(ScriptContextDependence) {
12011 v8::HandleScope scope;
12012 LocalContext c1;
12013 const char *source = "foo";
12014 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12015 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12016 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12017 CHECK_EQ(dep->Run()->Int32Value(), 100);
12018 CHECK_EQ(indep->Run()->Int32Value(), 100);
12019 LocalContext c2;
12020 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12021 CHECK_EQ(dep->Run()->Int32Value(), 100);
12022 CHECK_EQ(indep->Run()->Int32Value(), 101);
12023}
12024
ager@chromium.org96c75b52009-08-26 09:13:16 +000012025
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012026THREADED_TEST(StackTrace) {
12027 v8::HandleScope scope;
12028 LocalContext context;
12029 v8::TryCatch try_catch;
12030 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12031 v8::Handle<v8::String> src = v8::String::New(source);
12032 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12033 v8::Script::New(src, origin)->Run();
12034 CHECK(try_catch.HasCaught());
12035 v8::String::Utf8Value stack(try_catch.StackTrace());
12036 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12037}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012038
12039
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012040// Checks that a StackFrame has certain expected values.
12041void checkStackFrame(const char* expected_script_name,
12042 const char* expected_func_name, int expected_line_number,
12043 int expected_column, bool is_eval, bool is_constructor,
12044 v8::Handle<v8::StackFrame> frame) {
12045 v8::HandleScope scope;
12046 v8::String::Utf8Value func_name(frame->GetFunctionName());
12047 v8::String::Utf8Value script_name(frame->GetScriptName());
12048 if (*script_name == NULL) {
12049 // The situation where there is no associated script, like for evals.
12050 CHECK(expected_script_name == NULL);
12051 } else {
12052 CHECK(strstr(*script_name, expected_script_name) != NULL);
12053 }
12054 CHECK(strstr(*func_name, expected_func_name) != NULL);
12055 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12056 CHECK_EQ(expected_column, frame->GetColumn());
12057 CHECK_EQ(is_eval, frame->IsEval());
12058 CHECK_EQ(is_constructor, frame->IsConstructor());
12059}
12060
12061
12062v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12063 v8::HandleScope scope;
12064 const char* origin = "capture-stack-trace-test";
12065 const int kOverviewTest = 1;
12066 const int kDetailedTest = 2;
12067
12068 ASSERT(args.Length() == 1);
12069
12070 int testGroup = args[0]->Int32Value();
12071 if (testGroup == kOverviewTest) {
12072 v8::Handle<v8::StackTrace> stackTrace =
12073 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12074 CHECK_EQ(4, stackTrace->GetFrameCount());
12075 checkStackFrame(origin, "bar", 2, 10, false, false,
12076 stackTrace->GetFrame(0));
12077 checkStackFrame(origin, "foo", 6, 3, false, false,
12078 stackTrace->GetFrame(1));
12079 checkStackFrame(NULL, "", 1, 1, false, false,
12080 stackTrace->GetFrame(2));
12081 // The last frame is an anonymous function that has the initial call.
12082 checkStackFrame(origin, "", 8, 7, false, false,
12083 stackTrace->GetFrame(3));
12084
12085 CHECK(stackTrace->AsArray()->IsArray());
12086 } else if (testGroup == kDetailedTest) {
12087 v8::Handle<v8::StackTrace> stackTrace =
12088 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12089 CHECK_EQ(4, stackTrace->GetFrameCount());
12090 checkStackFrame(origin, "bat", 4, 22, false, false,
12091 stackTrace->GetFrame(0));
12092 checkStackFrame(origin, "baz", 8, 3, false, true,
12093 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012094#ifdef ENABLE_DEBUGGER_SUPPORT
12095 bool is_eval = true;
12096#else // ENABLE_DEBUGGER_SUPPORT
12097 bool is_eval = false;
12098#endif // ENABLE_DEBUGGER_SUPPORT
12099
12100 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012101 stackTrace->GetFrame(2));
12102 // The last frame is an anonymous function that has the initial call to foo.
12103 checkStackFrame(origin, "", 10, 1, false, false,
12104 stackTrace->GetFrame(3));
12105
12106 CHECK(stackTrace->AsArray()->IsArray());
12107 }
12108 return v8::Undefined();
12109}
12110
12111
12112// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012113// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12114// THREADED_TEST(CaptureStackTrace) {
12115TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012116 v8::HandleScope scope;
12117 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12118 Local<ObjectTemplate> templ = ObjectTemplate::New();
12119 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12120 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12121 LocalContext context(0, templ);
12122
12123 // Test getting OVERVIEW information. Should ignore information that is not
12124 // script name, function name, line number, and column offset.
12125 const char *overview_source =
12126 "function bar() {\n"
12127 " var y; AnalyzeStackInNativeCode(1);\n"
12128 "}\n"
12129 "function foo() {\n"
12130 "\n"
12131 " bar();\n"
12132 "}\n"
12133 "var x;eval('new foo();');";
12134 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12135 v8::Handle<Value> overview_result =
12136 v8::Script::New(overview_src, origin)->Run();
12137 ASSERT(!overview_result.IsEmpty());
12138 ASSERT(overview_result->IsObject());
12139
12140 // Test getting DETAILED information.
12141 const char *detailed_source =
12142 "function bat() {AnalyzeStackInNativeCode(2);\n"
12143 "}\n"
12144 "\n"
12145 "function baz() {\n"
12146 " bat();\n"
12147 "}\n"
12148 "eval('new baz();');";
12149 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12150 // Make the script using a non-zero line and column offset.
12151 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12152 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12153 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12154 v8::Handle<v8::Script> detailed_script(
12155 v8::Script::New(detailed_src, &detailed_origin));
12156 v8::Handle<Value> detailed_result = detailed_script->Run();
12157 ASSERT(!detailed_result.IsEmpty());
12158 ASSERT(detailed_result->IsObject());
12159}
12160
12161
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012162static void StackTraceForUncaughtExceptionListener(
12163 v8::Handle<v8::Message> message,
12164 v8::Handle<Value>) {
12165 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12166 CHECK_EQ(2, stack_trace->GetFrameCount());
12167 checkStackFrame("origin", "foo", 2, 3, false, false,
12168 stack_trace->GetFrame(0));
12169 checkStackFrame("origin", "bar", 5, 3, false, false,
12170 stack_trace->GetFrame(1));
12171}
12172
12173TEST(CaptureStackTraceForUncaughtException) {
12174 report_count = 0;
12175 v8::HandleScope scope;
12176 LocalContext env;
12177 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12178 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12179
12180 Script::Compile(v8_str("function foo() {\n"
12181 " throw 1;\n"
12182 "};\n"
12183 "function bar() {\n"
12184 " foo();\n"
12185 "};"),
12186 v8_str("origin"))->Run();
12187 v8::Local<v8::Object> global = env->Global();
12188 Local<Value> trouble = global->Get(v8_str("bar"));
12189 CHECK(trouble->IsFunction());
12190 Function::Cast(*trouble)->Call(global, 0, NULL);
12191 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12192 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12193}
12194
12195
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012196TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12197 v8::HandleScope scope;
12198 LocalContext env;
12199 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12200 1024,
12201 v8::StackTrace::kDetailed);
12202
12203 CompileRun(
12204 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12205 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12206 " 'isConstructor'];\n"
12207 "for (var i = 0; i < setters.length; i++) {\n"
12208 " var prop = setters[i];\n"
12209 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12210 "}\n");
12211 CompileRun("throw 'exception';");
12212 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12213}
12214
12215
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012216v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12217 v8::HandleScope scope;
12218 v8::Handle<v8::StackTrace> stackTrace =
12219 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12220 CHECK_EQ(5, stackTrace->GetFrameCount());
12221 v8::Handle<v8::String> url = v8_str("eval_url");
12222 for (int i = 0; i < 3; i++) {
12223 v8::Handle<v8::String> name =
12224 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12225 CHECK(!name.IsEmpty());
12226 CHECK_EQ(url, name);
12227 }
12228 return v8::Undefined();
12229}
12230
12231
12232TEST(SourceURLInStackTrace) {
12233 v8::HandleScope scope;
12234 Local<ObjectTemplate> templ = ObjectTemplate::New();
12235 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12236 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12237 LocalContext context(0, templ);
12238
12239 const char *source =
12240 "function outer() {\n"
12241 "function bar() {\n"
12242 " AnalyzeStackOfEvalWithSourceURL();\n"
12243 "}\n"
12244 "function foo() {\n"
12245 "\n"
12246 " bar();\n"
12247 "}\n"
12248 "foo();\n"
12249 "}\n"
12250 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12251 CHECK(CompileRun(source)->IsUndefined());
12252}
12253
12254
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012255// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012256THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012257 bool rv = false;
12258 for (int i = 0; i < 100; i++) {
12259 rv = v8::V8::IdleNotification();
12260 if (rv)
12261 break;
12262 }
12263 CHECK(rv == true);
12264}
12265
12266
12267static uint32_t* stack_limit;
12268
12269static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 stack_limit = reinterpret_cast<uint32_t*>(
12271 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012272 return v8::Undefined();
12273}
12274
12275
12276// Uses the address of a local variable to determine the stack top now.
12277// Given a size, returns an address that is that far from the current
12278// top of stack.
12279static uint32_t* ComputeStackLimit(uint32_t size) {
12280 uint32_t* answer = &size - (size / sizeof(size));
12281 // If the size is very large and the stack is very near the bottom of
12282 // memory then the calculation above may wrap around and give an address
12283 // that is above the (downwards-growing) stack. In that case we return
12284 // a very low address.
12285 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12286 return answer;
12287}
12288
12289
12290TEST(SetResourceConstraints) {
12291 static const int K = 1024;
12292 uint32_t* set_limit = ComputeStackLimit(128 * K);
12293
12294 // Set stack limit.
12295 v8::ResourceConstraints constraints;
12296 constraints.set_stack_limit(set_limit);
12297 CHECK(v8::SetResourceConstraints(&constraints));
12298
12299 // Execute a script.
12300 v8::HandleScope scope;
12301 LocalContext env;
12302 Local<v8::FunctionTemplate> fun_templ =
12303 v8::FunctionTemplate::New(GetStackLimitCallback);
12304 Local<Function> fun = fun_templ->GetFunction();
12305 env->Global()->Set(v8_str("get_stack_limit"), fun);
12306 CompileRun("get_stack_limit();");
12307
12308 CHECK(stack_limit == set_limit);
12309}
12310
12311
12312TEST(SetResourceConstraintsInThread) {
12313 uint32_t* set_limit;
12314 {
12315 v8::Locker locker;
12316 static const int K = 1024;
12317 set_limit = ComputeStackLimit(128 * K);
12318
12319 // Set stack limit.
12320 v8::ResourceConstraints constraints;
12321 constraints.set_stack_limit(set_limit);
12322 CHECK(v8::SetResourceConstraints(&constraints));
12323
12324 // Execute a script.
12325 v8::HandleScope scope;
12326 LocalContext env;
12327 Local<v8::FunctionTemplate> fun_templ =
12328 v8::FunctionTemplate::New(GetStackLimitCallback);
12329 Local<Function> fun = fun_templ->GetFunction();
12330 env->Global()->Set(v8_str("get_stack_limit"), fun);
12331 CompileRun("get_stack_limit();");
12332
12333 CHECK(stack_limit == set_limit);
12334 }
12335 {
12336 v8::Locker locker;
12337 CHECK(stack_limit == set_limit);
12338 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000012339}
ager@chromium.org3811b432009-10-28 14:53:37 +000012340
12341
12342THREADED_TEST(GetHeapStatistics) {
12343 v8::HandleScope scope;
12344 LocalContext c1;
12345 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012346 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
12347 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000012348 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012349 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
12350 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000012351}
12352
12353
12354static double DoubleFromBits(uint64_t value) {
12355 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000012356 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000012357 return target;
12358}
12359
12360
12361static uint64_t DoubleToBits(double value) {
12362 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000012363 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000012364 return target;
12365}
12366
12367
12368static double DoubleToDateTime(double input) {
12369 double date_limit = 864e13;
12370 if (IsNaN(input) || input < -date_limit || input > date_limit) {
12371 return i::OS::nan_value();
12372 }
12373 return (input < 0) ? -(floor(-input)) : floor(input);
12374}
12375
12376// We don't have a consistent way to write 64-bit constants syntactically, so we
12377// split them into two 32-bit constants and combine them programmatically.
12378static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
12379 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
12380}
12381
12382
12383THREADED_TEST(QuietSignalingNaNs) {
12384 v8::HandleScope scope;
12385 LocalContext context;
12386 v8::TryCatch try_catch;
12387
12388 // Special double values.
12389 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
12390 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
12391 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
12392 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
12393 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
12394 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
12395 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
12396
12397 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
12398 // on either side of the epoch.
12399 double date_limit = 864e13;
12400
12401 double test_values[] = {
12402 snan,
12403 qnan,
12404 infinity,
12405 max_normal,
12406 date_limit + 1,
12407 date_limit,
12408 min_normal,
12409 max_denormal,
12410 min_denormal,
12411 0,
12412 -0,
12413 -min_denormal,
12414 -max_denormal,
12415 -min_normal,
12416 -date_limit,
12417 -date_limit - 1,
12418 -max_normal,
12419 -infinity,
12420 -qnan,
12421 -snan
12422 };
12423 int num_test_values = 20;
12424
12425 for (int i = 0; i < num_test_values; i++) {
12426 double test_value = test_values[i];
12427
12428 // Check that Number::New preserves non-NaNs and quiets SNaNs.
12429 v8::Handle<v8::Value> number = v8::Number::New(test_value);
12430 double stored_number = number->NumberValue();
12431 if (!IsNaN(test_value)) {
12432 CHECK_EQ(test_value, stored_number);
12433 } else {
12434 uint64_t stored_bits = DoubleToBits(stored_number);
12435 // Check if quiet nan (bits 51..62 all set).
12436 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12437 }
12438
12439 // Check that Date::New preserves non-NaNs in the date range and
12440 // quiets SNaNs.
12441 v8::Handle<v8::Value> date = v8::Date::New(test_value);
12442 double expected_stored_date = DoubleToDateTime(test_value);
12443 double stored_date = date->NumberValue();
12444 if (!IsNaN(expected_stored_date)) {
12445 CHECK_EQ(expected_stored_date, stored_date);
12446 } else {
12447 uint64_t stored_bits = DoubleToBits(stored_date);
12448 // Check if quiet nan (bits 51..62 all set).
12449 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12450 }
12451 }
12452}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000012453
12454
12455static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
12456 v8::HandleScope scope;
12457 v8::TryCatch tc;
12458 v8::Handle<v8::String> str = args[0]->ToString();
12459 if (tc.HasCaught())
12460 return tc.ReThrow();
12461 return v8::Undefined();
12462}
12463
12464
12465// Test that an exception can be propagated down through a spaghetti
12466// stack using ReThrow.
12467THREADED_TEST(SpaghettiStackReThrow) {
12468 v8::HandleScope scope;
12469 LocalContext context;
12470 context->Global()->Set(
12471 v8::String::New("s"),
12472 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
12473 v8::TryCatch try_catch;
12474 CompileRun(
12475 "var i = 0;"
12476 "var o = {"
12477 " toString: function () {"
12478 " if (i == 10) {"
12479 " throw 'Hey!';"
12480 " } else {"
12481 " i++;"
12482 " return s(o);"
12483 " }"
12484 " }"
12485 "};"
12486 "s(o);");
12487 CHECK(try_catch.HasCaught());
12488 v8::String::Utf8Value value(try_catch.Exception());
12489 CHECK_EQ(0, strcmp(*value, "Hey!"));
12490}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012491
12492
sgjesse@chromium.org98180592009-12-02 08:17:28 +000012493TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012494 v8::V8::Initialize();
12495
12496 v8::HandleScope scope;
12497 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000012498 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012499 int gc_count;
12500
ager@chromium.org60121232009-12-03 11:25:37 +000012501 // Create a context used to keep the code from aging in the compilation
12502 // cache.
12503 other_context = Context::New();
12504
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012505 // Context-dependent context data creates reference from the compilation
12506 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012507 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012508 context = Context::New();
12509 {
12510 v8::HandleScope scope;
12511
12512 context->Enter();
12513 Local<v8::String> obj = v8::String::New("");
12514 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000012515 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012516 context->Exit();
12517 }
12518 context.Dispose();
12519 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012520 other_context->Enter();
12521 CompileRun(source_simple);
12522 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012523 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012524 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012525 }
ager@chromium.org60121232009-12-03 11:25:37 +000012526 CHECK_GE(2, gc_count);
12527 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012528
12529 // Eval in a function creates reference from the compilation cache to the
12530 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012531 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012532 context = Context::New();
12533 {
12534 v8::HandleScope scope;
12535
12536 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000012537 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012538 context->Exit();
12539 }
12540 context.Dispose();
12541 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012542 other_context->Enter();
12543 CompileRun(source_eval);
12544 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012545 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012546 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012547 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012548 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000012549 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012550
12551 // Looking up the line number for an exception creates reference from the
12552 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012553 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012554 context = Context::New();
12555 {
12556 v8::HandleScope scope;
12557
12558 context->Enter();
12559 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000012560 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012561 CHECK(try_catch.HasCaught());
12562 v8::Handle<v8::Message> message = try_catch.Message();
12563 CHECK(!message.IsEmpty());
12564 CHECK_EQ(1, message->GetLineNumber());
12565 context->Exit();
12566 }
12567 context.Dispose();
12568 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012569 other_context->Enter();
12570 CompileRun(source_exception);
12571 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012572 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012573 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012574 }
ager@chromium.org60121232009-12-03 11:25:37 +000012575 CHECK_GE(2, gc_count);
12576 CHECK_EQ(1, GetGlobalObjectsCount());
12577
12578 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012579}
ager@chromium.org5c838252010-02-19 08:53:10 +000012580
12581
12582THREADED_TEST(ScriptOrigin) {
12583 v8::HandleScope scope;
12584 LocalContext env;
12585 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12586 v8::Handle<v8::String> script = v8::String::New(
12587 "function f() {}\n\nfunction g() {}");
12588 v8::Script::Compile(script, &origin)->Run();
12589 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12590 env->Global()->Get(v8::String::New("f")));
12591 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12592 env->Global()->Get(v8::String::New("g")));
12593
12594 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
12595 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
12596 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
12597
12598 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
12599 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
12600 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
12601}
12602
12603
12604THREADED_TEST(ScriptLineNumber) {
12605 v8::HandleScope scope;
12606 LocalContext env;
12607 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12608 v8::Handle<v8::String> script = v8::String::New(
12609 "function f() {}\n\nfunction g() {}");
12610 v8::Script::Compile(script, &origin)->Run();
12611 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12612 env->Global()->Get(v8::String::New("f")));
12613 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12614 env->Global()->Get(v8::String::New("g")));
12615 CHECK_EQ(0, f->GetScriptLineNumber());
12616 CHECK_EQ(2, g->GetScriptLineNumber());
12617}
12618
12619
12620static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
12621 const AccessorInfo& info) {
12622 return v8_num(42);
12623}
12624
12625
12626static void SetterWhichSetsYOnThisTo23(Local<String> name,
12627 Local<Value> value,
12628 const AccessorInfo& info) {
12629 info.This()->Set(v8_str("y"), v8_num(23));
12630}
12631
12632
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012633TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000012634 v8::HandleScope scope;
12635 Local<ObjectTemplate> templ = ObjectTemplate::New();
12636 templ->SetAccessor(v8_str("x"),
12637 GetterWhichReturns42,
12638 SetterWhichSetsYOnThisTo23);
12639 LocalContext context;
12640 context->Global()->Set(v8_str("P"), templ->NewInstance());
12641 CompileRun("function C1() {"
12642 " this.x = 23;"
12643 "};"
12644 "C1.prototype = P;"
12645 "function C2() {"
12646 " this.x = 23"
12647 "};"
12648 "C2.prototype = { };"
12649 "C2.prototype.__proto__ = P;");
12650
12651 v8::Local<v8::Script> script;
12652 script = v8::Script::Compile(v8_str("new C1();"));
12653 for (int i = 0; i < 10; i++) {
12654 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12655 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12656 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12657 }
12658
12659 script = v8::Script::Compile(v8_str("new C2();"));
12660 for (int i = 0; i < 10; i++) {
12661 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12662 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
12663 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
12664 }
12665}
12666
12667
12668static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
12669 Local<String> name, const AccessorInfo& info) {
12670 return v8_num(42);
12671}
12672
12673
12674static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
12675 Local<String> name, Local<Value> value, const AccessorInfo& info) {
12676 if (name->Equals(v8_str("x"))) {
12677 info.This()->Set(v8_str("y"), v8_num(23));
12678 }
12679 return v8::Handle<Value>();
12680}
12681
12682
12683THREADED_TEST(InterceptorOnConstructorPrototype) {
12684 v8::HandleScope scope;
12685 Local<ObjectTemplate> templ = ObjectTemplate::New();
12686 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
12687 NamedPropertySetterWhichSetsYOnThisTo23);
12688 LocalContext context;
12689 context->Global()->Set(v8_str("P"), templ->NewInstance());
12690 CompileRun("function C1() {"
12691 " this.x = 23;"
12692 "};"
12693 "C1.prototype = P;"
12694 "function C2() {"
12695 " this.x = 23"
12696 "};"
12697 "C2.prototype = { };"
12698 "C2.prototype.__proto__ = P;");
12699
12700 v8::Local<v8::Script> script;
12701 script = v8::Script::Compile(v8_str("new C1();"));
12702 for (int i = 0; i < 10; i++) {
12703 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12704 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12705 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12706 }
12707
12708 script = v8::Script::Compile(v8_str("new C2();"));
12709 for (int i = 0; i < 10; i++) {
12710 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
12711 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
12712 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
12713 }
12714}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012715
12716
12717TEST(Bug618) {
12718 const char* source = "function C1() {"
12719 " this.x = 23;"
12720 "};"
12721 "C1.prototype = P;";
12722
12723 v8::HandleScope scope;
12724 LocalContext context;
12725 v8::Local<v8::Script> script;
12726
12727 // Use a simple object as prototype.
12728 v8::Local<v8::Object> prototype = v8::Object::New();
12729 prototype->Set(v8_str("y"), v8_num(42));
12730 context->Global()->Set(v8_str("P"), prototype);
12731
12732 // This compile will add the code to the compilation cache.
12733 CompileRun(source);
12734
12735 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000012736 // Allow enough iterations for the inobject slack tracking logic
12737 // to finalize instance size and install the fast construct stub.
12738 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12740 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
12741 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
12742 }
12743
12744 // Use an API object with accessors as prototype.
12745 Local<ObjectTemplate> templ = ObjectTemplate::New();
12746 templ->SetAccessor(v8_str("x"),
12747 GetterWhichReturns42,
12748 SetterWhichSetsYOnThisTo23);
12749 context->Global()->Set(v8_str("P"), templ->NewInstance());
12750
12751 // This compile will get the code from the compilation cache.
12752 CompileRun(source);
12753
12754 script = v8::Script::Compile(v8_str("new C1();"));
12755 for (int i = 0; i < 10; i++) {
12756 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
12757 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
12758 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
12759 }
12760}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012761
12762int prologue_call_count = 0;
12763int epilogue_call_count = 0;
12764int prologue_call_count_second = 0;
12765int epilogue_call_count_second = 0;
12766
12767void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
12768 ++prologue_call_count;
12769}
12770
12771void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
12772 ++epilogue_call_count;
12773}
12774
12775void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12776 ++prologue_call_count_second;
12777}
12778
12779void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
12780 ++epilogue_call_count_second;
12781}
12782
12783TEST(GCCallbacks) {
12784 LocalContext context;
12785
12786 v8::V8::AddGCPrologueCallback(PrologueCallback);
12787 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
12788 CHECK_EQ(0, prologue_call_count);
12789 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012790 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012791 CHECK_EQ(1, prologue_call_count);
12792 CHECK_EQ(1, epilogue_call_count);
12793 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
12794 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012795 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012796 CHECK_EQ(2, prologue_call_count);
12797 CHECK_EQ(2, epilogue_call_count);
12798 CHECK_EQ(1, prologue_call_count_second);
12799 CHECK_EQ(1, epilogue_call_count_second);
12800 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
12801 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012802 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012803 CHECK_EQ(2, prologue_call_count);
12804 CHECK_EQ(2, epilogue_call_count);
12805 CHECK_EQ(2, prologue_call_count_second);
12806 CHECK_EQ(2, epilogue_call_count_second);
12807 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
12808 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012809 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012810 CHECK_EQ(2, prologue_call_count);
12811 CHECK_EQ(2, epilogue_call_count);
12812 CHECK_EQ(2, prologue_call_count_second);
12813 CHECK_EQ(2, epilogue_call_count_second);
12814}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012815
12816
12817THREADED_TEST(AddToJSFunctionResultCache) {
12818 i::FLAG_allow_natives_syntax = true;
12819 v8::HandleScope scope;
12820
12821 LocalContext context;
12822
12823 const char* code =
12824 "(function() {"
12825 " var key0 = 'a';"
12826 " var key1 = 'b';"
12827 " var r0 = %_GetFromCache(0, key0);"
12828 " var r1 = %_GetFromCache(0, key1);"
12829 " var r0_ = %_GetFromCache(0, key0);"
12830 " if (r0 !== r0_)"
12831 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
12832 " var r1_ = %_GetFromCache(0, key1);"
12833 " if (r1 !== r1_)"
12834 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
12835 " return 'PASSED';"
12836 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012837 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012838 ExpectString(code, "PASSED");
12839}
12840
12841
12842static const int k0CacheSize = 16;
12843
12844THREADED_TEST(FillJSFunctionResultCache) {
12845 i::FLAG_allow_natives_syntax = true;
12846 v8::HandleScope scope;
12847
12848 LocalContext context;
12849
12850 const char* code =
12851 "(function() {"
12852 " var k = 'a';"
12853 " var r = %_GetFromCache(0, k);"
12854 " for (var i = 0; i < 16; i++) {"
12855 " %_GetFromCache(0, 'a' + i);"
12856 " };"
12857 " if (r === %_GetFromCache(0, k))"
12858 " return 'FAILED: k0CacheSize is too small';"
12859 " return 'PASSED';"
12860 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012861 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012862 ExpectString(code, "PASSED");
12863}
12864
12865
12866THREADED_TEST(RoundRobinGetFromCache) {
12867 i::FLAG_allow_natives_syntax = true;
12868 v8::HandleScope scope;
12869
12870 LocalContext context;
12871
12872 const char* code =
12873 "(function() {"
12874 " var keys = [];"
12875 " for (var i = 0; i < 16; i++) keys.push(i);"
12876 " var values = [];"
12877 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12878 " for (var i = 0; i < 16; i++) {"
12879 " var v = %_GetFromCache(0, keys[i]);"
12880 " if (v !== values[i])"
12881 " return 'Wrong value for ' + "
12882 " keys[i] + ': ' + v + ' vs. ' + values[i];"
12883 " };"
12884 " return 'PASSED';"
12885 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012886 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012887 ExpectString(code, "PASSED");
12888}
12889
12890
12891THREADED_TEST(ReverseGetFromCache) {
12892 i::FLAG_allow_natives_syntax = true;
12893 v8::HandleScope scope;
12894
12895 LocalContext context;
12896
12897 const char* code =
12898 "(function() {"
12899 " var keys = [];"
12900 " for (var i = 0; i < 16; i++) keys.push(i);"
12901 " var values = [];"
12902 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
12903 " for (var i = 15; i >= 16; i--) {"
12904 " var v = %_GetFromCache(0, keys[i]);"
12905 " if (v !== values[i])"
12906 " return 'Wrong value for ' + "
12907 " keys[i] + ': ' + v + ' vs. ' + values[i];"
12908 " };"
12909 " return 'PASSED';"
12910 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012911 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012912 ExpectString(code, "PASSED");
12913}
12914
12915
12916THREADED_TEST(TestEviction) {
12917 i::FLAG_allow_natives_syntax = true;
12918 v8::HandleScope scope;
12919
12920 LocalContext context;
12921
12922 const char* code =
12923 "(function() {"
12924 " for (var i = 0; i < 2*16; i++) {"
12925 " %_GetFromCache(0, 'a' + i);"
12926 " };"
12927 " return 'PASSED';"
12928 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012929 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012930 ExpectString(code, "PASSED");
12931}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012932
12933
12934THREADED_TEST(TwoByteStringInAsciiCons) {
12935 // See Chromium issue 47824.
12936 v8::HandleScope scope;
12937
12938 LocalContext context;
12939 const char* init_code =
12940 "var str1 = 'abelspendabel';"
12941 "var str2 = str1 + str1 + str1;"
12942 "str2;";
12943 Local<Value> result = CompileRun(init_code);
12944
12945 CHECK(result->IsString());
12946 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
12947 int length = string->length();
12948 CHECK(string->IsAsciiRepresentation());
12949
12950 FlattenString(string);
12951 i::Handle<i::String> flat_string = FlattenGetString(string);
12952
12953 CHECK(string->IsAsciiRepresentation());
12954 CHECK(flat_string->IsAsciiRepresentation());
12955
12956 // Create external resource.
12957 uint16_t* uc16_buffer = new uint16_t[length + 1];
12958
12959 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
12960 uc16_buffer[length] = 0;
12961
12962 TestResource resource(uc16_buffer);
12963
12964 flat_string->MakeExternal(&resource);
12965
12966 CHECK(flat_string->IsTwoByteRepresentation());
12967
12968 // At this point, we should have a Cons string which is flat and ASCII,
12969 // with a first half that is a two-byte string (although it only contains
12970 // ASCII characters). This is a valid sequence of steps, and it can happen
12971 // in real pages.
12972
12973 CHECK(string->IsAsciiRepresentation());
12974 i::ConsString* cons = i::ConsString::cast(*string);
12975 CHECK_EQ(0, cons->second()->length());
12976 CHECK(cons->first()->IsTwoByteRepresentation());
12977
12978 // Check that some string operations work.
12979
12980 // Atom RegExp.
12981 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
12982 CHECK_EQ(6, reresult->Int32Value());
12983
12984 // Nonatom RegExp.
12985 reresult = CompileRun("str2.match(/abe./g).length;");
12986 CHECK_EQ(6, reresult->Int32Value());
12987
12988 reresult = CompileRun("str2.search(/bel/g);");
12989 CHECK_EQ(1, reresult->Int32Value());
12990
12991 reresult = CompileRun("str2.search(/be./g);");
12992 CHECK_EQ(1, reresult->Int32Value());
12993
12994 ExpectTrue("/bel/g.test(str2);");
12995
12996 ExpectTrue("/be./g.test(str2);");
12997
12998 reresult = CompileRun("/bel/g.exec(str2);");
12999 CHECK(!reresult->IsNull());
13000
13001 reresult = CompileRun("/be./g.exec(str2);");
13002 CHECK(!reresult->IsNull());
13003
13004 ExpectString("str2.substring(2, 10);", "elspenda");
13005
13006 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13007
13008 ExpectString("str2.charAt(2);", "e");
13009
13010 reresult = CompileRun("str2.charCodeAt(2);");
13011 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13012}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013013
13014
13015// Failed access check callback that performs a GC on each invocation.
13016void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13017 v8::AccessType type,
13018 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013020}
13021
13022
13023TEST(GCInFailedAccessCheckCallback) {
13024 // Install a failed access check callback that performs a GC on each
13025 // invocation. Then force the callback to be called from va
13026
13027 v8::V8::Initialize();
13028 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13029
13030 v8::HandleScope scope;
13031
13032 // Create an ObjectTemplate for global objects and install access
13033 // check callbacks that will block access.
13034 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13035 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13036 IndexedGetAccessBlocker,
13037 v8::Handle<v8::Value>(),
13038 false);
13039
13040 // Create a context and set an x property on it's global object.
13041 LocalContext context0(NULL, global_template);
13042 context0->Global()->Set(v8_str("x"), v8_num(42));
13043 v8::Handle<v8::Object> global0 = context0->Global();
13044
13045 // Create a context with a different security token so that the
13046 // failed access check callback will be called on each access.
13047 LocalContext context1(NULL, global_template);
13048 context1->Global()->Set(v8_str("other"), global0);
13049
13050 // Get property with failed access check.
13051 ExpectUndefined("other.x");
13052
13053 // Get element with failed access check.
13054 ExpectUndefined("other[0]");
13055
13056 // Set property with failed access check.
13057 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13058 CHECK(result->IsObject());
13059
13060 // Set element with failed access check.
13061 result = CompileRun("other[0] = new Object()");
13062 CHECK(result->IsObject());
13063
13064 // Get property attribute with failed access check.
13065 ExpectFalse("\'x\' in other");
13066
13067 // Get property attribute for element with failed access check.
13068 ExpectFalse("0 in other");
13069
13070 // Delete property.
13071 ExpectFalse("delete other.x");
13072
13073 // Delete element.
13074 CHECK_EQ(false, global0->Delete(0));
13075
13076 // DefineAccessor.
13077 CHECK_EQ(false,
13078 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13079
13080 // Define JavaScript accessor.
13081 ExpectUndefined("Object.prototype.__defineGetter__.call("
13082 " other, \'x\', function() { return 42; })");
13083
13084 // LookupAccessor.
13085 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13086 " other, \'x\')");
13087
13088 // HasLocalElement.
13089 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13090
13091 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13092 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13093 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13094
13095 // Reset the failed access check callback so it does not influence
13096 // the other tests.
13097 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13098}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013100TEST(DefaultIsolateGetCurrent) {
13101 CHECK(v8::Isolate::GetCurrent() != NULL);
13102 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13103 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13104 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13105}
13106
13107TEST(IsolateNewDispose) {
13108 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13109 v8::Isolate* isolate = v8::Isolate::New();
13110 CHECK(isolate != NULL);
13111 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13112 CHECK(current_isolate != isolate);
13113 CHECK(current_isolate == v8::Isolate::GetCurrent());
13114
13115 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13116 last_location = last_message = NULL;
13117 isolate->Dispose();
13118 CHECK_EQ(last_location, NULL);
13119 CHECK_EQ(last_message, NULL);
13120}
13121
13122TEST(IsolateEnterExitDefault) {
13123 v8::HandleScope scope;
13124 LocalContext context;
13125 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13126 CHECK(current_isolate != NULL); // Default isolate.
13127 ExpectString("'hello'", "hello");
13128 current_isolate->Enter();
13129 ExpectString("'still working'", "still working");
13130 current_isolate->Exit();
13131 ExpectString("'still working 2'", "still working 2");
13132 current_isolate->Exit();
13133 // Default isolate is always, well, 'default current'.
13134 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13135 // Still working since default isolate is auto-entering any thread
13136 // that has no isolate and attempts to execute V8 APIs.
13137 ExpectString("'still working 3'", "still working 3");
13138}
13139
13140TEST(DisposeDefaultIsolate) {
13141 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13142
13143 // Run some V8 code to trigger default isolate to become 'current'.
13144 v8::HandleScope scope;
13145 LocalContext context;
13146 ExpectString("'run some V8'", "run some V8");
13147
13148 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13149 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13150 last_location = last_message = NULL;
13151 isolate->Dispose();
13152 // It is not possible to dispose default isolate via Isolate API.
13153 CHECK_NE(last_location, NULL);
13154 CHECK_NE(last_message, NULL);
13155}
13156
13157TEST(RunDefaultAndAnotherIsolate) {
13158 v8::HandleScope scope;
13159 LocalContext context;
13160
13161 // Enter new isolate.
13162 v8::Isolate* isolate = v8::Isolate::New();
13163 CHECK(isolate);
13164 isolate->Enter();
13165 { // Need this block because subsequent Exit() will deallocate Heap,
13166 // so we need all scope objects to be deconstructed when it happens.
13167 v8::HandleScope scope_new;
13168 LocalContext context_new;
13169
13170 // Run something in new isolate.
13171 CompileRun("var foo = 153;");
13172 ExpectTrue("function f() { return foo == 153; }; f()");
13173 }
13174 isolate->Exit();
13175
13176 // This runs automatically in default isolate.
13177 // Variables in another isolate should be not available.
13178 ExpectTrue("function f() {"
13179 " try {"
13180 " foo;"
13181 " return false;"
13182 " } catch(e) {"
13183 " return true;"
13184 " }"
13185 "};"
13186 "var bar = 371;"
13187 "f()");
13188
13189 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13190 last_location = last_message = NULL;
13191 isolate->Dispose();
13192 CHECK_EQ(last_location, NULL);
13193 CHECK_EQ(last_message, NULL);
13194
13195 // Check that default isolate still runs.
13196 ExpectTrue("function f() { return bar == 371; }; f()");
13197}
13198
13199TEST(DisposeIsolateWhenInUse) {
13200 v8::Isolate* isolate = v8::Isolate::New();
13201 CHECK(isolate);
13202 isolate->Enter();
13203 v8::HandleScope scope;
13204 LocalContext context;
13205 // Run something in this isolate.
13206 ExpectTrue("true");
13207 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13208 last_location = last_message = NULL;
13209 // Still entered, should fail.
13210 isolate->Dispose();
13211 CHECK_NE(last_location, NULL);
13212 CHECK_NE(last_message, NULL);
13213}
13214
13215TEST(RunTwoIsolatesOnSingleThread) {
13216 // Run isolate 1.
13217 v8::Isolate* isolate1 = v8::Isolate::New();
13218 isolate1->Enter();
13219 v8::Persistent<v8::Context> context1 = v8::Context::New();
13220
13221 {
13222 v8::Context::Scope cscope(context1);
13223 v8::HandleScope scope;
13224 // Run something in new isolate.
13225 CompileRun("var foo = 'isolate 1';");
13226 ExpectString("function f() { return foo; }; f()", "isolate 1");
13227 }
13228
13229 // Run isolate 2.
13230 v8::Isolate* isolate2 = v8::Isolate::New();
13231 v8::Persistent<v8::Context> context2;
13232
13233 {
13234 v8::Isolate::Scope iscope(isolate2);
13235 context2 = v8::Context::New();
13236 v8::Context::Scope cscope(context2);
13237 v8::HandleScope scope;
13238
13239 // Run something in new isolate.
13240 CompileRun("var foo = 'isolate 2';");
13241 ExpectString("function f() { return foo; }; f()", "isolate 2");
13242 }
13243
13244 {
13245 v8::Context::Scope cscope(context1);
13246 v8::HandleScope scope;
13247 // Now again in isolate 1
13248 ExpectString("function f() { return foo; }; f()", "isolate 1");
13249 }
13250
13251 isolate1->Exit();
13252
13253 // Run some stuff in default isolate.
13254 v8::Persistent<v8::Context> context_default = v8::Context::New();
13255
13256 {
13257 v8::Context::Scope cscope(context_default);
13258 v8::HandleScope scope;
13259 // Variables in other isolates should be not available, verify there
13260 // is an exception.
13261 ExpectTrue("function f() {"
13262 " try {"
13263 " foo;"
13264 " return false;"
13265 " } catch(e) {"
13266 " return true;"
13267 " }"
13268 "};"
13269 "var isDefaultIsolate = true;"
13270 "f()");
13271 }
13272
13273 isolate1->Enter();
13274
13275 {
13276 v8::Isolate::Scope iscope(isolate2);
13277 v8::Context::Scope cscope(context2);
13278 v8::HandleScope scope;
13279 ExpectString("function f() { return foo; }; f()", "isolate 2");
13280 }
13281
13282 {
13283 v8::Context::Scope cscope(context1);
13284 v8::HandleScope scope;
13285 ExpectString("function f() { return foo; }; f()", "isolate 1");
13286 }
13287
13288 {
13289 v8::Isolate::Scope iscope(isolate2);
13290 context2.Dispose();
13291 }
13292
13293 context1.Dispose();
13294 isolate1->Exit();
13295
13296 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13297 last_location = last_message = NULL;
13298
13299 isolate1->Dispose();
13300 CHECK_EQ(last_location, NULL);
13301 CHECK_EQ(last_message, NULL);
13302
13303 isolate2->Dispose();
13304 CHECK_EQ(last_location, NULL);
13305 CHECK_EQ(last_message, NULL);
13306
13307 // Check that default isolate still runs.
13308 {
13309 v8::Context::Scope cscope(context_default);
13310 v8::HandleScope scope;
13311 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
13312 }
13313}
13314
13315static int CalcFibonacci(v8::Isolate* isolate, int limit) {
13316 v8::Isolate::Scope isolate_scope(isolate);
13317 v8::HandleScope scope;
13318 LocalContext context;
13319 i::ScopedVector<char> code(1024);
13320 i::OS::SNPrintF(code, "function fib(n) {"
13321 " if (n <= 2) return 1;"
13322 " return fib(n-1) + fib(n-2);"
13323 "}"
13324 "fib(%d)", limit);
13325 Local<Value> value = CompileRun(code.start());
13326 CHECK(value->IsNumber());
13327 return static_cast<int>(value->NumberValue());
13328}
13329
13330class IsolateThread : public v8::internal::Thread {
13331 public:
13332 explicit IsolateThread(v8::Isolate* isolate, int fib_limit)
13333 : Thread(NULL, "IsolateThread"),
13334 isolate_(isolate),
13335 fib_limit_(fib_limit),
13336 result_(0) { }
13337
13338 void Run() {
13339 result_ = CalcFibonacci(isolate_, fib_limit_);
13340 }
13341
13342 int result() { return result_; }
13343
13344 private:
13345 v8::Isolate* isolate_;
13346 int fib_limit_;
13347 int result_;
13348};
13349
13350TEST(MultipleIsolatesOnIndividualThreads) {
13351 v8::Isolate* isolate1 = v8::Isolate::New();
13352 v8::Isolate* isolate2 = v8::Isolate::New();
13353
13354 IsolateThread thread1(isolate1, 21);
13355 IsolateThread thread2(isolate2, 12);
13356
13357 // Compute some fibonacci numbers on 3 threads in 3 isolates.
13358 thread1.Start();
13359 thread2.Start();
13360
13361 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
13362 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
13363
13364 thread1.Join();
13365 thread2.Join();
13366
13367 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
13368 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
13369 CHECK_EQ(result1, 10946);
13370 CHECK_EQ(result2, 144);
13371 CHECK_EQ(result1, thread1.result());
13372 CHECK_EQ(result2, thread2.result());
13373
13374 isolate1->Dispose();
13375 isolate2->Dispose();
13376}
13377
13378
13379class InitDefaultIsolateThread : public v8::internal::Thread {
13380 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013381 enum TestCase {
13382 IgnoreOOM,
13383 SetResourceConstraints,
13384 SetFatalHandler,
13385 SetCounterFunction,
13386 SetCreateHistogramFunction,
13387 SetAddHistogramSampleFunction
13388 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013389
13390 explicit InitDefaultIsolateThread(TestCase testCase)
13391 : Thread(NULL, "InitDefaultIsolateThread"),
13392 testCase_(testCase),
13393 result_(false) { }
13394
13395 void Run() {
13396 switch (testCase_) {
13397 case IgnoreOOM:
13398 v8::V8::IgnoreOutOfMemoryException();
13399 break;
13400
13401 case SetResourceConstraints: {
13402 static const int K = 1024;
13403 v8::ResourceConstraints constraints;
13404 constraints.set_max_young_space_size(256 * K);
13405 constraints.set_max_old_space_size(4 * K * K);
13406 v8::SetResourceConstraints(&constraints);
13407 break;
13408 }
13409
13410 case SetFatalHandler:
13411 v8::V8::SetFatalErrorHandler(NULL);
13412 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013413
13414 case SetCounterFunction:
13415 v8::V8::SetCounterFunction(NULL);
13416 break;
13417
13418 case SetCreateHistogramFunction:
13419 v8::V8::SetCreateHistogramFunction(NULL);
13420 break;
13421
13422 case SetAddHistogramSampleFunction:
13423 v8::V8::SetAddHistogramSampleFunction(NULL);
13424 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013425 }
13426 result_ = true;
13427 }
13428
13429 bool result() { return result_; }
13430
13431 private:
13432 TestCase testCase_;
13433 bool result_;
13434};
13435
13436
13437static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
13438 InitDefaultIsolateThread thread(testCase);
13439 thread.Start();
13440 thread.Join();
13441 CHECK_EQ(thread.result(), true);
13442}
13443
13444TEST(InitializeDefaultIsolateOnSecondaryThread1) {
13445 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
13446}
13447
13448TEST(InitializeDefaultIsolateOnSecondaryThread2) {
13449 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
13450}
13451
13452TEST(InitializeDefaultIsolateOnSecondaryThread3) {
13453 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
13454}
13455
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013456TEST(InitializeDefaultIsolateOnSecondaryThread4) {
13457 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
13458}
13459
13460TEST(InitializeDefaultIsolateOnSecondaryThread5) {
13461 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
13462}
13463
13464TEST(InitializeDefaultIsolateOnSecondaryThread6) {
13465 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
13466}
13467
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013468
13469TEST(StringCheckMultipleContexts) {
13470 const char* code =
13471 "(function() { return \"a\".charAt(0); })()";
13472
13473 {
13474 // Run the code twice in the first context to initialize the call IC.
13475 v8::HandleScope scope;
13476 LocalContext context1;
13477 ExpectString(code, "a");
13478 ExpectString(code, "a");
13479 }
13480
13481 {
13482 // Change the String.prototype in the second context and check
13483 // that the right function gets called.
13484 v8::HandleScope scope;
13485 LocalContext context2;
13486 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
13487 ExpectString(code, "not a");
13488 }
13489}
13490
13491
13492TEST(NumberCheckMultipleContexts) {
13493 const char* code =
13494 "(function() { return (42).toString(); })()";
13495
13496 {
13497 // Run the code twice in the first context to initialize the call IC.
13498 v8::HandleScope scope;
13499 LocalContext context1;
13500 ExpectString(code, "42");
13501 ExpectString(code, "42");
13502 }
13503
13504 {
13505 // Change the Number.prototype in the second context and check
13506 // that the right function gets called.
13507 v8::HandleScope scope;
13508 LocalContext context2;
13509 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
13510 ExpectString(code, "not 42");
13511 }
13512}
13513
13514
13515TEST(BooleanCheckMultipleContexts) {
13516 const char* code =
13517 "(function() { return true.toString(); })()";
13518
13519 {
13520 // Run the code twice in the first context to initialize the call IC.
13521 v8::HandleScope scope;
13522 LocalContext context1;
13523 ExpectString(code, "true");
13524 ExpectString(code, "true");
13525 }
13526
13527 {
13528 // Change the Boolean.prototype in the second context and check
13529 // that the right function gets called.
13530 v8::HandleScope scope;
13531 LocalContext context2;
13532 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
13533 ExpectString(code, "");
13534 }
13535}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000013536
13537
13538TEST(DontDeleteCellLoadIC) {
13539 const char* function_code =
13540 "function readCell() { while (true) { return cell; } }";
13541
13542 {
13543 // Run the code twice in the first context to initialize the load
13544 // IC for a don't delete cell.
13545 v8::HandleScope scope;
13546 LocalContext context1;
13547 CompileRun("var cell = \"first\";");
13548 ExpectBoolean("delete cell", false);
13549 CompileRun(function_code);
13550 ExpectString("readCell()", "first");
13551 ExpectString("readCell()", "first");
13552 }
13553
13554 {
13555 // Use a deletable cell in the second context.
13556 v8::HandleScope scope;
13557 LocalContext context2;
13558 CompileRun("cell = \"second\";");
13559 CompileRun(function_code);
13560 ExpectString("readCell()", "second");
13561 ExpectBoolean("delete cell", true);
13562 ExpectString("(function() {"
13563 " try {"
13564 " return readCell();"
13565 " } catch(e) {"
13566 " return e.toString();"
13567 " }"
13568 "})()",
13569 "ReferenceError: cell is not defined");
13570 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013571 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000013572 ExpectString("readCell()", "new_second");
13573 ExpectString("readCell()", "new_second");
13574 }
13575}
13576
13577
13578TEST(DontDeleteCellLoadICForceDelete) {
13579 const char* function_code =
13580 "function readCell() { while (true) { return cell; } }";
13581
13582 // Run the code twice to initialize the load IC for a don't delete
13583 // cell.
13584 v8::HandleScope scope;
13585 LocalContext context;
13586 CompileRun("var cell = \"value\";");
13587 ExpectBoolean("delete cell", false);
13588 CompileRun(function_code);
13589 ExpectString("readCell()", "value");
13590 ExpectString("readCell()", "value");
13591
13592 // Delete the cell using the API and check the inlined code works
13593 // correctly.
13594 CHECK(context->Global()->ForceDelete(v8_str("cell")));
13595 ExpectString("(function() {"
13596 " try {"
13597 " return readCell();"
13598 " } catch(e) {"
13599 " return e.toString();"
13600 " }"
13601 "})()",
13602 "ReferenceError: cell is not defined");
13603}
13604
13605
13606TEST(DontDeleteCellLoadICAPI) {
13607 const char* function_code =
13608 "function readCell() { while (true) { return cell; } }";
13609
13610 // Run the code twice to initialize the load IC for a don't delete
13611 // cell created using the API.
13612 v8::HandleScope scope;
13613 LocalContext context;
13614 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
13615 ExpectBoolean("delete cell", false);
13616 CompileRun(function_code);
13617 ExpectString("readCell()", "value");
13618 ExpectString("readCell()", "value");
13619
13620 // Delete the cell using the API and check the inlined code works
13621 // correctly.
13622 CHECK(context->Global()->ForceDelete(v8_str("cell")));
13623 ExpectString("(function() {"
13624 " try {"
13625 " return readCell();"
13626 " } catch(e) {"
13627 " return e.toString();"
13628 " }"
13629 "})()",
13630 "ReferenceError: cell is not defined");
13631}
13632
13633
13634TEST(GlobalLoadICGC) {
13635 const char* function_code =
13636 "function readCell() { while (true) { return cell; } }";
13637
13638 // Check inline load code for a don't delete cell is cleared during
13639 // GC.
13640 {
13641 v8::HandleScope scope;
13642 LocalContext context;
13643 CompileRun("var cell = \"value\";");
13644 ExpectBoolean("delete cell", false);
13645 CompileRun(function_code);
13646 ExpectString("readCell()", "value");
13647 ExpectString("readCell()", "value");
13648 }
13649 {
13650 v8::HandleScope scope;
13651 LocalContext context2;
13652 // Hold the code object in the second context.
13653 CompileRun(function_code);
13654 CheckSurvivingGlobalObjectsCount(1);
13655 }
13656
13657 // Check inline load code for a deletable cell is cleared during GC.
13658 {
13659 v8::HandleScope scope;
13660 LocalContext context;
13661 CompileRun("cell = \"value\";");
13662 CompileRun(function_code);
13663 ExpectString("readCell()", "value");
13664 ExpectString("readCell()", "value");
13665 }
13666 {
13667 v8::HandleScope scope;
13668 LocalContext context2;
13669 // Hold the code object in the second context.
13670 CompileRun(function_code);
13671 CheckSurvivingGlobalObjectsCount(1);
13672 }
13673}
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000013674
13675
13676TEST(RegExp) {
13677 v8::HandleScope scope;
13678 LocalContext context;
13679
13680 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
13681 CHECK(re->IsRegExp());
13682 CHECK(re->GetSource()->Equals(v8_str("foo")));
13683 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13684
13685 re = v8::RegExp::New(v8_str("bar"),
13686 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13687 v8::RegExp::kGlobal));
13688 CHECK(re->IsRegExp());
13689 CHECK(re->GetSource()->Equals(v8_str("bar")));
13690 CHECK_EQ(static_cast<int>(re->GetFlags()),
13691 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
13692
13693 re = v8::RegExp::New(v8_str("baz"),
13694 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13695 v8::RegExp::kMultiline));
13696 CHECK(re->IsRegExp());
13697 CHECK(re->GetSource()->Equals(v8_str("baz")));
13698 CHECK_EQ(static_cast<int>(re->GetFlags()),
13699 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13700
13701 re = CompileRun("/quux/").As<v8::RegExp>();
13702 CHECK(re->IsRegExp());
13703 CHECK(re->GetSource()->Equals(v8_str("quux")));
13704 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13705
13706 re = CompileRun("/quux/gm").As<v8::RegExp>();
13707 CHECK(re->IsRegExp());
13708 CHECK(re->GetSource()->Equals(v8_str("quux")));
13709 CHECK_EQ(static_cast<int>(re->GetFlags()),
13710 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
13711
13712 // Override the RegExp constructor and check the API constructor
13713 // still works.
13714 CompileRun("RegExp = function() {}");
13715
13716 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
13717 CHECK(re->IsRegExp());
13718 CHECK(re->GetSource()->Equals(v8_str("foobar")));
13719 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
13720
13721 re = v8::RegExp::New(v8_str("foobarbaz"),
13722 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
13723 v8::RegExp::kMultiline));
13724 CHECK(re->IsRegExp());
13725 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
13726 CHECK_EQ(static_cast<int>(re->GetFlags()),
13727 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
13728
13729 context->Global()->Set(v8_str("re"), re);
13730 ExpectTrue("re.test('FoobarbaZ')");
13731
13732 v8::TryCatch try_catch;
13733 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
13734 CHECK(re.IsEmpty());
13735 CHECK(try_catch.HasCaught());
13736 context->Global()->Set(v8_str("ex"), try_catch.Exception());
13737 ExpectTrue("ex instanceof SyntaxError");
13738}
13739
13740
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013741THREADED_TEST(Equals) {
13742 v8::HandleScope handleScope;
13743 LocalContext localContext;
13744
13745 v8::Handle<v8::Object> globalProxy = localContext->Global();
13746 v8::Handle<Value> global = globalProxy->GetPrototype();
13747
13748 CHECK(global->StrictEquals(global));
13749 CHECK(!global->StrictEquals(globalProxy));
13750 CHECK(!globalProxy->StrictEquals(global));
13751 CHECK(globalProxy->StrictEquals(globalProxy));
13752
13753 CHECK(global->Equals(global));
13754 CHECK(!global->Equals(globalProxy));
13755 CHECK(!globalProxy->Equals(global));
13756 CHECK(globalProxy->Equals(globalProxy));
13757}
13758
13759
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000013760static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
13761 const v8::AccessorInfo& info ) {
13762 return v8_str("42!");
13763}
13764
13765
13766static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
13767 v8::Handle<v8::Array> result = v8::Array::New();
13768 result->Set(0, v8_str("universalAnswer"));
13769 return result;
13770}
13771
13772
13773TEST(NamedEnumeratorAndForIn) {
13774 v8::HandleScope handle_scope;
13775 LocalContext context;
13776 v8::Context::Scope context_scope(context.local());
13777
13778 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
13779 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
13780 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
13781 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
13782 "var result = []; for (var k in o) result.push(k); result"));
13783 CHECK_EQ(1, result->Length());
13784 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
13785}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000013786
13787
13788TEST(DefinePropertyPostDetach) {
13789 v8::HandleScope scope;
13790 LocalContext context;
13791 v8::Handle<v8::Object> proxy = context->Global();
13792 v8::Handle<v8::Function> define_property =
13793 CompileRun("(function() {"
13794 " Object.defineProperty("
13795 " this,"
13796 " 1,"
13797 " { configurable: true, enumerable: true, value: 3 });"
13798 "})").As<Function>();
13799 context->DetachGlobal();
13800 define_property->Call(proxy, 0, NULL);
13801}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013802
13803
13804static void InstallContextId(v8::Handle<Context> context, int id) {
13805 Context::Scope scope(context);
13806 CompileRun("Object.prototype").As<Object>()->
13807 Set(v8_str("context_id"), v8::Integer::New(id));
13808}
13809
13810
13811static void CheckContextId(v8::Handle<Object> object, int expected) {
13812 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
13813}
13814
13815
13816THREADED_TEST(CreationContext) {
13817 HandleScope handle_scope;
13818 Persistent<Context> context1 = Context::New();
13819 InstallContextId(context1, 1);
13820 Persistent<Context> context2 = Context::New();
13821 InstallContextId(context2, 2);
13822 Persistent<Context> context3 = Context::New();
13823 InstallContextId(context3, 3);
13824
13825 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
13826
13827 Local<Object> object1;
13828 Local<Function> func1;
13829 {
13830 Context::Scope scope(context1);
13831 object1 = Object::New();
13832 func1 = tmpl->GetFunction();
13833 }
13834
13835 Local<Object> object2;
13836 Local<Function> func2;
13837 {
13838 Context::Scope scope(context2);
13839 object2 = Object::New();
13840 func2 = tmpl->GetFunction();
13841 }
13842
13843 Local<Object> instance1;
13844 Local<Object> instance2;
13845
13846 {
13847 Context::Scope scope(context3);
13848 instance1 = func1->NewInstance();
13849 instance2 = func2->NewInstance();
13850 }
13851
13852 CHECK(object1->CreationContext() == context1);
13853 CheckContextId(object1, 1);
13854 CHECK(func1->CreationContext() == context1);
13855 CheckContextId(func1, 1);
13856 CHECK(instance1->CreationContext() == context1);
13857 CheckContextId(instance1, 1);
13858 CHECK(object2->CreationContext() == context2);
13859 CheckContextId(object2, 2);
13860 CHECK(func2->CreationContext() == context2);
13861 CheckContextId(func2, 2);
13862 CHECK(instance2->CreationContext() == context2);
13863 CheckContextId(instance2, 2);
13864
13865 {
13866 Context::Scope scope(context1);
13867 CHECK(object1->CreationContext() == context1);
13868 CheckContextId(object1, 1);
13869 CHECK(func1->CreationContext() == context1);
13870 CheckContextId(func1, 1);
13871 CHECK(instance1->CreationContext() == context1);
13872 CheckContextId(instance1, 1);
13873 CHECK(object2->CreationContext() == context2);
13874 CheckContextId(object2, 2);
13875 CHECK(func2->CreationContext() == context2);
13876 CheckContextId(func2, 2);
13877 CHECK(instance2->CreationContext() == context2);
13878 CheckContextId(instance2, 2);
13879 }
13880
13881 {
13882 Context::Scope scope(context2);
13883 CHECK(object1->CreationContext() == context1);
13884 CheckContextId(object1, 1);
13885 CHECK(func1->CreationContext() == context1);
13886 CheckContextId(func1, 1);
13887 CHECK(instance1->CreationContext() == context1);
13888 CheckContextId(instance1, 1);
13889 CHECK(object2->CreationContext() == context2);
13890 CheckContextId(object2, 2);
13891 CHECK(func2->CreationContext() == context2);
13892 CheckContextId(func2, 2);
13893 CHECK(instance2->CreationContext() == context2);
13894 CheckContextId(instance2, 2);
13895 }
13896
13897 context1.Dispose();
13898 context2.Dispose();
13899 context3.Dispose();
13900}